2016-03-12 26 views
0

我試圖獲取設備的電子郵件地址,我使用Java2OP將AccountManager類轉換爲對象pascal。不過,我嘗試使用下面的代碼來獲取電子郵件地址:如何在Delphi 10中獲取設備的電子郵件地址

jAm: JAccountManager; 
accounts: TJavaObjectArray<JAccountClass>; 
jAcc: JAccountClass; 
begin 

    jAM := TJAccountManager.JavaClass.get(SharedActivityContext); 
    accounts := TJavaObjectArray<JAccountClass>.Wrap(jAM.getAccountsByType(StringToJString('com.google'))); 

    mmLog.Lines.Add('Length Accounts: ' + Inttostr(accounts.Length)); 

    if accounts.Length > 0 then begin 
    jAcc := accounts.Items[0]; 
    mmLog.Lines.Add(jstringtostring(jAcc.name)); 
    end else begin 
    mmLog.Lines.Add('no accounts available'); 
    end; 

我收到訪問衝突在地址415E5254,訪問地址0000002C! 任何想法傢伙?

JAccountClass = interface(JObjectClass) 
['{94EE6861-F326-489F-8919-E20B39E3D9C1}'] 
{class} function _GetCREATOR: JParcelable_Creator; cdecl; 
{class} function _Getname: JString; cdecl; 
{class} function _Gettype: JString; cdecl; 
{class} function init(name: JString; &type: JString): JAccount; cdecl; overload;//Deprecated 
{class} function init(init: JParcel): JAccount; cdecl; overload;//Deprecated 
{class} function describeContents: Integer; cdecl; 
{class} function equals(o: JObject): Boolean; cdecl; 
{class} property CREATOR: JParcelable_Creator read _GetCREATOR; 
{class} property name: JString read _Getname; 
{class} property &type: JString read _Gettype; 
end; 

    [JavaSignature('android/accounts/Account')] 
JAccount = interface(JObject) 
['{71476381-8B6E-471F-9189-9857ECD7508C}'] 
function hashCode: Integer; cdecl; 
function toString: JString; cdecl; 
procedure writeToParcel(dest: JParcel; flags: Integer); cdecl; 
end; 
TJAccount = class(TJavaGenericImport<JAccountClass, JAccount>) end; 

