做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 改成其他目录,看看报错就知道了(因为系统应用也没权限写我们应用的私有目录,其他目录我们又没有权限去读取)。
以上。
本站由以下主机服务商提供服务支持:
ludou
Android 10 及以上,拍照如何保存到Pictures目录下的指定文件夹,如Pictures/.nomedia。现在发现,删除Pictures根目录下的照片,有时会被华为手机拦截。不删除的话,app拍照产生的临时照片越来越多,占内存。
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
这里要怎么改一下?
Mosaic-C
我的理解是:应用自身的 data 目录下的文件不会产生.nomedia,.nomedia 是系统行为,另外 Pictures 文件夹是包含用户其他应用的图片的公共文件夹,属于隐私内容,删除会被拦截是正常行为,合理逻辑应该是:将临时文件保存在应用目录,需要导出的才导出(使用 URI 写入),并且导出后不再进行更改。
ludou
android 10以上系统调用相机拍照不是只能保存到DCIM或者Pictures目录吗?所以拍照的照片没办法保存到应用的cacheDir啊。现在使用RELATIVE_PATH存到Pictures的子目录下,删除照片同样有时会被拦截。如果保存到有.nomedia文件的目录下,又取不到uri。
Mosaic-C
虽然没有尝试,但我感觉 FileProvider.getUriForFile 这个 7.0 加进来的 API 在缓存目录应当是能用的,所以你可以试试,毕竟传递的 Uri 并没有说一定要来自于 MediaStore 创建的。