android - 在 Delphi 10.3 Rio 中写入外部 SD 卡
问题描述
我编写了一个照片应用程序,将图像从外部源流式传输到平板电脑(三星 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 卡。如此处所述:Android 5.0 及更高版本上的 SD 卡。
有谁知道我如何在 Delphi 10.3 Rio 中调用 SD 卡的权限选择器?与包括 TotalCommander for Android 在内的所有应用程序类似,需要对外部 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/。不同于使用标准目录返回的内容。
解决方案
您无需调用系统对话框即可获得访问权限。
使用 时PermissionsService.RequestPermissions()
,您实际上需要等待 Android 回复授权或拒绝状态,然后才能尝试执行您请求权限的操作。
在您显示的代码中,您没有传递回调函数RequestPermissions()
来获取该回复。因此,在向 SD 卡写入文件之前,您不知道用户是否实际授予了对 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()
实际上不需要写入 SD 卡的权限:WRITE_EXTERNAL_STORAGE
从 开始
Build.VERSION_CODES.KITKAT
,读取或写入返回的路径不需要权限;调用应用程序始终可以访问它。这仅适用于为调用应用程序的包名称生成的路径。访问属于其他包的路径,Manifest.permission.WRITE_EXTERNAL_STORAGE
和/或是Manifest.permission.READ_EXTERNAL_STORAGE
必需的。
像 TotalCommander 这样的应用程序访问其他应用程序的文件,这就是它需要(READ|WRITE)_EXTERNAL_STORAGE
. 您的应用程序可能不会,如果它只是读取/写入自己的文件以供自己使用。
推荐阅读
- c# - 使用范围通过 SMTP 和 Accesstoken 发送的邮件
- sql - 在同一个表上查询时,HIVE 列别名未显示在输出中
- excel - VBA 代码将主 Outlook 收件箱中的所有未读电子邮件随机拆分到子文件夹中
- javascript - .map() 方法中的参数顺序
- powershell - 使用 Powershell 将 MSMQ 消息从一个队列移动到另一个队列
- java - 在 Java NullPointerException 中为 arrayList 添加每个列表元素
- excel - 基于相似的选项卡名称运行宏
- c# - 当关卡结束时,如何将一个关卡的分数添加到该关卡之外的货币?
- flutter - 如何从 url [Flutter][Dio] 获取文件名
- java - 将具有多列选择的@Query 映射到@Repository 中的Java 对象- 是否可以开箱即用?