4
votes

I'm using Delphi 10.3 Community Edition to write a simple Android app and trying to invoke native device camera, but getting an error instead.

I'm following the official Delphi guide:

On the Form Designer, select the button (for taking a photo). In the Object Inspector, select the drop-down list for the Action property. Select New Standard Action | Media Library | TTakePhotoFromCameraAction:

On the Events tab, expand the Action node, and then double-click the OnDidFinishTaking event.

Add the following code to the OnDidFinishTaking event handler:

procedure TForm1.TakePhotoFromCameraAction1DidFinishTaking(Image: TBitmap);
begin
  Image1.Bitmap.Assign(Image);
end;

This code assigns a picture taken from the mobile device camera to the Bitmap property of the TImage component.

I have verified that Project | Options | Uses Permissions - Camera setting is set to true. I'm requesting required permission on the app start as well. There's no difference between running in Debug or Release.

However there is a problem. When clicking the button I get the following error message:

java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.PackageItemInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference.

Here's the code I've written for the simplest test app:

unit Unit1;
interface
uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, System.Permissions,
  FMX.StdCtrls, FMX.MediaLibrary, FMX.Platform, System.Messaging, FMX.Objects,
  System.Actions, FMX.ActnList, FMX.StdActns, FMX.MediaLibrary.Actions,
  FMX.Controls.Presentation;

type
  TForm1 = class(TForm)
    Button1: TButton;
    ActionList1: TActionList;
    TakePhotoFromCameraAction1: TTakePhotoFromCameraAction;
    procedure FormCreate(Sender: TObject);
  private
    procedure PermissionRequestResult(Sender: TObject; const APermissions: TArray<string>; const AGrantResults: TArray<TPermissionStatus>);
    procedure DisplayRationale(Sender: TObject; const APermissions: TArray<string>; const APostRationaleProc: TProc);
  end;

var
  Form1: TForm1;

implementation
uses
{$IFDEF ANDROID}
  Androidapi.Helpers,
  Androidapi.JNI.JavaTypes,
  Androidapi.JNI.Os,
{$ENDIF}
  FMX.DialogService;

{$R *.fmx}

procedure TForm1.PermissionRequestResult(Sender: TObject; const APermissions: TArray<string>; const AGrantResults: TArray<TPermissionStatus>);
begin
  // 3 permission involved
  if (Length(AGrantResults) = 3)
  and (AGrantResults[0] = TPermissionStatus.Granted)
  and (AGrantResults[1] = TPermissionStatus.Granted)
  and (AGrantResults[2] = TPermissionStatus.Granted) then
  else
    ShowMessage('Required permission has not been granted') ;
end;

procedure TForm1.DisplayRationale(Sender: TObject; const APermissions: TArray<string>; const APostRationaleProc: TProc);
begin
  TDialogService.ShowMessage('Need to access the camera',
    procedure(const AResult: TModalResult)
    begin
      APostRationaleProc;
    end);
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  permCam, permRead, permWrite: string;
begin
  // Request permissions
  permCam := JStringToString(TJManifest_permission.JavaClass.CAMERA);
  permRead := JStringToString(TJManifest_permission.JavaClass.READ_EXTERNAL_STORAGE);
  permWrite := JStringToString(TJManifest_permission.JavaClass.WRITE_EXTERNAL_STORAGE);
  PermissionsService.RequestPermissions([permCam, permRead, permWrite], PermissionRequestResult, DisplayRationale);
end;

end.

How to make the native camera TTakePhotoFromCameraAction to work?

3
The same question in Russian: ru.stackoverflow.com/questions/922403 - Kromster

3 Answers

12
votes

Check that the Project Options > Entitlements List > Secure File Sharing option is set to true.

2
votes

For anyone porting a project from an older version to 10.3, make sure that your AndroidManifest.xml includes the <%provider%> tag right above the <%application-meta-data%> tag.

A lot of comments I've found on other sides and here are suggesting that this file can be found here:

C:\Users\(yourusername)\AppData\Roaming\Embarcadero\BDS\20.0\AndroidManifest.xml

But if that doesn't work then you likely already have an AndroidManifest.template.xml file in your source directory. If that is the case then the compiler will use this template file and ignore the file in the AppData folder!

2
votes

I was having issues where Android 9 would work but some devices running Android 10 wouldn't. I needed to do the steps in the answers listed above but mine was still not working until I added:

android:requestLegacyExternalStorage="true"

to the application section of my AndroidManifest.template.xml