Skip to content Skip to sidebar Skip to footer

How To Get Device Email Address In Delphi 10

I'm trying to get my device email address, I used Java2OP to convert AccountManager class to object pascal. However, I tried to get the email address using the following code: jAm

Solution 1:

Since there have been some comments about issues using the code snippets I thought it might be helpful to throw in a full unit (albeit containing minimal import definitions) to try and belay the problems and confusion.

Here is a helper unit that works in Delphi XE8 through to Delphi 10.1 Berlin (I can't check earlier versions, but in principle it should be 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.

This can be used in a fashion akin to this:

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;

The permissions checking code comes from this helper unit:

unit MiscU;

interface

functionHasPermission(const Permission: string): Boolean;

implementation

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

functionHasPermission(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.

Solution 2:

You should use the name property of the Account and not asking to convert the object to a string.

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

Solution 3:

getAccountsByType() returns an array of Account objects, not an array of class types. And check for nil pointers.

Try this instead:

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

Solution 4:

copy {class} function _Getname: JString; cdecl; to JAccount class, then use this code:

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

Post a Comment for "How To Get Device Email Address In Delphi 10"