简体   繁体   English

在 Delphi 10.3 Rio 中写入外部 SD 卡

[英]Writing to an external SD card in Delphi 10.3 Rio

I have written a photo application that streams images from an external source to my app on a tablet (Samsung Galaxy TAB S).我编写了一个照片应用程序,它将图像从外部源流式传输到平板电脑(三星 Galaxy TAB S)上的应用程序。 I have decided to use the external SD card in the tablet as storage, as the internal storage often runs out of space.我决定使用平板电脑中的外部 SD 卡作为存储空间,因为内部存储空间经常用完。 Plus, I need to remove it to backup all the images.另外,我需要将其删除以备份所有图像。

Everything works fine for "reading" the JPGs, but when it comes to "writing" JPGs from the stream to the SD Card, permission is denied.对于“读取”JPG 一切正常,但是当涉及到从流向 SD 卡“写入”JPG 时,权限被拒绝。

I have already set the WRITE_EXTERNAL_STORAGE permission, but this does not work using the Android SDK 25.2.5, as Android changed the way the permissions work for external access.我已经设置了WRITE_EXTERNAL_STORAGE权限,但这在使用 Android SDK 25.2.5 时不起作用,因为 Android 更改了权限用于外部访问的方式。

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

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

What I want to do is invoke the Android System Folder Chooser Dialog to allow access for the App to write to the SD card.我想要做的是调用 Android 系统文件夹选择器对话框以允许应用程序访问以写入 SD 卡。 As described here: SD Card on Android 5.0 and Later .如此处所述: Android 5.0 及更高版本上的 SD 卡

Does anyone know how I can invoke the permissions selector for the SD card in in Delphi 10.3 Rio?有谁知道如何在 Delphi 10.3 Rio 中调用 SD 卡的权限选择器? Similar to all apps including TotalCommander for Android, that need write access to an external SD card.与包括 TotalCommander for Android 在内的所有应用程序类似,需要对外部 SD 卡进行写访问。

I have now tried again, using the following code and still no luck.我现在再次尝试,使用以下代码,但仍然没有运气。 I need to create new folders for image galleries, and the folder can not be created.我需要为图库创建新文件夹,但无法创建该文件夹。

  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);

I always get "Access Granted", but the folder can not be created.我总是得到“授予访问权限”,但无法创建文件夹。

The SD card is not internal to the tablet, but a "removable" microSD card because I need to remove it when the galleries are full to backup to another device (PC/MAC). SD 卡不在平板电脑内部,而是一个“可移动”的 microSD 卡,因为当画廊已满时我需要将其移除以备份到另一台设备(PC/MAC)。 The path to the card is /storage/2266-7298/.卡的路径是/storage/2266-7298/。 Different from what is returned using the standard directory.与使用标准目录返回的内容不同。

You don't need to invoke a system dialog to get access.您无需调用系统对话框即可访问。

When using PermissionsService.RequestPermissions() , you need to actually wait for Android to reply with a granted or denied status before you can then attempt to perform the action you are requesting permissions for.使用PermissionsService.RequestPermissions() ,您需要实际等待 Android 回复授予或拒绝状态,然后才能尝试执行您请求权限的操作。

In the code you have shown, you are not passing a callback function to RequestPermissions() to get that reply.在您显示的代码中,您没有将回调函数传递给RequestPermissions()以获取回复。 So you don't know whether the user actually granted access to the SD card before you write files to it.因此,在向 SD 卡写入文件之前,您不知道用户是否真的授予了对 SD 卡的访问权限。

You need something more like this:你需要更像这样的东西:

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;

Note, if you use Android's Context.getExternalFilesDir() function (which is wrapped by Delphi's System.IOUtils.TPath.GetSharedDocumentsPath() method), you don't actually need WRITE_EXTERNAL_STORAGE permission to write to the SD card if you are writing to a folder that belongs to your app package:请注意,如果您使用 Android 的Context.getExternalFilesDir()函数(由 Delphi 的System.IOUtils.TPath.GetSharedDocumentsPath()方法包装),如果您要写入 SD 卡,则实际上不需要WRITE_EXTERNAL_STORAGE权限来写入 SD 卡属于您的应用程序包的文件夹:

Starting in Build.VERSION_CODES.KITKAT , no permissions are required to read or write to the returned path;Build.VERSION_CODES.KITKAT开始,不需要任何权限来读取或写入返回的路径; it's always accessible to the calling app.呼叫应用程序始终可以访问它。 This only applies to paths generated for package name of the calling application.这仅适用于为调用应用程序的包名称生成的路径。 To access paths belonging to other packages, Manifest.permission.WRITE_EXTERNAL_STORAGE and/or Manifest.permission.READ_EXTERNAL_STORAGE are required.要访问属于其他包的路径,需要Manifest.permission.WRITE_EXTERNAL_STORAGE和/或Manifest.permission.READ_EXTERNAL_STORAGE

Apps like TotalCommander access other app's files, that is why it requires (READ|WRITE)_EXTERNAL_STORAGE .像 TotalCommander 这样的应用程序访问其他应用程序的文件,这就是它需要(READ|WRITE)_EXTERNAL_STORAGE Your app may not, if it is just reading/writing its own files for its own use.您的应用程序可能不会,如果它只是读取/写入自己的文件供自己使用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM