应用重启后无法访问Picker Uri权限问题求助
解决重启应用后无法访问图片Uri的权限问题
你遇到的问题根源是:ActivityResultContracts.GetContent()返回的图片Uri属于临时权限Uri,系统仅在当前应用会话内授予访问权限,重启应用后权限被回收,因此会抛出SecurityException。直接将这类Uri存入SharedPrefs是不可行的,以下是两种可靠的解决方案:
方案1:复制图片到应用私有目录,存储本地文件路径
将选中的图片复制到应用专属的私有存储目录,存储本地文件路径,无需依赖系统临时权限,是最稳定的方案。
实现步骤
- 编写Uri转本地文件的工具函数:
private suspend fun copyUriToLocal(context: Context, uri: Uri): String? { return withContext(Dispatchers.IO) { try { context.contentResolver.openInputStream(uri)?.use { inputStream -> val fileName = "selected_img_${System.currentTimeMillis()}.jpg" val localFile = File(context.filesDir, fileName) FileOutputStream(localFile).use { outputStream -> inputStream.copyTo(outputStream) } localFile.absolutePath } } catch (e: Exception) { e.printStackTrace() null } } }
- 修改选择器回调,保存本地路径到SharedPrefs:
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? -> uri?.let { lifecycleScope.launch { copyUriToLocal(context, it)?.let { localPath -> imageUri = Uri.fromFile(File(localPath)) // 存储本地路径 context.getSharedPreferences("app_prefs", Context.MODE_PRIVATE).edit() .putString("saved_image_path", localPath) .apply() } } } }
- 重启应用后读取路径并加载:
val prefs = context.getSharedPreferences("app_prefs", Context.MODE_PRIVATE) val savedPath = prefs.getString("saved_image_path", null) savedPath?.let { imageUri = Uri.fromFile(File(it)) }
方案2:使用OpenDocument()获取持久化Uri权限
通过ActivityResultContracts.OpenDocument()获取的Uri,可申请持久化访问权限,重启应用后依然有效,无需复制文件。
实现步骤
- 替换选择器Contract并申请持久化权限:
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.OpenDocument()) { uri: Uri? -> uri?.let { // 申请持久化读写权限 val persistFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION context.contentResolver.takePersistableUriPermission(it, persistFlags) imageUri = it // 存储Uri字符串到SharedPrefs context.getSharedPreferences("app_prefs", Context.MODE_PRIVATE).edit() .putString("saved_image_uri", it.toString()) .apply() } } // 启动图片选择器 launcher.launch(arrayOf("image/*"))
- 重启应用后读取Uri并加载:
val prefs = context.getSharedPreferences("app_prefs", Context.MODE_PRIVATE) val savedUriStr = prefs.getString("saved_image_uri", null) savedUriStr?.let { imageUri = Uri.parse(it) }
注意事项
- 该方案依赖原图存在,如果用户删除了原图,Uri会失效,需要处理加载失败的场景。
- 仅在用户主动选择图片时可申请持久化权限,无法通过其他方式获取。
方案对比
- 方案1:稳定性最高,不受用户删除原图影响,但会占用应用自身存储,适合需要长期保存的图片。
- 方案2:不占用额外存储,但依赖原图存在,适合临时展示或不需要长期留存的场景。
内容的提问来源于stack exchange,提问作者Us3rL0sT
相关产品推荐
相关产品推荐

