1. 程式人生 > 其它 >為Delphi 10.4.2實現android拍照填坑

為Delphi 10.4.2實現android拍照填坑

 最新的Delphi版本發展到10.4.2,完美支援Andriod 11,但由於Android本身的變化,在開發Android app拍照功能功能時,還是會遇到問題,但這不是Delphi本身的問題,而是你不知如何在Delphi中處理的問題。為什麼會這樣呢?一句話,Android本身不斷變化造成的。

今天就有朋友遇到在10.4.2下拍照出現問題,就是拍完後,點對號,不返回。

1.拍照對於Delphi來說,已經做成了一個 標準的Action,在Form上放置一個 ActionList ,然後增加一個標準的拍照:

 增加後,我們需要處理 TakePhotnFormCameraAction 的 OnDidFinishTaking事件,即接收拍照的結果:

 這個事件程式碼,將拍照結果,傳給 imgPhotoLibraryImage,來顯示照片。

procedure TCameraRollForm.TakePhotoFromCameraAction1DidFinishTaking(
  Image: TBitmap);
begin
  { Assign the image retrieved from the Photo Library to the TImage component. }
  imgPhotoLibraryImage.Bitmap.Assign(Image);
end;

2.執行拍照。這塊我們要動態的申請許可權。

procedure TCameraRollForm.btnPhotoLibraryClick(Sender: TObject);
begin
  PermissionsService.RequestPermissions([
  JStringToString(TJManifest_permission.JavaClass.READ_EXTERNAL_STORAGE),
  JStringToString(TJManifest_permission.JavaClass.WRITE_EXTERNAL_STORAGE),
  JStringToString(TJManifest_permission.JavaClass.CAMERA)],
  LoadPicturePermissionRequestResult, DisplayRationale)
end;

// Optional rationale display routine to display permission requirement rationale to the user
procedure TCameraRollForm.DisplayRationale(Sender: TObject; const APermissions: TArray<string>; const APostRationaleProc: TProc);
var
  I: Integer;
  RationaleMsg: string;
begin
  for I := 0 to High(APermissions) do
  begin
    if APermissions[I] = JStringToString(TJManifest_permission.JavaClass.READ_EXTERNAL_STORAGE) then
      RationaleMsg := RationaleMsg + 'The app needs to load photo files from your device';
  end;
  // Show an explanation to the user *asynchronously* - don't block this thread waiting for the user's response!
  // After the user sees the explanation, invoke the post-rationale routine to request the permissions
  TDialogService.ShowMessage('The app needs to read a photo file from your device to show it to you',
    procedure(const AResult: TModalResult)
    begin
      APostRationaleProc;
    end)
end;

procedure TCameraRollForm.LoadPicturePermissionRequestResult(Sender: TObject; const APermissions: TArray<string>; const AGrantResults: TArray<TPermissionStatus>);
begin
  if (Length(AGrantResults) = 3) and
     (AGrantResults[0] = TPermissionStatus.Granted) and
     (AGrantResults[1] = TPermissionStatus.Granted) and
     (AGrantResults[2] = TPermissionStatus.Granted)
     then
//      TakePhotoFromLibraryAction1.Execute
      TakePhotoFromCameraAction1.Execute
  else
    TDialogService.ShowMessage('Cannot do photo editing because the required permissions are not granted');
end;

PermissionsService.RequestPermissions這個方法,請求拍照許可權,請求後會執行回撥函式LoadPicturePermissionRequestResult,在這個函式中,判斷使用者是否同意了請求的許可權,如果同意,則執行拍照動作:TakePhotoFromCameraAction1.Execute。

寫到這裡,我不僅想,如果官方在TakePhotoFromCameraAction1.Execute中,自動請求許可權該有多好,能省去我這麼多麻煩,還要記得需要請求哪些許可權。唉,想多了不是...

接下來,我們要對專案做一些配置,不然拍照也不正常。

首先,要設定Secure File Sharing為True,如下圖:

關於這項設定,我前期有寫過,Delphi 10.3.1 Secure File Sharing解決應用間檔案共享。

對應的這三個許可權也要設定一下:

TJManifest_permission.JavaClass.READ_EXTERNAL_STORAGE)
TJManifest_permission.JavaClass.WRITE_EXTERNAL_STORAGE)
TJManifest_permission.JavaClass.CAMERA)

有兩種方法,一是在Project Options中設定,如下圖:

或者,另外一種就是直接修改AndroidManifest.template.xml,增加需要的許可權,實際上這兩種方法的目的是一樣的,第一種方法,也是由Delphi把設定的許可權填加到AndroidManifest.xml檔案中:

<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-feature android:name="android.hardware.camera"/>
<uses-feature android:name="android.hardware.camera.autofocus" />

最後,對於從10.3.3升級過來的專案,我們還要在AndroidManifest.template.xml中增加一句:

android: requestLegacyExternalStorage = "true"

上面朋友遇到的就是這個問題,其實,我前期遇到過,並且整理出來了:Delphi 10.4.1 在android平臺下建立檔案無許可權,可以去參考一下