Доброго времени суток. Столкнулся с такой же проблемой в 10.4.2. В стандартном примере все работает, а в мигрированном приложении из 10.3.3 - приложение всегда ловит отмену запроса на фото. Я так понимаю где-то не хватает прав для временного файла.
Путем долгих и мучительных экспериментов и курением доки организовал эту всю штуку через нативные интенты.
Код вырезан из рабочего проекта, по этому извините если что-то не так. Но смысл должен быть понятен.
Здесь кроме самого фото еще реализовано автоматическое поворачивание картинки по Exif-даным, относительно того в каком положении был телефон.
Так же очень важно не забыть выставить права в опциях приложение и подключить Secure File Sharing в Entitlement List. С Uses секцией надеюсь разберетесь, не уверен что нужно для Вашей задачи все из того что я кинул.
Uses
....
Androidapi.JNI.GraphicsContentViewText,
Androidapi.JNI.App,
Androidapi.JNI.JavaTypes,
Androidapi.Helpers,
FMX.Platform.Android,
System.Permissions,
Androidapi.JNI.Os,
Androidapi.JNI.Net,
Androidapi.JNI.Support,
Androidapi.JNI.Provider,
Androidapi.JNIBridge,
FMX.Helpers.Android,
FMX.Surfaces,
Androidapi.JNI.Media;
TfmMain = class(TForm)
...
procedure FormCreate(Sender: TObject);
procedure btnPhotos_ShowCameraClick(Sender: TObject);
...
protected
FMessageSubscriptionID : integer;
FPermissionWriteExternalStorage: string;
FPermissionCamera: string;
FPermissionReadExternalStorage: string;
FphotoUri :Jnet_Uri;
JFileName: JFile;
procedure DisplayRationale(Sender: TObject; const APermissions: TArray<string>; const APostRationaleProc: TProc);
procedure TakePicturePermissionRequestResult(Sender: TObject; const APermissions: TArray<string>; const AGrantResults: TArray<TPermissionStatus>);
procedure TakePicturePermissionRequestAfterINitResult(Sender: TObject; const APermissions: TArray<string>; const AGrantResults: TArray<TPermissionStatus>);
procedure HandleActivityMessage(const Sender: TObject; const M: TMessage);
function OnActivityResult(RequestCode, ResultCode: Integer; Data: JIntent): Boolean;
end;
procedure TfmMain.FormCreate(Sender: TObject);
begin
FPermissionCamera := JStringToString(TJManifest_permission.JavaClass.CAMERA);
FPermissionReadExternalStorage := JStringToString(TJManifest_permission.JavaClass.READ_EXTERNAL_STORAGE);
FPermissionWriteExternalStorage := JStringToString(TJManifest_permission.JavaClass.WRITE_EXTERNAL_STORAGE);
...
end;
procedure TfmMain.HandleActivityMessage(const Sender: TObject; const M: TMessage);
begin
if M is TMessageResultNotification then begin
OnActivityResult(TMessageResultNotification(M).RequestCode, TMessageResultNotification(M).ResultCode, TMessageResultNotification(M).Value);
end;
end;
function TfmMain.OnActivityResult(RequestCode, ResultCode: Integer; Data: JIntent): Boolean;
procedure SetPhotoData();
var
jBmp : JBitmap;
xSurface : TBitmapSurface;
vImage : TImage;
xExif : JExifInterface;
sOrientation : JString;
rotationAngle, orientation : integer;
sFile : string;
ScreenService: IFMXScreenService;
begin
if RequestCode = 1001 then begin
if ResultCode = TJActivity.JavaClass.RESULT_OK then begin
if FphotoUri <> nil then begin
jBmp := TJImages_Media.JavaClass.getBitmap(SharedActivity.getContentResolver, FphotoUri);
if jBmp <> nil then begin
xSurface := TBitmapSurface.Create;
try
JBitmapToSurface(jBmp, xSurface);
vImage := TImage.Create(nil);
try
vImage.Bitmap.Assign(xSurface);
sFile := JStringToString(JFileName.getAbsolutePath);
xExif := TJExifInterface.JavaClass.init(StringToJString(sFile));
sOrientation := xExif.getAttribute(TJExifInterface.JavaClass.TAG_ORIENTATION);
if sOrientation = nil then
orientation := TJExifInterface.JavaClass.ORIENTATION_NORMAL
else
orientation := StrToIntDef(JStringToString(sOrientation), 0);
rotationAngle := 0;
if orientation = TJExifInterface.JavaClass.ORIENTATION_ROTATE_90 then
rotationAngle := 90;
if orientation = TJExifInterface.JavaClass.ORIENTATION_ROTATE_180 then
rotationAngle := 180;
if orientation = TJExifInterface.JavaClass.ORIENTATION_ROTATE_270 then
rotationAngle := 270;
if rotationAngle <> 0 then
vImage.Bitmap.Rotate(rotationAngle);
//Готовое фото уже в vImage - выводим куда нужно
imPhotos_Photo.Bitmap.Assign(vImage.Bitmap);
finally
vImage.Free;
end;
finally
xSurface.Free
end{try..finally};
end else begin
//не вдалось завантажити картинку
TDialogService.ShowMessage('Не вдалось завантажити картинку');
end{if..else};
end else begin
//пустий Uri
TDialogService.ShowMessage('Пустий Uri');
end{if..else};
end else begin
TDialogService.ShowMessage('Відмовились робити фото');
end{if..else};
end{if};
end;
begin
Result := False;
TMessageManager.DefaultManager.Unsubscribe(TMessageResultNotification, FMessageSubscriptionID);
FMessageSubscriptionID := 0;
if RequestCode = 1001 then begin
// робота з камерою - отримання фото
SetPhotoData();
exit;
end;
...
end;
procedure TfmMain.TakePicturePermissionRequestResult(Sender: TObject;
const APermissions: TArray<string>;
const AGrantResults: TArray<TPermissionStatus>);
var
intent : jintent;
Authority: JString;
begin
// 3 permissions involved: CAMERA, READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE
if (Length(AGrantResults) = 3) and (AGrantResults[0] = TPermissionStatus.Granted) and (AGrantResults[1] = TPermissionStatus.Granted) and (AGrantResults[2] = TPermissionStatus.Granted) then begin
//створюємо "намір" отримання фото з камери
intent := TJIntent.JavaClass.init;
intent.setAction(TJMediaStore.JavaClass.ACTION_IMAGE_CAPTURE);
//створюємо тимчасовий файл
JFileName := TJFile.JavaClass.createTempFile(StringToJString('picture'), StringToJString('.jpg'));
//отримуємо опис прав по файлам
Authority := StringToJString(JStringToString(TAndroidHelper.Context.getApplicationContext.getPackageName) + '.fileprovider');
//отримуємо URI-до тимчасового файлу в контексті нашої аплікації
FphotoUri:= TJFileProvider.JavaClass.getUriForFile(TAndroidHelper.Context, Authority, JFileName);
//кажемо що наш "намір" має писати дані в цей тимчасовий файл
intent.putExtra(TJMediaStore.JavaClass.EXTRA_OUTPUT,
TJParcelable.Wrap((FphotoUri as ILocalObject).GetObjectID)
);
//реєструємось на отримання подій
FMessageSubscriptionID := TMessageManager.DefaultManager.SubscribeToMessage(TMessageResultNotification, HandleActivityMessage);
//стартуємо наш "намір"
MainActivity.startActivityForResult(intent, 1001);
end else
TDialogService.ShowMessage('Не надані необхідні для роботи дозволи!');
end;
procedure TfmMain.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] = FPermissionCamera then
RationaleMsg := RationaleMsg + 'The app needs to access the camera to take a photo' + SLineBreak + SLineBreak
else if APermissions[I] = FPermissionReadExternalStorage then
RationaleMsg := RationaleMsg + 'The app needs to read a photo file 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(RationaleMsg,
procedure(const AResult: TModalResult)
begin
APostRationaleProc;
end);
end;
procedure TfmMain.btnPhotos_ShowCameraClick(Sender: TObject);
begin
PermissionsService.RequestPermissions( [FPermissionCamera, FPermissionReadExternalStorage, FPermissionWriteExternalStorage],
TakePicturePermissionRequestResult,
DisplayRationale
);
end;
P.S. возможно нужно будет вставить в манифест:
android:requestLegacyExternalStorage="true"