Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi Rio fails to read external storage with READ_EXTERNAL_STORAGE permissions set

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?

like image 260
Andre Ruebel Avatar asked Dec 02 '18 11:12

Andre Ruebel


1 Answers

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;
like image 161
Dalija Prasnikar Avatar answered Nov 15 '22 10:11

Dalija Prasnikar