Как вызвать родную камеру в приложении Delphi для Android?

Я использую Delphi 10.3 Community Edition для написания простого приложения для Android и пытаюсь вызвать собственную камеру устройства, но вместо этого получаю сообщение об ошибке.

Я следую официальному руководству Delphi:

В конструкторе форм выберите кнопку (для фотографирования). В Инспекторе объектов выберите раскрывающийся список для свойства "Действие". Выберите новое стандартное действие | Медиатека | TTakePhotoFromCameraAction:

На вкладке "События" разверните узел "Действие", а затем дважды щелкните событие OnDidFinishTaking.

Добавьте следующий код в обработчик события OnDidFinishTaking:

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

Этот код назначает снимок, сделанный камерой мобильного устройства, свойству Bitmap компонента TImage.

Я подтвердил, что проект | Варианты | Использует разрешения - настройка камеры установлена ​​на true, Я также запрашиваю разрешение на запуск приложения. Нет разницы между выполнением в Debug или Release.

Однако есть проблема. При нажатии на кнопку я получаю следующее сообщение об ошибке:

java.lang.NullPointerException: попытка вызвать виртуальный метод 'android.content.res.XmlResourceParser android.content.pm.PackageItemInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' для ссылки на пустой объект.

Вот код, который я написал для самого простого тестового приложения:

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?

3 ответа

Решение

Убедитесь, что для параметров проекта> Список прав> Параметр безопасного доступа к файлам установлено значение true,

Для тех, кто переносит проект со старой версии на 10.3, убедитесь, что ваш AndroidManifest.xml включает тег <% provider%> прямо над тегом <% application-meta-data%>.

Я нашел много комментариев с других сторон, и здесь предполагается, что этот файл можно найти здесь:

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

Но если это не сработает, вероятно, у вас уже есть AndroidManifest.template.xmlфайл в исходном каталоге. Если это так, то компилятор будет использовать этот файл шаблона и игнорировать файл в папке AppData!

У меня были проблемы, когда Android 9 работал, а некоторые устройства под управлением Android 10 — нет. Мне нужно было выполнить шаги в ответах, перечисленных выше, но мой все еще не работал, пока я не добавил:

Android: requestLegacyExternalStorage = "истина"

в раздел приложения моего AndroidManifest.template.xml

Другие вопросы по тегам