JAccountManagerClass = interface(JObjectClass) 
['{96273844-2D84-47F0-BFD5-14B73402F843}'] 
{class} function _GetACTION_AUTHENTICATOR_INTENT: JString; cdecl; 
{class} function _GetAUTHENTICATOR_ATTRIBUTES_NAME: JString; cdecl; 
{class} function _GetAUTHENTICATOR_META_DATA_NAME: JString; cdecl; 
{class} function _GetERROR_CODE_BAD_ARGUMENTS: Integer; cdecl; 
{class} function _GetERROR_CODE_BAD_AUTHENTICATION: Integer; cdecl; 
{class} function _GetERROR_CODE_BAD_REQUEST: Integer; cdecl; 
{class} function _GetERROR_CODE_CANCELED: Integer; cdecl; 
{class} function _GetERROR_CODE_INVALID_RESPONSE: Integer; cdecl; 
{class} function _GetERROR_CODE_NETWORK_ERROR: Integer; cdecl; 
{class} function _GetERROR_CODE_REMOTE_EXCEPTION: Integer; cdecl; 
{class} function _GetERROR_CODE_UNSUPPORTED_OPERATION: Integer; cdecl; 
{class} function _GetKEY_ACCOUNTS: JString; cdecl; 
{class} function _GetKEY_ACCOUNT_AUTHENTICATOR_RESPONSE: JString; cdecl; 
{class} function _GetKEY_ACCOUNT_MANAGER_RESPONSE: JString; cdecl; 
{class} function _GetKEY_ACCOUNT_NAME: JString; cdecl; 
{class} function _GetKEY_ACCOUNT_TYPE: JString; cdecl; 
{class} function _GetKEY_ANDROID_PACKAGE_NAME: JString; cdecl; 
{class} function _GetKEY_AUTHENTICATOR_TYPES: JString; cdecl; 
{class} function _GetKEY_AUTHTOKEN: JString; cdecl; 
{class} function _GetKEY_AUTH_FAILED_MESSAGE: JString; cdecl; 
{class} function _GetKEY_AUTH_TOKEN_LABEL: JString; cdecl; 
{class} function _GetKEY_BOOLEAN_RESULT: JString; cdecl; 
{class} function _GetKEY_CALLER_PID: JString; cdecl; 
{class} function _GetKEY_CALLER_UID: JString; cdecl; 
{class} function _GetKEY_ERROR_CODE: JString; cdecl; 
{class} function _GetKEY_ERROR_MESSAGE: JString; cdecl; 
{class} function _GetKEY_INTENT: JString; cdecl; 
{class} function _GetKEY_PASSWORD: JString; cdecl; 
{class} function _GetKEY_USERDATA: JString; cdecl; 
{class} function _GetLOGIN_ACCOUNTS_CHANGED_ACTION: JString; cdecl; 
{class} function addAccount(accountType: JString; authTokenType: JString; requiredFeatures: TJavaObjectArray<JString>; addAccountOptions: JBundle; activity: JActivity; callback: JAccountManagerCallback; handler: JHandler): JAccountManagerFuture; cdecl;//Deprecated 
{class} procedure clearPassword(account: JAccount); cdecl;//Deprecated 
{class} function confirmCredentials(account: JAccount; options: JBundle; activity: JActivity; callback: JAccountManagerCallback; handler: JHandler): JAccountManagerFuture; cdecl;//Deprecated 
{class} function editProperties(accountType: JString; activity: JActivity; callback: JAccountManagerCallback; handler: JHandler): JAccountManagerFuture; cdecl;//Deprecated 
{class} function get(context: JContext): JAccountManager; cdecl; 
{class} function getAccountsByTypeAndFeatures(&type: JString; features: TJavaObjectArray<JString>; callback: TJavaObjectArray<JAccountManagerCallback>; handler: JHandler): TJavaObjectArray<JAccountManagerFuture>; cdecl; 
{class} function getAccountsByTypeForPackage(&type: JString; packageName: JString): TJavaObjectArray<JAccount>; cdecl; 
{class} function getAuthToken(account: JAccount; authTokenType: JString; options: JBundle; activity: JActivity; callback: JAccountManagerCallback; handler: JHandler): JAccountManagerFuture; cdecl; overload; 
{class} function getAuthenticatorTypes: TJavaObjectArray<JAuthenticatorDescription>; cdecl; 
{class} function getPassword(account: JAccount): JString; cdecl; 
{class} function getUserData(account: JAccount; key: JString): JString; cdecl; 
{class} function newChooseAccountIntent(selectedAccount: JAccount; allowableAccounts: JArrayList; allowableAccountTypes: TJavaObjectArray<JString>; alwaysPromptForAccount: Boolean; descriptionOverrideText: JString; addAccountAuthTokenType: JString; addAccountRequiredFeatures: TJavaObjectArray<JString>; addAccountOptions: JBundle): JIntent; cdecl; 
{class} function peekAuthToken(account: JAccount; authTokenType: JString): JString; cdecl; 
{class} function removeAccount(account: JAccount; callback: JAccountManagerCallback; handler: JHandler): JAccountManagerFuture; cdecl; 
{class} procedure removeOnAccountsUpdatedListener(listener: JOnAccountsUpdateListener); cdecl; 
{class} function updateCredentials(account: JAccount; authTokenType: JString; options: JBundle; activity: JActivity; callback: JAccountManagerCallback; handler: JHandler): JAccountManagerFuture; cdecl; 
{class} property ACTION_AUTHENTICATOR_INTENT: JString read _GetACTION_AUTHENTICATOR_INTENT; 
{class} property AUTHENTICATOR_ATTRIBUTES_NAME: JString read _GetAUTHENTICATOR_ATTRIBUTES_NAME; 
{class} property AUTHENTICATOR_META_DATA_NAME: JString read _GetAUTHENTICATOR_META_DATA_NAME; 
{class} property ERROR_CODE_BAD_ARGUMENTS: Integer read _GetERROR_CODE_BAD_ARGUMENTS; 
{class} property ERROR_CODE_BAD_AUTHENTICATION: Integer read _GetERROR_CODE_BAD_AUTHENTICATION; 
{class} property ERROR_CODE_BAD_REQUEST: Integer read _GetERROR_CODE_BAD_REQUEST; 
{class} property ERROR_CODE_CANCELED: Integer read _GetERROR_CODE_CANCELED; 
{class} property ERROR_CODE_INVALID_RESPONSE: Integer read _GetERROR_CODE_INVALID_RESPONSE; 
{class} property ERROR_CODE_NETWORK_ERROR: Integer read _GetERROR_CODE_NETWORK_ERROR; 
{class} property ERROR_CODE_REMOTE_EXCEPTION: Integer read _GetERROR_CODE_REMOTE_EXCEPTION; 
{class} property ERROR_CODE_UNSUPPORTED_OPERATION: Integer read _GetERROR_CODE_UNSUPPORTED_OPERATION; 
{class} property KEY_ACCOUNTS: JString read _GetKEY_ACCOUNTS; 
{class} property KEY_ACCOUNT_AUTHENTICATOR_RESPONSE: JString read _GetKEY_ACCOUNT_AUTHENTICATOR_RESPONSE; 
{class} property KEY_ACCOUNT_MANAGER_RESPONSE: JString read _GetKEY_ACCOUNT_MANAGER_RESPONSE; 
{class} property KEY_ACCOUNT_NAME: JString read _GetKEY_ACCOUNT_NAME; 
{class} property KEY_ACCOUNT_TYPE: JString read _GetKEY_ACCOUNT_TYPE; 
{class} property KEY_ANDROID_PACKAGE_NAME: JString read _GetKEY_ANDROID_PACKAGE_NAME; 
{class} property KEY_AUTHENTICATOR_TYPES: JString read _GetKEY_AUTHENTICATOR_TYPES; 
{class} property KEY_AUTHTOKEN: JString read _GetKEY_AUTHTOKEN; 
{class} property KEY_AUTH_FAILED_MESSAGE: JString read _GetKEY_AUTH_FAILED_MESSAGE; 
{class} property KEY_AUTH_TOKEN_LABEL: JString read _GetKEY_AUTH_TOKEN_LABEL; 
{class} property KEY_BOOLEAN_RESULT: JString read _GetKEY_BOOLEAN_RESULT; 
{class} property KEY_CALLER_PID: JString read _GetKEY_CALLER_PID; 
{class} property KEY_CALLER_UID: JString read _GetKEY_CALLER_UID; 
{class} property KEY_ERROR_CODE: JString read _GetKEY_ERROR_CODE; 
{class} property KEY_ERROR_MESSAGE: JString read _GetKEY_ERROR_MESSAGE; 
{class} property KEY_INTENT: JString read _GetKEY_INTENT; 
{class} property KEY_PASSWORD: JString read _GetKEY_PASSWORD; 
{class} property KEY_USERDATA: JString read _GetKEY_USERDATA; 
{class} property LOGIN_ACCOUNTS_CHANGED_ACTION: JString read _GetLOGIN_ACCOUNTS_CHANGED_ACTION; 
end; 

[JavaSignature('android/accounts/AccountManager')] 
JAccountManager = interface(JObject) 
['{9FA4077B-4628-433C-BAFC-9EB299DA9C98}'] 
function addAccountExplicitly(account: JAccount; password: JString; userdata: JBundle): Boolean; cdecl;//Deprecated 
procedure addOnAccountsUpdatedListener(listener: JOnAccountsUpdateListener; handler: JHandler; updateImmediately: Boolean); cdecl;//Deprecated 
function blockingGetAuthToken(account: JAccount; authTokenType: JString; notifyAuthFailure: Boolean): JString; cdecl;//Deprecated 
function getAccounts: TJavaObjectArray<JAccount>; cdecl; 
function getAccountsByType(&type: JString): TJavaObjectArray<JAccount>; cdecl; 
function getAuthToken(account: JAccount; authTokenType: JString; notifyAuthFailure: Boolean; callback: JAccountManagerCallback; handler: JHandler): JAccountManagerFuture; cdecl; overload;//Deprecated 
function getAuthToken(account: JAccount; authTokenType: JString; options: JBundle; notifyAuthFailure: Boolean; callback: JAccountManagerCallback; handler: JHandler): JAccountManagerFuture; cdecl; overload; 
function getAuthTokenByFeatures(accountType: JString; authTokenType: JString; features: TJavaObjectArray<JString>; activity: JActivity; addAccountOptions: JBundle; getAuthTokenOptions: JBundle; callback: JAccountManagerCallback; handler: JHandler): JAccountManagerFuture; cdecl; 
function hasFeatures(account: JAccount; features: TJavaObjectArray<JString>; callback: JAccountManagerCallback; handler: JHandler): JAccountManagerFuture; cdecl; 
procedure invalidateAuthToken(accountType: JString; authToken: JString); cdecl; 
procedure setAuthToken(account: JAccount; authTokenType: JString; authToken: JString); cdecl; 
procedure setPassword(account: JAccount; password: JString); cdecl; 
procedure setUserData(account: JAccount; key: JString; value: JString); cdecl; 
end; 
TJAccountManager = class(TJavaGenericImport<JAccountManagerClass, JAccountManager>) end; 

我已經添加一些來自AccountManager.pas類中,JAccount類不具備屬性,它是在JAccountClass,但代碼工作,而我仍然得到訪問違規錯誤。

+1

竟被它d幫助知道哪一行正在拋出訪問衝突... –

+0

也許這行'accounts:= TJavaObjectArray .Wrap(jAM.getAccountsByType(StringToJString('com.google')));''或這個'mmLog .Lines.Add(jstringtostring(jAcc.name));',我無法編譯沒有這些。 @J ... – ColdZer0

+0

...所以如果它沒有編譯,你是如何得到訪問衝突的?你不應該在這裏猜測。當你遇到訪問衝突時,進入調試器並查看指令指針指向哪一行 - 然後告訴我們該行是什麼。 –

回答

1

副本{class} function _Getname: JString; cdecl;JAccount類,然後使用此代碼:

var 
    jAm: JAccountManager; 
    accounts: TJavaObjectArray<JAccount>; 
    jAcc: JAccount; 
begin 
    jAM := TJAccountManager.JavaClass.get(SharedActivityContext); 
    if jAM <> nil then begin 
    accounts := TJavaObjectArray<JAccount>.Wrap(jAM.getAccountsByType(StringToJString('com.google'))); 
    if accounts <> nil then begin 
     mmLog.Lines.Add('Length Accounts: ' + IntToStr(accounts.Length)); 
     if accounts.Length > 0 then begin 
     jAcc := accounts.Items[0]; 
     mmLog.Lines.Add(JStringtoString(jAcc._Getname)); 
     end else begin 
     mmLog.Lines.Add('no accounts available'); 
     end; 
    end; 
    end else begin 
    mmLog.Lines.Add('no accounts found'); 
    end; 
end; 
+0

感謝Haelty和Remy – ColdZer0

1

您應該使用Accountname屬性,而不是要求將該對象轉換爲字符串。

mmLog.Lines.Add(jstringtostring(jAcc.name)); 
+0

我得到訪問衝突在地址415E5254,訪問地址0000002C! – ColdZer0

1

