如何在 Delphi 10 中获取设备电子邮件地址
How to get device email address in Delphi 10
我正在尝试获取我的设备电子邮件地址,我使用 Java2OP 将 AccountManager class 转换为 object pascal。但是,我尝试使用以下代码获取电子邮件地址:
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 的 classes,JAccount Class 没有 name 属性,它在 JAccountClass 中,但代码有效,但我仍然遇到访问冲突错误。
您应该使用 Account
的 name
属性 而不是要求将对象转换为字符串。
mmLog.Lines.Add(jstringtostring( jAcc.name));
getAccountsByType()
returns Account
对象数组,而不是 class 类型数组。并检查零指针。
试试这个:
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;
将{class} function _Getname: JString; cdecl;
复制到JAccount
class,然后使用此代码:
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;
由于有一些关于使用代码片段的问题的评论,我认为放入一个完整的单元(尽管包含最少的导入定义)可能有助于解决问题和混淆。
这是一个可以在 Delphi XE8 到 Delphi 10.1 Berlin 中工作的辅助单元(我无法检查早期版本,但原则上应该没问题):
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.
我正在尝试获取我的设备电子邮件地址,我使用 Java2OP 将 AccountManager class 转换为 object pascal。但是,我尝试使用以下代码获取电子邮件地址:
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 的 classes,JAccount Class 没有 name 属性,它在 JAccountClass 中,但代码有效,但我仍然遇到访问冲突错误。
您应该使用 Account
的 name
属性 而不是要求将对象转换为字符串。
mmLog.Lines.Add(jstringtostring( jAcc.name));
getAccountsByType()
returns Account
对象数组,而不是 class 类型数组。并检查零指针。
试试这个:
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;
将{class} function _Getname: JString; cdecl;
复制到JAccount
class,然后使用此代码:
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;
由于有一些关于使用代码片段的问题的评论,我认为放入一个完整的单元(尽管包含最少的导入定义)可能有助于解决问题和混淆。
这是一个可以在 Delphi XE8 到 Delphi 10.1 Berlin 中工作的辅助单元(我无法检查早期版本,但原则上应该没问题):
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.