1、崩溃场景**
- 当用户使用android7.0系统的手机调用相机
- 或者打开相册、读取写入文件时崩溃
2、崩溃的描述
- android.os.FileUriExposedException这个错误提示
- 针对于权限部分,Android7.0是google推出的对权限做了一个更新即不允许出现以file://的形式调用隐式APP系统,也就是说以前呢,Uri的获取方式是以file://xxx的样式来,那么我们也就是通过Uri.fromFile()来获取如今放在7.0及以上系统呢,这样子就不行啦;
- 如今的解决关键在哪里呢,需要在应用间共享文件,也就是需要发送一项content://URI,并授予 URI 临时访问权限。进行此授权的最简单方式是使用FileProvider类。
3、解决方案
1、(推荐)7.0之后你的app就算有权限,给出一个URI之后手机也认为你没有权限。
不用修改原有代码,在Application的oncreate方法中:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
StrictMode.VmPolicy.Builder builder = new
StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
}
2、在调用相机的时候添加7.0系统的判断然后读取相册
/*获取当前系统的android版本号*/
int currentapiVersion = android.os.Build.VERSION.SDK_INT;
Log.e("currentapiVersion","currentapiVersion====>"+currentapiVersion);
if (currentapiVersion<24){
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(pathFile));
startActivityForResult(intent, TAKE_PICTURE);
}else {
ContentValues contentValues = new ContentValues(1);
contentValues.put(MediaStore.Images.Media.DATA, pathFile.getAbsolutePath());
Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,contentValues);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(intent, TAKE_PICTURE);
}
①在mainfest标签里加入以下该权限
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
②在application下加入该provider
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.test.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
在这里我们需要注意一下其中设置的各种属性的含义:
- authorities:是该项目的包名+provider
- grantUriPermissions:必须是true,表示授予 URI 临时访问权限
- exported:必须是false
- resource:中的@xml/file_paths是我们接下来要在资源文件目录下添加的文件
③在res目录下创建xml文件夹,在里面新建filepaths.xml文件,代码如下
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<paths>
<external-path path="" name="camera_photos" />
<files-path path="" name="photos" />
</paths>
</resources>
需要注意的是:
- path:需要临时授权访问的路径(.代表在相机调用时候访问的是所有路径,而文件写入时访问的路径是Android/data/com.ijuyin.prints.news/)
- name: 是你为设置的这个访问路径起的名字
④接下来便是修改适配Android 7.0及以上系统的代码
//拍照
Intent camera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//适配android7.0 手机拍照取uri的处理
if(Build.VERSION.SDK_INT<24){
uri = Uri.fromFile(imgFile);//7.0这里会闪退,imgfile是图片文件路径
camera.putExtra(MediaStore.EXTRA_OUTPUT, uri);
}else{
uri=FileProvider.getUriForFile(SellerAffiliate.this,"com.test.fileprovider",imgFile);
camera.putExtra(MediaStore.EXTRA_OUTPUT, uri);
camera.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION );//添加这一句表示对目标应用临时授权该Uri所代表的文件
}
startActivityForResult(camera, FLAG_CHOOSE_CAMERA);
//跳转相册
Intent intent = new Intent();
intent.setAction(Intent.ACTION_PICK);
intent.setType("image/*");
startActivityForResult(intent, FLAG_CHOOSE_IMG);
然后在onactivityresult拍照回调中
if (data != null) {
String filepath="";
//拍照返回
if(getPhotoType.equals("0")){
if(uri.getScheme()!=null && "content".equalsIgnoreCase(uri.getScheme())){
filepath=imgFile.getAbsolutePath();
}else{
filepath=uri.getPath();
}
}//相册返回
else{
if (data != null) {
filepath =pathStr;
}
}
// pathStr=path;
//将图片进行双重压缩后再上传
// String filepath=BitmapComPressUtils.getRealFilePath(SellerAffiliate.this,uri);
Bitmap imgBitmap= BitmapComPressUtils.getDecordeImage(SellerAffiliate.this,filepath,800f,480f);
if(imgBitmap==null){
return;
}
String imgpath=BitmapComPressUtils.saveBitmap(SellerAffiliate.this,imgBitmap);
pathStr=imgpath;
网友评论