我有一个我曾经在西雅图德尔福(Delphi Seattle)创建的项目,现在我想搬到德尔福里约(Delphi Rio)。 我使用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?
有人暗示某人吗?
答案 0 :(得分:10)
Android OS introduced Runtime Permissions模型中复制
这意味着除了在清单中指定权限外,还需要请求用户在运行时授予您所谓的危险权限的权限。用户可以在询问时选择授予您权限,但也可以随时撤消该权限。
每当您的应用程序处理需要运行时权限的代码时,它都必须验证用户是否已授予您该权限,并准备处理用户未授予您权限的情况。
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;