如何在 Android 11+(API 30+)中安全、合规地从图库选取图片-java教程

android 11 及以上版本因分区存储(scoped storage)限制,使用 `action_pick` + `extra_output` 方式会导致“access denied”错误;应改用 `action_get_content` 获取只读 uri,并通过 `contentresolver` 安全读取图像数据。

在 Android 11(API 30)及更高版本中,Google 强制推行 分区存储(Scoped Storage),大幅收紧对共享存储(如 DCIM、Pictures)的直接文件路径访问权限。你当前代码中使用 Intent.ACTION_PICK 并传入 EXTRA_OUTPUT 的方式,在 Android 11+ 上已被系统拒绝写入权限——即使你声明了 READ_MEDIA_IMAGES,MediaStore 也不再允许第三方 App 向外部 URI 写入临时结果,因此会触发 “Access denied” 错误。

✅ 正确做法:放弃 ACTION_PICK + EXTRA_OUTPUT,改用 ACTION_GET_CONTENT
该方式不尝试写入外部 URI,而是由系统返回一个具有临时读取权限的 content:// URI(如 content://media/…),App 可通过 ContentResolver 安全读取图像数据,完全符合 Android 11+ 的隐私与存储规范。

✅ 推荐实现(现代 AndroidX Activity Result API)

// Kotlin 示例(推荐)
private val pickerActivityResultLauncher = registerForActivityResult(
    ActivityResultContracts.StartActivityForResult()
) { result ->
    if (result.resultCode == RESULT_OK && result.data?.data != null) {
        val photoUri: Uri = result.data!!.data!!

        // ✅ 安全获取 Bitmap(无需文件路径!)
        val bitmap = MediaStore.Images.Media.getBitmap(contentResolver, photoUri)
        imageView.setImageBitmap(bitmap)

        // ✅ 或转换为 File(如需保存/上传)
        val inputStream = contentResolver.openInputStream(photoUri)
        val tempFile = File(cacheDir, "picked_${System.currentTimeMillis()}.jpg")
        inputStream?.use { input ->
            FileOutputStream(tempFile).use { output ->
                input.copyTo(output)
            }
        }
        Log.d("Picker", "Saved to: ${tempFile.absolutePath}")
    }
}
// Java 示例(兼容写法)
private final ActivityResultLauncher<Intent> pickerActivityResultLauncher =
    registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
        result -> {
            if (result.getResultCode() == RESULT_OK && result.getData() != null) {
                Uri photoUri = result.getData().getData();
                try {
                    Bitmap bitmap = MediaStore.Images.Media.getBitmap(
                        getContentResolver(), photoUri);
                    imageView.setImageBitmap(bitmap);

                    // 如需保存为本地文件(推荐缓存目录)
                    InputStream is = getContentResolver().openInputStream(photoUri);
                    File tempFile = new File(getCacheDir(), "picked_" + System.currentTimeMillis() + ".jpg");
                    try (FileOutputStream os = new FileOutputStream(tempFile)) {
                        is.transferTo(os);
                    }
                    Log.d("Picker", "Saved: " + tempFile.getAbsolutePath());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

调用选取器:

夏夕资源网专注于CMS网站模板,主流语言整站网站源码下载,网站建设相关教程分享,好用的软件素材整合下载,提供一站式便捷自助服务。
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
7. 如遇到加密压缩包,默认解压密码为"zy.lucklyus.top",如遇到无法解压的请联系管理员!
夏夕资源网-网站模板_免费源码_资源素材 » 如何在 Android 11+(API 30+)中安全、合规地从图库选取图片-java教程
在线时间:12:00 - 22:00
关注微信公众号:微信公众号
站长邮箱:[email protected]
  • 运营天数: 1394+
  • 资源总数: 47989+
  • 用户总数: 1+
  • 今日更新: 0+
  • 访问次数: 4043028+
  • 本周更新: 0+
  • 最后更新: 2026-03-16

本站指数

×
  • 运营天数: 1394+
  • 资源总数: 47989+
  • 用户总数: 1+
  • 今日更新: 0+
  • 访问次数: 4043028+
  • 本周更新: 0+
  • 最后更新: 2026-03-16