7

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?

Dalija Prasnikar
  • 24,159
  • 30
  • 74
  • 140
Andre Ruebel
  • 431
  • 3
  • 10
  • If you created the application in Seattle, and are migrating it to Rio, you need to add to AndroidManifest.template.xml just before , and check the Secure File Sharing option in the Entitlement List in Project Options – Dave Nottage Dec 02 '18 at 12:56
  • @DaveNottage Dalija's answer below is the way to deal with permission on API 23 and higher (targeted by Rio). Note that RequestPermissions accepts an array of permission strings, in case you need to ask for multiple permissions at once. – nolaspeaker Dec 02 '18 at 15:18

1 Answers1

12

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;
Dalija Prasnikar
  • 24,159
  • 30
  • 74
  • 140