在Delphi 10.3 Rio中写入外部SD卡

时间:2019-08-21 21:49:59

标签: android delphi delphi-10.3-rio

我编写了一个照片应用程序,可将图像从外部源流式传输到平板电脑(Samsung Galaxy TAB S)上的应用程序。我决定使用平板电脑中的外部SD卡作为存储设备,因为内部存储设备通常空间不足。另外,我需要将其删除以备份所有图像。

一切都可以“读取” JPG,但将“ JPG”从流“写入” SD卡时,权限被拒绝。

我已经设置了WRITE_EXTERNAL_STORAGE权限,但这在Android SDK 25.2.5中不起作用,因为Android更改了外部访问权限的工作方式。

fWriteStorage:=JStringToString(TJManifest_permission.JavaClass.WRITE_EXTERNAL_STORAGE);

PermissionsService.RequestPermissions([fReadStorage, fWriteStorage], DisplayRationale);

我要执行的操作是调用Android系统文件夹选择器对话框,以允许应用程序访问以写入SD卡。如此处所述:SD Card on Android 5.0 and Later

有人知道我如何在Delphi 10.3 Rio中调用SD卡的权限选择器吗?与包括适用于Android的TotalCommander在内的所有应用类似,这些应用需要对外部SD卡的写权限。

我现在再次尝试使用以下代码,但仍然没有运气。我需要为图片库创建新文件夹,但无法创建该文件夹。

  fWriteStorage := JStringToString(TJManifest_permission.JavaClass.WRITE_EXTERNAL_STORAGE);
  if PermissionsService.IsPermissionGranted(fWriteStorage) then
  begin
    applog('IsPermissionGranted: TRUE');
    if ForceDirectories(System.IOUtils.TPath.Combine(GLOBAL_SDCARD, 'FoxyTab/Storage')) then
      AppLog('GLOBAL_SDCARD Created')
    else
      AppLog('Can not create SD CARD folder ' + System.IOUtils.TPath.Combine(GLOBAL_SDCARD, 'FoxyTab/Storage'));
      PermissionsService.RequestPermissions([fWriteStorage],
    procedure(const APermissions: TArray<string>; const AGrantResults: TArray<TPermissionStatus>)
    begin
      if (Length(AGrantResults) = 1) and (AGrantResults[0] = TPermissionStatus.Granted) then
      begin
        AppLog('Access Granted');
        if ForceDirectories(System.IOUtils.TPath.Combine(GLOBAL_SDCARD, 'FoxyTab/Storage')) then
          AppLog('GLOBAL_SDCARD Created')
        else
          AppLog('Can not create SD CARD folder ' + System.IOUtils.TPath.Combine(GLOBAL_SDCARD, 'FoxyTab/Storage'));

      end
      else
      begin
        AppLog('Access Denied');
      end;
    end);

我总是获得“授予访问权限”,但是无法创建该文件夹。

SD卡不是平板电脑的内部设备,而是“可移动” microSD卡,因为当画廊已满时,我需要将其卸下以备份到另一台设备(PC / MAC)。卡的路径是/ storage / 2266-7298 /。与使用标准目录返回的内容不同。

1 个答案:

答案 0 :(得分:1)

您无需调用系统对话框即可获得访问权限。

使用PermissionsService.RequestPermissions()时,您实际上需要等待Android以授予或拒绝状态回复,然后才能尝试执行您请求其权限的操作。

在显示的代码中,您没有将回调函数传递给RequestPermissions()以获取该答复。因此,在将文件写入文件之前,您不知道用户是否实际上已授予对SD卡的访问权限。

您需要更多类似的东西:

fWriteStorage := JStringToString(TJManifest_permission.JavaClass.WRITE_EXTERNAL_STORAGE);

...

if PermissionsService.IsPermissionGranted(fWriteStorage) then
begin
  // access previously granted, write files...
end
else
begin
  PermissionsService.RequestPermissions([fWriteStorage],
    procedure(const APermissions: TArray<string>; const AGrantResults: TArray<TPermissionStatus>)
    begin
      if (Length(AGrantResults) = 1) and (AGrantResults[0] = TPermissionStatus.Granted) then
      begin
        // access granted, write files...
      end
      else
      begin
        // access denied, can't write files...
      end;
    end,
    DisplayRationale);
  end;
end;

请注意,如果您使用Android的Context.getExternalFilesDir()函数(由Delphi的System.IOUtils.TPath.GetSharedDocumentsPath()方法包装),则实际上不需要WRITE_EXTERNAL_STORAGE权限即可写入SD卡写入属于您的应用程序包的文件夹:

  

Build.VERSION_CODES.KITKAT开始,不需要权限来读取或写入返回的路径;调用应用程序始终可以访问它。这仅适用于为调用应用程序的程序包名称生成的路径。要访问属于其他包的路径,需要Manifest.permission.WRITE_EXTERNAL_STORAGE和/或Manifest.permission.READ_EXTERNAL_STORAGE

诸如TotalCommander之类的应用程序可以访问其他应用程序的文件,这就是为什么它需要(READ|WRITE)_EXTERNAL_STORAGE的原因。如果您的应用只是读取/写入自己的文件供自己使用,则可能不会。