Android 7.0调用系统相机(文件访问crash android.os.FileUriExposedException)
2017-12-06 18:50
696 查看
最近项目中做图片上传的功能中遇到一个问题,就是7.0的手机上调用系统相机指定图片路径的情况下回crash,报错android.os.FileUriExposedException uri暴露的错误。
Android7.0对应用共享文件这块做了一些强制性的要求。从7.0开始,android框架默认执行StrictMode,禁止向应用外公开file://的URI,也就是说必须将此URI转换为content://,才能给别的应用使用,并授予URI临时访问权限。
知道错误原因了,那么解决办法就好说了:
第一种办法:绕过7.0的文件权限检查
既然默认执行了StrictMode,那最简单的办法就是禁止执行StrictMode,绕过7.0的文件权限检查,也是最简单的一种方式,只需要添加少量代码,而可以不改动原来的代码
第二种办法:使用 FileProvider类授权
使用方法:
1.在manifest.xml中添加provider
2.在res文件夹下新建文件夹xml,在xml里新建文件file_paths.xml,
file_paths.xml:
files-path代表的根目录: Context.getFilesDir()
external-path代表的根目录: Environment.getExternalStorageDirectory()
cache-path代表的根目录: getCacheDir()
path路径当然也可以自己定义,与实际文件路径存在就行;“.”类似于通配符,使用所有的路径
例如文件路径“/storage/emulated/0/Android/data/包名/cache/1512556077575.jpg”
7.0的URI:”content://包名.fileProvider/files_root/cache/1512556077575.jpg”
其中“包名.fileProvider”为在manifest.xml中配置的authorities。
3.在调用相机时:
其中FileProvider.getUriForFile()的第二个参数必须与在在manifest.xml中配置的authorities一致,也可以不使用包名,但必须保持一致。
最终7.0上:
file:/storage/emulated/0/Android/data/包名/cache/1512556077575.jpg
picUri :content://包名.fileProvider/files_root/cache/1512556077575.jpg
然后就可以正常打开相机了。
4.拍照返回
关于6.0权限问题不要忘了,就不在此列出了。
此文章借鉴很多他人博客,不在一一列举,谢谢各位。
Android7.0对应用共享文件这块做了一些强制性的要求。从7.0开始,android框架默认执行StrictMode,禁止向应用外公开file://的URI,也就是说必须将此URI转换为content://,才能给别的应用使用,并授予URI临时访问权限。
知道错误原因了,那么解决办法就好说了:
第一种办法:绕过7.0的文件权限检查
既然默认执行了StrictMode,那最简单的办法就是禁止执行StrictMode,绕过7.0的文件权限检查,也是最简单的一种方式,只需要添加少量代码,而可以不改动原来的代码
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); StrictMode.setVmPolicy(builder.build()); }
这段代码可以写在Application的onCreate()里,也可以写在需要调用文件访问的地方。 当然这是一种比较流氓的方法,放弃了设计者的初衷;
第二种办法:使用 FileProvider类授权
使用方法:
1.在manifest.xml中添加provider
<application ...> <provider android:authorities="你的包名.fileProvider" android:name="android.support.v4.content.FileProvider" android:grantUriPermissions="true" android:exported="false"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"/> </provider> </application>
2.在res文件夹下新建文件夹xml,在xml里新建文件file_paths.xml,
file_paths.xml:
<?xml version="1.0" encoding="utf-8"?> <paths> <external-path path="Android/data/包名/" name="files_root" /> <external-path path="." name="external_storage_root" /> <cache-path name="cache_paths" path="cache/"/> </paths>
files-path代表的根目录: Context.getFilesDir()
external-path代表的根目录: Environment.getExternalStorageDirectory()
cache-path代表的根目录: getCacheDir()
path路径当然也可以自己定义,与实际文件路径存在就行;“.”类似于通配符,使用所有的路径
例如文件路径“/storage/emulated/0/Android/data/包名/cache/1512556077575.jpg”
7.0的URI:”content://包名.fileProvider/files_root/cache/1512556077575.jpg”
其中“包名.fileProvider”为在manifest.xml中配置的authorities。
3.在调用相机时:
private void openCamera() { String photoName = Calendar.getInstance().getTimeInMillis() + ".jpg"; Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); file = new File(getExternalCacheDir(), photoName);//file是一个全局变量 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //7.0 以上 picUri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".fileProvider", file); }else { //7.0 以下 picUri = Uri.fromFile(file); } intent.putExtra(MediaStore.EXTRA_OUTPUT, picUri); startActivityForResult(intent, CAMERA_REQUEST); }
其中FileProvider.getUriForFile()的第二个参数必须与在在manifest.xml中配置的authorities一致,也可以不使用包名,但必须保持一致。
最终7.0上:
file:/storage/emulated/0/Android/data/包名/cache/1512556077575.jpg
picUri :content://包名.fileProvider/files_root/cache/1512556077575.jpg
然后就可以正常打开相机了。
4.拍照返回
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode != RESULT_OK) { return; } switch (requestCode){ case CAMERA_REQUEST://拍照返回 ivPic.setImageURI(picUri);//显示图片 //以下代码用于获取图片文件,7.0如果也用picUri.getPath(),则得到的文件f为空,所以通过全局变量file来获取 String url = picUri.getPath(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){ url = file.getPath(); } File f = new File(url); System.out.println("~file bytes = " + f.length() + " b"); //todo break; case ALNUM_REQUEST: break; } }
关于6.0权限问题不要忘了,就不在此列出了。
此文章借鉴很多他人博客,不在一一列举,谢谢各位。
相关文章推荐
- Android 7.0调用系统相机报错Caused by: android.os.FileUriExposedException: file:///storage/emulated/0/rpms/14
- Android 7.0 系统相机崩溃解决android.os.FileUriExposedException
- 【适配整理】Android 7.0 调取系统相机崩溃解决android.os.FileUriExposedException
- 【适配整理】Android 7.0 调取系统相机崩溃解决android.os.FileUriExposedException
- Android 7.0 FileUriExposedException 解决(调用系统相机)
- Android 7.0 调取系统相机崩溃解决android.os.FileUriExposedException
- 解决Android7.0系统 调用系统相机、系统播放器播放视频、切图兼容问题,报异常android.os.FileUriExposedException
- 解决Android7.0系统 调用系统相机、系统播放器播放视频、切图兼容问题,报异常android.os.FileUriExposedException
- android 7.0系统打开本地文件的问题android.os.FileUriExposedException:file:///storage/emulated/0/
- android 7.0系统解决拍照的问题android.os.FileUriExposedException:
- android 7.0读取文件报异常信息 - android.os.FileUriExposedException
- 兼容Android N 调用相册和相机获取图片及Crash- FileUriExposedException解决方案
- Android 7.0 调取相机崩溃 android.os.FileUriExposedException
- android 7.0系统解决拍照的问题android.os.FileUriExposedException:file:///storage/emulated/0/test.txt
- Android 7.0调用相机拍照 报错 FileUriExposedException
- android 7.0 + 相机拍照 FileUriExposedException
- Android 7.0 调用系统相机崩溃解决 android.os.FileUriException
- Android 7.0配置fileprovider共享文件 解决FileUriExposedException
- Android 7.0 调用照相机照相报错 FileUriExposedException 解决
- Android7.0打开本地文件失败 android.os.FileUriExposedException