Delphi Rio 无法读取设置了 READ_EXTERNAL_STORAGE 权限的外部存储

Delphi Rio fails to read external storage with READ_EXTERNAL_STORAGE permissions set

我有一个曾经在 Delphi 西雅图创建的项目,现在我想搬到 Delphi 里约热内卢。 我使用 findfirst/findnext

读取外部 SD 卡上的目录结构
  i := findfirst(datadir + '*', faanyfile, ts);

datadir 变量包含有效目录。在西雅图,代码运行良好(return 值 i=0)并且第一个目录条目在变量 ts 中 returned。 现在,在 Rio 上编译相同的代码,我得到一个 return 错误值 i=13(访问被拒绝)。

我的项目中设置了权限READ_EXTERNAL_STORAGE。

如果我将清单文件中的 targetSdkVersion(在 Rio 中自动设置为 26)硬编码为 19(即 minSdkVersion),代码将再次运行,即使在 Rio 中也是如此。 显然,处理 sd 卡访问的某种方式已从 sdk 级别 19 更改为 26?

有什么提示吗?

Android OS 自 API 23 年以来引入了 Runtime Permissions 模型。

这意味着除了在Manifest中指定权限之外,您还需要在运行时请求用户授予您所谓的危险权限。用户可以选择在被询问时授予您权限,但也可以随时撤销该权限。

每当您的应用程序处理需要运行时权限的代码时,它都必须验证用户是否授予您该权限,并准备好处理用户未授予您权限的情况。

READ_EXTERNAL_STORAGE就是其中之一。

可以在 Permissions overview

找到不同权限的概述(包括它们的分类)

要在 Google Play 商店上传您的应用程序,您的应用程序需要至少支持 API 26(目前)和 Delphi Rio 默认目标是新 API 水平。它还引入了对在运行时询问权限的支持。

以下是请求 READ_EXTERNAL_STORAGE 权限并从共享下载文件夹中读取文件的基本示例。

uses
  System.Permissions,
  Androidapi.Helpers,
  Androidapi.JNI.App,
  Androidapi.JNI.OS,
  ...

procedure TMainForm.AddFiles;
var
  LFiles: TArray<string>;
  LFile: string;
begin
  LFiles := TDirectory.GetFiles(TPath.GetSharedDownloadsPath);
  for LFile in LFiles do
    begin
      Memo1.Lines.Add(LFile);
    end;
end;

procedure TMainForm.Button1Click(Sender: TObject);
begin
  PermissionsService.RequestPermissions([JStringToString(TJManifest_permission.JavaClass.READ_EXTERNAL_STORAGE)],
    procedure(const APermissions: TArray<string>; const AGrantResults: TArray<TPermissionStatus>)
    begin
      if (Length(AGrantResults) = 1) and (AGrantResults[0] = TPermissionStatus.Granted) then
        begin
          Memo1.Lines.Add('GRANTED');
          AddFiles;
        end
      else
        begin
          Memo1.Lines.Add('NOT GRANTED');
        end;
    end)
end;