如何在DelphiAndroid应用中调用原生相机?

How to invoke native camera in Delphi Android application?

我正在使用 Delphi 10.3 Community Edition 编写一个简单的 Android 应用程序并尝试调用本机设备相机,但出现错误。

我在关注官方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.

我已验证项目 |选项 |使用权限 - 相机设置设为 true。我也在请求启动应用程序所需的权限。 Debug 或 Release 中 运行 没有区别。

但是有一个问题。单击按钮时出现以下错误消息:

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.

这是我为最简单的测试应用编写的代码:

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.

如何让原生相机TTakePhotoFromCameraAction生效?

检查项目选项 > 权利列表 > 安全文件共享选项是否设置为 true

对于将项目从旧版本移植到 10.3 的任何人,请确保您的 AndroidManifest.xml 在 <%application-meta-data%> 标记正上方包含 <%provider%> 标记。

我在其他方面和这里发现的很多评论都建议可以在此处找到此文件:

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

但如果这不起作用,那么您的 源目录 中可能已经有一个 AndroidManifest.template.xml 文件。如果是这样,那么编译器将使用此模板文件并忽略 AppData 文件夹中的文件!

我遇到了 Android 9 可以工作但某些设备 运行 Android 10 不能工作的问题。我需要执行上面列出的答案中的步骤,但我的仍然无法正常工作,直到我添加:

android:requestLegacyExternalStorage="true"

到我的AndroidManifest.template.xml

的申请部分