Delphi Rio не может прочитать внешнее хранилище с установленными разрешениями READ_EXTERNAL_STORAGE

У меня есть проект, который я когда-то создал в Delphi Seattle, и теперь я хотел бы переехать в Delphi Rio. Я прочитал структуру каталогов на внешней SD-карте, используя findfirst / findnext

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

Переменная datadir содержит допустимый каталог. В Сиэтле код работает нормально (возвращаемое значение i=0), и первая запись каталога возвращается в переменной ts. Теперь, компилируя тот же код на Rio, я получаю значение ошибки возврата i=13 (доступ запрещен).

Разрешение READ_EXTERNAL_STORAGE установлено в моем проекте.

Если я жестко закодирую targetSdkVersion в файле манифеста (который автоматически устанавливается на 26 в Rio) до 19 (который является minSdkVersion), код снова работает, даже в Rio. Таким образом, очевидно, что какой-то способ обработки доступа к SD-карте изменился с уровня SDK 19 на 26?

Любые намеки на кого-то?

1 ответ

Решение

Android OS представила модель прав доступа Runtime начиная с API 23.

Это означает, что в дополнение к указанию разрешения в Manifest вам также необходимо запросить у пользователя разрешение на так называемые опасные разрешения во время выполнения. Пользователь может дать вам разрешение на запрос, но он также может отозвать это разрешение в любое время.

Всякий раз, когда ваше приложение имеет дело с кодом, для которого требуется разрешение во время выполнения, оно должно убедиться, что пользователь предоставил вам это разрешение, и быть готовым справиться с ситуацией, когда пользователь не предоставил вам разрешение.

READ_EXTERNAL_STORAGE это один из них.

Обзор различных разрешений (включая их классификацию) можно найти в обзоре разрешений.

Чтобы загрузить свое приложение в Google Play Store, ваше приложение должно поддерживать минимальный 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;
Другие вопросы по тегам