三星Android13-14设备takePersistableUriPermission权限异常问题
三星Android 13-14设备上SAF持久化权限异常问题及解决方案
异常信息
在Firebase Crashlytics中捕获到以下致命异常:
Fatal Exception: java.lang.RuntimeException Failure delivering result ResultInfo{who=null, request=1915322883, result=-1, data=Intent { dat=content:/... flg=0xc3 }} to activity {com..../com....Activity}: java.lang.SecurityException: No persistable permission grants found for UID 10571 and Uri content:/...
Fatal Exception: java.lang.SecurityException No persistable permission grants found for UID 10434 and Uri content:/...
异常触发点:android.content.ContentResolver.takePersistableUriPermission (ContentResolver.java:2952)
异常堆栈:
Caused by android.os.RemoteException Remote stack trace: at com.android.server.uri.UriGrantsManagerService.takePersistableUriPermission(UriGrantsManagerService.java:385) at android.app.IUriGrantsManager$Stub.onTransact(IUriGrantsManager.java:139) at android.os.Binder.execTransactInternal(Binder.java:1375) at android.os.Binder.execTransact(Binder.java:1311)
触发场景与原代码
当应用调用ContentResolver.takePersistableUriPermission方法获取SAF(存储访问框架)持久化权限时触发该异常,相关代码如下:
val safResultLauncher = rememberLauncherForActivityResult( contract = ActivityResultContracts.StartActivityForResult() ) { activityResult -> coroutineScope.launch { if (activityResult.resultCode == Activity.RESULT_OK) { val treeUri = activityResult.data?.data if (treeUri != null) { context.contentResolver.takePersistableUriPermission( treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION ) } } } } // 选择文件夹 try { safResultLauncher.launch(Intent.ACTION_OPEN_DOCUMENT_TREE) } catch (e: Throwable) { // ... }
受影响设备
该问题仅出现在搭载Android 13-14系统的三星设备上,涉及机型包括:
- Galaxy S24 Ultra
- Galaxy S24+
- Galaxy S21+ 5G
- Galaxy S20 FE 5G
- Galaxy Z Fold5
- Galaxy Z Flip4
- Galaxy A24
- Galaxy A15 5G
- Galaxy A15
- Galaxy A14 5G
解决方案与优化代码
鉴于Android系统的SAF权限限制,可通过清除已有的持久化Uri权限(当不再需要时),同时针对部分存储无法获取持久化Uri的情况捕获异常,优化后的代码如下:
fun grantPermissionForFolderSaf( context: Context, activityResult: ActivityResult, ): Uri? { if (activityResult.resultCode == Activity.RESULT_OK) { val treeUri = activityResult.data?.data if (treeUri != null) { clearAllPersistedUriPermissions(context) try { context.contentResolver.takePersistableUriPermission( /* uri = */ treeUri, /* modeFlags = */ Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION ) return treeUri } catch (e: Throwable) { // ... 提示用户尝试选择其他存储的说明 } } } return null } private fun clearAllPersistedUriPermissions(context: Context) { try { val contentResolver = context.contentResolver for (uriPermission in contentResolver.persistedUriPermissions) { contentResolver.releasePersistableUriPermission( /* uri = */ uriPermission.uri, /* modeFlags = */ Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION ) } } catch (e: Throwable) { // 安全起见... e.printStackTrace() } }
内容的提问来源于stack exchange,提问作者user924
相关产品推荐
相关产品推荐

