本文主要是介绍Android 调用自带相机抛FileUriExposedException异常,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
最近公司业务需求,做一个类似淘宝,京东的拍照搜索商品的功能,这里搜索引擎使用的是百度的AI搜图,效果整体还不错。服务端接口接收的参数是一个图片文件,这里就需要使用到Android自带相机,按照常规的用法写完后在某些手机上报错,查看log FileUriExposedException,抛出这样一个异常.
上网查阅了资料后得知在Android 7.0以后的应用,Android 框架执行的 StrictMode API 政策禁止在您的应用外部公开 file:// URI。如果一项包含文件 URI 的 intent 离开您的应用,则应用出现故障,并出现 FileUriExposedException 异常。
解决办法:
Google给出的解决办法使用FileProvider ,FileProvider是v4包中一个继承ContentProvider的子类,位置是android.support.v4.content,他可以通过File创建一个content://类型的Uri而不是file://类型的Uri.
使用步骤:
1.manifest中申明FileProvider
android:authorities:类似schema,命名空间之类,后面会用到。
android:exported:false表示我们的provider不需要对外开放。
android:grantUriPermissions:申明为true,你才能获取临时共享权限
2.res/xml中定义对外暴露的文件夹路径
在res文件夹下创建名为xml的文件夹,然后再xml文件夹下创建名为file_paths.xml(注:在manifest android:resource="@xml/file_paths"处引用此文件
)
name:一个引用字符串。
path:文件夹“相对路径”,完整路径取决于当前的标签类型。
paths节点下有很多取值:
<files-path name="name" path="path" /> 物理路径相当于Context.getFilesDir() + /path/。
<cache-path name="name" path="path" /> 物理路径相当于Context.getCacheDir() + /path/。
<external-path name="name" path="path" /> 物理路径相当于Environment.getExternalStorageDirectory() + /path/。
<external-files-path name="name" path="path" /> 物理路径相当于**Context.getExternalFilesDir(String) **+ /path/。
<external-cache-path name="name" path="path" />物理路径相当于Context.getExternalCacheDir() + /path/。
<root-path name="name" path="path" /> 物理路径相当于/path/。
3.生成content://类型的Uri
平常我们写法是这样的,在7.0后就会抛出FileUriExposedException:
File picFile = xxx;
Uri picUri = Uri.fromFile(picFile);
所以我们需要使用content来生成URL
Url uri = FileProvider.getUriForFile(fragment.getActivity(), "com.jiemeihome.internal", getFile());
4.给Uri授予临时权限
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
Intent.FLAG_GRANT_READ_URI_PERMISSION //表示可读
Intent.FLAG_GRANT_WRITE_URI_PERMISSION//表示可写
权限的添加视项目需求而定.
5.使用Intent传递Uri
项目中需要使用到相机和相册代码如下:
public static void startCarmera(Fragment fragment) {Uri uri; Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); uri = FileProvider.getUriForFile(fragment.getActivity(), "com.jiemeihome.internal", getFile()); intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); } else {intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(getFile())); }fragment.startActivityForResult(intent, RESULT_CAMERA); }
public static void startGallery(Activity activity) {Intent intentGallery = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); activity.startActivityForResult(intentGallery, RESULT_GALLERY); }
public static File getFile() {File newFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+ "/images/" + System.currentTimeMillis() + ".jpg"); if (!newFile.exists()) {newFile.getParentFile().mkdirs(); }mCurrentPhotoPath = newFile.getAbsolutePath(); return newFile; }
然后再onActivityResult()中处理接收返回的图片:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) {if (requestCode == RESULT_CAMERA) {upload(CarmeraUtil.mCurrentPhotoPath); } else if (requestCode == RESULT_GALLERY && data != null) {//处理来自图库的照片 Uri selectedImage = data.getData(); String[] filePathColumn = {MediaStore.Images.Media.DATA}; Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null); cursor.moveToFirst(); int columnIndex = cursor.getColumnIndex(filePathColumn[0]); String picturePath = cursor.getString(columnIndex); cursor.close(); upload(picturePath); }} }
这篇关于Android 调用自带相机抛FileUriExposedException异常的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!