升级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就没问题。
核心原因
- Delphi权限请求队列阻塞:Android13对蓝牙权限的处理逻辑和旧版本差异大,Delphi默认的批量权限请求会被蓝牙权限抢占,导致其他权限请求被压后,首次启动时根本没触发。
- 权限分组优先级冲突:targetSdk31后,Android的权限分组规则更新,相机、存储与蓝牙权限的请求优先级不同,批量请求时系统只会弹出高优先级的蓝牙权限,其他权限被延迟到下次启动。
- 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。
验证方法
- 彻底卸载旧应用,清理手机缓存。
- 重新打包安装,首次启动看是否先弹相机、存储权限,再弹蓝牙权限。
- 测试相机功能,确认不会崩溃。
- 重启应用,检查权限状态是否正常保留。
内容的提问来源于stack exchange,提问作者Haifisch
相关产品推荐
相关产品推荐