getAccountsByType()返回Account對象,而不是類類型的數組的數組。並檢查無指針。

試試這個:

var 
    jAm: JAccountManager; 
    accounts: TJavaObjectArray<JAccount>; 
    jAcc: JAccount; 
begin 
    jAM := TJAccountManager.JavaClass.get(SharedActivityContext); 
    if jAM <> nil then begin 
    accounts := TJavaObjectArray<JAccount>.Wrap(jAM.getAccountsByType(StringToJString('com.google'))); 
    if accounts <> nil then begin 
     mmLog.Lines.Add('Length Accounts: ' + IntToStr(accounts.Length)); 
     if accounts.Length > 0 then begin 
     jAcc := accounts.Items[0]; 
     mmLog.Lines.Add(JStringtoString(jAcc.name)); 
     end else begin 
     mmLog.Lines.Add('no accounts available'); 
     end; 
    end; 
    end else begin 
    mmLog.Lines.Add('no accounts found'); 
    end; 
else begin 
    mmLog.Lines.Add('no account manager available'); 
end; 
+0

非常感謝您看看我的帖子。但是,我仍然在地址415E5254發現訪問衝突,訪問地址0000002C!我不能闖入調試器。 @Remy Lebeau – ColdZer0

+0

你需要調試你的代碼。如果您不能使用實際的調試器,則必須將所有內容輸出到日誌中。無論哪種方式,你需要分析你的變量值。接近地址0的AV通常意味着正在訪問零指針。 –

+0

如何將所有內容輸出到日誌?,我會在這裏發佈輸出。我的delphi10目前有調試器的問題!如果AccountManager.pas有幫助,我添加了一些類AccountManager.pas,謝謝。 @Remy Lebeau – ColdZer0

1

由於一直使用的代碼片段我想這可能是有關問題的一些意見有助於拋出一個完整的單元(儘管包含最少的導入定義)來試圖解決問題和困惑。

這裏是一個輔助單元,通過在Delphi XE8工程德爾福10.1柏林(我無法檢查早期版本,但原則上應該是OK):

unit AccountEmailsU; 

interface 

function GetAccountEmails(const AccountType: String): TArray<String>; 

implementation 

uses 
    Androidapi.Helpers, 
    Androidapi.Jni, 
{$IF Declared(RTLVersion) and (RTLVersion >= 31)} 
    // Delphi 10.1 Berlin adds in full imports for the accounts classes 
    Androidapi.JNI.Accounts; 
{$ELSE} 
    Androidapi.JNIBridge, 
    Androidapi.JNI.App, 
    Androidapi.JNI.GraphicsContentViewText, 
    Androidapi.JNI.JavaTypes, 
    Androidapi.JNI.Os; 

type 
// ===== Forward declarations ===== 

    JAccount = interface;//android.accounts.Account 
    JAccountManager = interface;//android.accounts.AccountManager 

// ===== Interface declarations ===== 

    JAccountClass = interface(JObjectClass) 
    ['{94EE6861-F326-489F-8919-E20B39E3D9C1}'] 
    end; 

    [JavaSignature('android/accounts/Account')] 
    JAccount = interface(JObject) 
    ['{71476381-8B6E-471F-9189-9857ECD7508C}'] 
    function _Getname: JString; cdecl; 
    function _Gettype: JString; cdecl; 
    property name: JString read _Getname; 
    property &type: JString read _Gettype; 
    end; 
    TJAccount = class(TJavaGenericImport<JAccountClass, JAccount>) end; 

    JAccountManagerClass = interface(JObjectClass) 
    ['{96273844-2D84-47F0-BFD5-14B73402F843}'] 
    {class} function &get(context: JContext): JAccountManager; cdecl; 
    end; 

    [JavaSignature('android/accounts/AccountManager')] 
    JAccountManager = interface(JObject) 
    ['{9FA4077B-4628-433C-BAFC-9EB299DA9C98}'] 
    function getAccountsByType(type_: JString): TJavaObjectArray<JAccount>; cdecl; 
    end; 
    TJAccountManager = class(TJavaGenericImport<JAccountManagerClass, JAccountManager>) end; 
{$ENDIF} 

