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

应用重启后无法访问Picker Uri权限问题求助

解决重启应用后无法访问图片Uri的权限问题

你遇到的问题根源是:ActivityResultContracts.GetContent()返回的图片Uri属于临时权限Uri,系统仅在当前应用会话内授予访问权限,重启应用后权限被回收,因此会抛出SecurityException。直接将这类Uri存入SharedPrefs是不可行的,以下是两种可靠的解决方案:


方案1:复制图片到应用私有目录,存储本地文件路径

将选中的图片复制到应用专属的私有存储目录,存储本地文件路径,无需依赖系统临时权限,是最稳定的方案。

实现步骤

  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
        }
    }
}
  1. 修改选择器回调,保存本地路径到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()
            }
        }
    }
}
  1. 重启应用后读取路径并加载:
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,可申请持久化访问权限,重启应用后依然有效,无需复制文件。

实现步骤

  1. 替换选择器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/*"))
  1. 重启应用后读取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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 23:50:15