抬头仰望星空,是否能发现自己的渺小。

伪斜杠青年

人们总是混淆了欲望和理想

Android 10 , 11 调用系统相机错误:Failed to find configured root that contains data.

做H5界面拍照功能遇到的错误:

java.lang.IllegalArgumentException: Failed to find configured root that contains your_file

网上的说法都很旧,大多数是说 FileProvider 配置错误而这里并不是,查看逻辑后发现,之前未适配 Android 10,11 ,所以使用的是 FileProvider.getUriForFile 获取到的URI,然后传递给系统相机即可,但目前新版本并不允许这样做,正确的做法如下:

先根据不同的 Android 版本生成不同的URI:

    val uploadUri:Uri

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        val values = ContentValues()
        values.put(MediaStore.Images.Media.DISPLAY_NAME, "pic.jpg")
        values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_DCIM)
        values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
        uploadUri = context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
    } else {
        val authority: String = context.getPackageName().toString() + ".fileprovider"
        val file = File(context.getCacheDir().toString() + "/pic.jpg")
        uploadUri = FileProvider.getUriForFile(context, authority, file)
    }

然后使用该 URI 作为相机拍照后输出的路径:

    val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
    intent.putExtra("return-data", true)
    intent.putExtra(MediaStore.EXTRA_OUTPUT, uploadUri)
    intent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
    startActivityForResult(intent, REQUEST_CODE_UPLOAD_IMAGE)

最后在拍照回调里先判断 intent.getData() 是否为空(大概率是为空),为空时直接用 uploadUri 即可。 Uri 怎么用?直接读输入流,然后保存到私有目录:

    InputStream inputStream = getContentResolver().openInputStream(uri);

可以发现整体逻辑变了:

Android 7.0 以下 :自行指定一个私有目录或者其他目录URI,然后传递给系统相机,系统相机获取到权限就可以随意写。

Android 10 及以上:需要先显示在系统中定义一个 URI,先报备再传递给系统相机进行操作,而且目录必须为公用目录(DCIM,Pictures)。

对于 Android 7.0以上的版本只要用 FileProvider 授权就行,Android 7.0以下的版本,随便怎么玩,但在Android 10以上,是不被允许的,同时对于相机的调用,输出目录只能用 DCIM, 以及 Pictures 目录,不信可以将上面的 Environment.DIRECTORY_DCIM 改成其他目录,看看报错就知道了(因为系统应用也没权限写我们应用的私有目录,其他目录我们又没有权限去读取)。

以上。


本站由以下主机服务商提供服务支持:

0条评论

发表评论