Delphi Rio fails to read external storage with READ_EXTERNAL_STORAGE permissions set

  • A+
Category:Languages

I have a project that I once created in Delphi Seattle and I would now like to move to Delphi Rio. I read the directory structure on an external SD-Card using findfirst/findnext

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

datadir variable contains a valid directory. On Seattle, the code works fine (return value i=0) and the first directory entry is returned in variable ts. Now, compiling the same code on Rio, I get a return error value i=13 (access denied).

The permission READ_EXTERNAL_STORAGE is set in my project.

If I hardcode the targetSdkVersion in the manifest file (which is automatically set to 26 in Rio) down to 19 (which is the minSdkVersion) the code works again, even in Rio. So obviously some way to handle sd-card access has changed from sdk-level 19 to 26?

Any hints someone?

 


Android OS introduced Runtime Permissions model since API 23.

That means in addition to specifying permission in Manifest, you also need to ask user for granting you permission for so called dangerous permissions at runtime. User has a choice to give you permission when asked, but it can also revoke that permission at any time.

Whenever your application deals with code that needs runtime permission it must verify that user granted you that permission and be prepared to deal with situation where user didn't gave you the permission.

READ_EXTERNAL_STORAGE is one of them.

Overview of different permissions (including their classification) can be found at Permissions overview

To upload your application on Google Play Store, your application needs to support minimum API 26 (for the moment) and Delphi Rio by default targets new API levels. It also introduces support for asking permissions at runtime.

Following is basic example that asks for READ_EXTERNAL_STORAGE permission and reads files from shared downloads folder.

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; 

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: