前言
最近测试那边报了个bug,手机拍照时出现crash,这么常用而且很久没动的一个功能咋就出错了。经过跟测试人员确认,是在7.0手机上出现的。果然,7.0以下版本没有这个问题,那肯定就是兼容性问题了。下面带大家一步步来解决问题。
1.注册内容提供者FileProvider
从7.0开始,Android不允许直接调用本地路径,那样被认为是不安全的,即使用 content://代替了 file:///。FileProvider是一种特殊的内容提供器,作为四大组件之一,我们要使用它得先在AndroidManifest文件中进行声明。
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.test.bf"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
我们需要创建一个共享路径xml文件file_paths
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="my_images"
path="test" />
<!--code below fix the 'failed to find configured root that contains xxx' exception-->
<root-path
name="root_path"
path="." />
</paths>
name属性的值可以随便写,path属性的值表示共享的具体位置
2.调用系统相机
因为6.0以上安卓增加了权限管理,在打开相机前得检查相应权限是否打开。因app在一开始便申请了权限,在这里就不贴出相应代码。
if (Build.VERSION.SDK_INT >= 24) {
//调用系统相机
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//临时添加权限
takePictureIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
File photoFile = null;
try {
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
PHOTO_PATH = storageDir.getPath();
photoFile = File.createTempFile("head_image", ".png", storageDir);
} catch (IOException ex) {
ex.printStackTrace();
}
if (photoFile != null) {
//获取uri,注意:路径跟上面FileProvider声明的时候一致
photoURI = FileProvider.getUriForFile(this, "com.test.bf", photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, PHOTO_REQUEST_CAREMA);
}
}
} else {/**code below is not work for version 7.0 or later*/
try {
File file = new File(PHOTO_PATH);
if (!file.exists()) {
boolean success = file.mkdirs();// 创建文件夹
if (!success) {
ToastUtil.showShort(getString(R.string.create_album_fail));
}
}
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
photoURI =Uri.fromFile(new File(PHOTO_PATH, PHOTO_NAME));
intent.putExtra(MediaStore.EXTRA_OUTPUT,
photoURI);
startActivityForResult(intent, PHOTO_REQUEST_CAREMA);// 采用ForResult打开
} catch (Exception e) {
e.printStackTrace();
}
}
3.裁剪图片(也需要做7.0适配)
public void cropPhoto(Uri uri, int outputX, int outputY) {
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(uri, "image/*");
intent.putExtra("crop", "true");
// aspectX aspectY 是宽高的比例
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
// outputX outputY 是裁剪图片宽高
intent.putExtra("outputX", outputX);
intent.putExtra("outputY", outputY);
intent.putExtra("return-data", true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//开启临时权限
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
//重点:针对7.0以上的操作
intent.setClipData(ClipData.newRawUri(MediaStore.EXTRA_OUTPUT, uri));
uritempFile = uri;
} else {
uritempFile = Uri.parse("file://" + "/" + Environment.getExternalStorageDirectory().getPath() + "/" + "small.jpg");
}
intent.putExtra(MediaStore.EXTRA_OUTPUT, uritempFile);
startActivityForResult(intent, PHOTO_CROP);
}
网友评论