function GetAccountEmails(const AccountType: String): TArray<String>; 
var 
    AccountManager: JAccountManager; 
    Accounts: TJavaObjectArray<JAccount>; 
    Account: JAccount; 
    AccountLoopCounter: Integer; 
begin 
{$IF RTLVersion >= 30} 
    AccountManager := TJAccountManager.JavaClass.get(TAndroidHelper.Context); 
{$ELSE} 
    AccountManager := TJAccountManager.JavaClass.get(SharedActivityContext); 
{$ENDIF} 
    if AccountManager <> nil then 
    begin 
    Accounts := AccountManager.getAccountsByType(StringToJString(AccountType)); 
    if Accounts <> nil then 
    begin 
     SetLength(Result, Accounts.Length); 
     for AccountLoopCounter := 0 to Pred(Accounts.Length) do 
     begin 
     //Account := Accounts.Items[AccountLoopCounter]; 
     Account := TJAccount.Wrap(Accounts.GetRawItem(AccountLoopCounter)); 
     Result[AccountLoopCounter] := JStringtoString(Account.name); 
     end 
    end; 
    end; 
end; 

procedure RegisterTypes; 
begin 
    TRegTypes.RegisterType('AccountEmailsU.JAccount', TypeInfo(AccountEmailsU.JAccount)); 
    TRegTypes.RegisterType('AccountEmailsU.JAccountManager', TypeInfo(AccountEmailsU.JAccountManager)); 
end; 

initialization 
    RegisterTypes; 
end. 

這可以被用在時尚類似於此:

uses 
{$IF RTLVersion >= 31} 
    FMX.DialogService, 
//{$ELSE} 
// FMX.Dialogs, 
{$ENDIF} 
    AccountEmailsU, 
    MiscU; 

procedure TForm1.btnGetAccountEmailsClick(Sender: TObject); 
const 
    AccountType = 'com.google'; 
var 
    AccountNames: TArray<String>; 
    AccountLoopCounter: Integer; 
begin 
    if not HasPermission('android.permission.GET_ACCOUNTS') then 
{$IF RTLVersion >= 31} 
    TDialogService.MessageDialog('App does not have the GET_ACCOUNTS permission', 
     TMsgDlgType.mtError, [TMsgDlgBtn.mbCancel], TMsgDlgBtn.mbCancel, 0, nil) 
{$ELSE} 
    MessageDlg('App does not have the GET_ACCOUNTS permission', 
     TMsgDlgType.mtError, [TMsgDlgBtn.mbCancel], 0) 
{$ENDIF} 
    else 
    begin 
    AccountNames := GetAccountEmails(AccountType); 
    AccountsListBox.Items.Clear; 
    for AccountLoopCounter := Low(AccountNames) to High(AccountNames) do 
     AccountsListBox.Items.Add(AccountNames[AccountLoopCounter]) 
    end; 
end; 

檢查代碼來自該輔助單元的權限:

unit MiscU; 

interface 

function HasPermission(const Permission: string): Boolean; 

implementation 

uses 
    FMX.Helpers.Android, 
    Androidapi.Helpers, 
    Androidapi.JNI.JavaTypes, 
    Androidapi.JNI.GraphicsContentViewText; 

function HasPermission(const Permission: string): Boolean; 
begin 
    //Permissions listed at http://d.android.com/reference/android/Manifest.permission.html 
{$IF RTLVersion >= 30} 
    Result := TAndroidHelper.Context.checkCallingOrSelfPermission(
{$ELSE} 
    Result := SharedActivityContext.checkCallingOrSelfPermission(
{$ENDIF} 
    StringToJString(Permission)) = 
    TJPackageManager.JavaClass.PERMISSION_GRANTED 
end; 

end. 
相關問題