You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi 12.1中PermissionsService.RequestPermissions()无法正常申请文件读写权限

问题排查与解决方案

你的问题核心是Android版本权限机制变更加上Delphi 12.1默认目标SDK升级导致的:

  • 从Android 13(API 33)开始,Google废弃了READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE通用存储权限,改用细分的媒体权限(针对图片、视频、音频)或MANAGE_EXTERNAL_STORAGE(针对全文件访问)。
  • Delphi 12.1默认目标SDK已升级到API 33+,此时调用旧权限申请时,Android系统会直接返回未授权状态,不会弹出权限申请窗口。

具体修复步骤

1. 明确权限需求

根据业务场景选择对应权限:

  • 仅访问媒体文件(图片/视频/音频):使用新的媒体权限(推荐,符合Google Play规范)
  • 需访问所有文件(含非媒体):使用MANAGE_EXTERNAL_STORAGE权限(注意:该权限需Google Play特殊审核,普通应用不建议滥用)

2. 修改代码适配新权限

场景一:访问媒体文件

适配不同Android版本的权限逻辑:

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, System.Permissions,
  Androidapi.Jni.Os, Fmx.DialogService, Androidapi.Helpers, Androidapi.Jni.GraphicsContentViewText;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure PermissionRequestResult(Sender: TObject; const APermissions: TClassicStringDynArray; const AGrantResults: TClassicPermissionStatusDynArray);
    procedure ExplainReason(Sender: TObject; const APermissions: TClassicStringDynArray; const APostRationaleProc: TProc);
    procedure FormShow(Sender: TObject);
  private
    FPermissions: TArray<string>;
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

procedure TForm1.ExplainReason(Sender: TObject; const APermissions: TClassicStringDynArray; const APostRationaleProc: TProc);
begin
  TDialogService.ShowMessage('应用需要访问媒体文件以完成相关功能',
    procedure(const AResult: TModalResult)
    begin
      APostRationaleProc;
    end);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  // 根据Android版本选择对应权限
  if TOSVersion.Check(13) then
  begin
    // Android 13+ 使用细分媒体权限,按需添加图片/视频/音频权限
    FPermissions := [
      JStringToString(TJManifest_permission.JavaClass.READ_MEDIA_IMAGES),
      JStringToString(TJManifest_permission.JavaClass.READ_MEDIA_VIDEO),
      JStringToString(TJManifest_permission.JavaClass.READ_MEDIA_AUDIO)
    ];
  end
  else
  begin
    // Android 12及以下保留旧权限
    FPermissions := [
      JStringToString(TJManifest_permission.JavaClass.READ_EXTERNAL_STORAGE),
      JStringToString(TJManifest_permission.JavaClass.WRITE_EXTERNAL_STORAGE)
    ];
  end;
end;

procedure TForm1.FormShow(Sender: TObject);
begin
  PermissionsService.RequestPermissions(FPermissions, PermissionRequestResult, ExplainReason);
end;

procedure TForm1.PermissionRequestResult(Sender: TObject; const APermissions: TClassicStringDynArray; const AGrantResults: TClassicPermissionStatusDynArray);
var
  AllGranted: Boolean;
  I: Integer;
begin
  AllGranted := True;
  for I := 0 to High(AGrantResults) do
  begin
    if AGrantResults[I] <> TPermissionStatus.Granted then
    begin
      AllGranted := False;
      Break;
    end;
  end;

  if AllGranted then
    TDialogService.ShowMessage('权限已获取')
  else
    TDialogService.ShowMessage('所需权限未获取');
end;

end.

场景二:全文件访问(谨慎使用)

若必须访问所有文件,需使用MANAGE_EXTERNAL_STORAGE权限,且需引导用户到系统设置手动开启:

procedure TForm1.FormCreate(Sender: TObject);
begin
  if TOSVersion.Check(11) then // Android 11+ 需要该权限
    FPermissions := [JStringToString(TJManifest_permission.JavaClass.MANAGE_EXTERNAL_STORAGE)]
  else
    FPermissions := [
      JStringToString(TJManifest_permission.JavaClass.READ_EXTERNAL_STORAGE),
      JStringToString(TJManifest_permission.JavaClass.WRITE_EXTERNAL_STORAGE)
    ];
end;

procedure TForm1.PermissionRequestResult(Sender: TObject; const APermissions: TClassicStringDynArray; const AGrantResults: TClassicPermissionStatusDynArray);
begin
  if (Length(AGrantResults) > 0) and (AGrantResults[0] = TPermissionStatus.Granted) then
    TDialogService.ShowMessage('权限已获取')
  else
  begin
    TDialogService.ShowMessage('请在系统设置中为应用开启文件访问权限',
      procedure(const AResult: TModalResult)
      begin
        if AResult = mrOk then
          TAndroidHelper.Context.startActivity(TAndroidHelper.IntentSetAction(TJIntent.JavaClass.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION));
      end);
  end;
end;

3. 配置AndroidManifest.xml

确保对应权限在清单文件中声明:

  • 媒体权限:勾选READ_MEDIA_IMAGES、READ_MEDIA_VIDEO、READ_MEDIA_AUDIO(通过Project Options > Application > Android > Permissions勾选,或手动编辑AndroidManifest.template.xml)
  • 全文件访问权限:勾选MANAGE_EXTERNAL_STORAGE

额外注意事项

  • Delphi 12.1的PermissionsService已适配新权限,需确保使用正确的权限常量。
  • 建议将应用目标SDK升级到API 33+,以符合Google Play上架要求。
  • Android 13+访问媒体文件时,无需申请WRITE_EXTERNAL_STORAGE权限,写入媒体库操作会自动授权。

内容的提问来源于stack exchange,提问作者Lettergold Lettergold

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 01:04:57