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

升级targetSdkVersion到31后Android权限请求异常问题

Delphi Android targetSdk31 权限请求异常问题解决

问题背景

用Delphi 10.4升级到11.2开发的Android应用,原本targetSdkVersion=29时权限请求一切正常。为上架Play商店改成targetSdkVersion=31,按要求加了exported=true,并调整了蓝牙权限:

<!-- 原蓝牙权限 -->
<uses-permission android:name="android.permission.BLUETOOTH"/>
<!-- 修改后 -->
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30"/>
<!-- 新增权限 -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE"/>
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>

但在Android13设备上,首次启动只弹出蓝牙权限请求,相机、存储权限完全没提示,调用相机直接崩溃;重启应用后所有权限才正常弹出,功能恢复。切回targetSdk29就没问题。

核心原因

  1. Delphi权限请求队列阻塞:Android13对蓝牙权限的处理逻辑和旧版本差异大,Delphi默认的批量权限请求会被蓝牙权限抢占,导致其他权限请求被压后,首次启动时根本没触发。
  2. 权限分组优先级冲突:targetSdk31后,Android的权限分组规则更新,相机、存储与蓝牙权限的请求优先级不同,批量请求时系统只会弹出高优先级的蓝牙权限,其他权限被延迟到下次启动。
  3. Delphi 11.2的Android13适配bug:Delphi对Android13的权限请求机制支持不完善,首次启动时的应用初始化流程和权限请求逻辑存在冲突。

解决办法

1. 手动拆分权限请求顺序,避免批量触发

把核心权限(相机、存储)和蓝牙权限分开请求,先搞定核心权限再处理蓝牙:

procedure TMainForm.FormShow(Sender: TObject);
begin
  // 先请求相机、存储这些核心权限
  if not PermissionsService.IsPermissionGranted(CAMERA) or
     not PermissionsService.IsPermissionGranted(READ_EXTERNAL_STORAGE) then
  begin
    PermissionsService.RequestPermissions([CAMERA, READ_EXTERNAL_STORAGE],
      procedure(const APermissions: TArray<string>; const AGrantResults: TArray<TPermissionStatus>)
      var
        I: Integer;
        AllGranted: Boolean;
      begin
        AllGranted := True;
        for I := 0 to Length(AGrantResults)-1 do
          if AGrantResults[I] <> TPermissionStatus.Granted then
          begin
            AllGranted := False;
            Break;
          end;

        // 核心权限搞定后,再请求蓝牙权限
        if AllGranted then
        begin
          if not PermissionsService.IsPermissionGranted(BLUETOOTH_SCAN) or
             not PermissionsService.IsPermissionGranted(BLUETOOTH_CONNECT) then
          begin
            PermissionsService.RequestPermissions([BLUETOOTH_SCAN, BLUETOOTH_CONNECT],
              procedure(const APermissions: TArray<string>; const AGrantResults: TArray<TPermissionStatus>)
              begin
                // 蓝牙权限处理逻辑,比如初始化蓝牙模块
              end);
          end;
        end;
      end);
  end;
end;

2. 修正Manifest权限声明,适配Android13规则

  • 存储权限:targetSdk31需要兼容旧版本和Android13的新权限,补充以下声明:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32"/>
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
  • 蓝牙权限:如果不需要通过蓝牙扫描获取位置,给BLUETOOTH_SCAN加neverForLocation标记,避免触发额外的位置权限请求:
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation"/>
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>

3. 延迟触发权限请求,避开应用初始化冲突

别在FormCreate里直接请求权限,用定时器延迟几百毫秒,等应用完全启动后再触发:

procedure TMainForm.FormCreate(Sender: TObject);
begin
  Timer1.Interval := 500; // 延迟500ms
  Timer1.Enabled := True;
end;

procedure TMainForm.Timer1Timer(Sender: TObject);
begin
  Timer1.Enabled := False;
  // 调用权限请求方法
  RequestPermissionsStepByStep;
end;

procedure TMainForm.RequestPermissionsStepByStep;
begin
  // 这里放上面的分步权限请求代码
end;

4. 更新Delphi组件到最新版

打开Delphi的GetIt Package Manager,搜索并更新Android相关组件,尤其是Permissions Service的适配补丁,官方可能已经修复了Android13的权限请求bug。

验证方法

  1. 彻底卸载旧应用,清理手机缓存。
  2. 重新打包安装,首次启动看是否先弹相机、存储权限,再弹蓝牙权限。
  3. 测试相机功能,确认不会崩溃。
  4. 重启应用,检查权限状态是否正常保留。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 17:21:07