7

我有一个我曾经在西雅图德尔福创建的项目,现在我想搬到德尔福里约。我使用 findfirst/findnext 读取了外部 SD 卡上的目录结构

  i := findfirst(datadir + '*', faanyfile, ts);

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

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

如果我将清单文件中的 targetSdkVersion(在 Rio 中自动设置为 26)硬编码为 19(即 minSdkVersion),则即使在 Rio 中,代码也会再次起作用。那么很明显,一些处理 sd 卡访问的方法已经从 sdk 级别 19 更改为 26?

有什么提示吗?

4

1 回答 1

12

Android 操作系统从 API 23 开始引入了运行时权限模型。

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

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

READ_EXTERNAL_STORAGE是其中之一。

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

要将您的应用程序上传到 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;
于 2018-12-02T12:26:53.483 回答