Android 6.0 系统拍照后拿到Uri进行裁剪,结果报错如下:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.android.gallery3d/com.android.gallery3d.filtershow.crop.CropActivity}: java.lang.SecurityException: Permission Denial: opening provider android.support.v4.content.FileProvider from ProcessRecord{a7016cc 27355:com.android.gallery3d/u0a35} (pid=27355, uid=10035) that is not exported from uid 10074
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2583)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2665)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1499)
at android.os.Handler.dispatchMessage(Handler.java:111)
at android.os.Looper.loop(Looper.java:207)
at android.app.ActivityThread.main(ActivityThread.java:5765)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:679)
Caused by: java.lang.SecurityException: Permission Denial: opening provider android.support.v4.content.FileProvider from ProcessRecord{a7016cc 27355:com.android.gallery3d/u0a35} (pid=27355, uid=10035) that is not exported from uid 10074
at android.os.Parcel.readException(Parcel.java:1599)
at android.os.Parcel.readException(Parcel.java:1552)
at android.app.ActivityManagerProxy.getContentProvider(ActivityManagerNative.java:3735)
at android.app.ActivityThread.acquireProvider(ActivityThread.java:5062)
at android.app.ContextImpl$ApplicationContentResolver.acquireUnstableProvider(ContextImpl.java:2023)
at android.content.ContentResolver.acquireUnstableProvider(ContentResolver.java:1517)
at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1121)
at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:958)
at android.content.ContentResolver.openInputStream(ContentResolver.java:678)
at com.mediatek.gallery3d.util.DecodeSpecLimitor.isOutOfSpecLimit(DecodeSpecLimitor.java:39)
at com.android.gallery3d.filtershow.crop.CropActivity.startLoadBitmap(CropActivity.java:240)
at com.android.gallery3d.filtershow.crop.CropActivity.onCreate(CropActivity.java:158)
at android.app.Activity.performCreate(Activity.java:6309)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1113)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2530)
拿到的Uri为:
content://xxx/File/Pictures/JPEG_20180712_112510.jpg
可以看到格式为:content://authorities/定义的name属性/文件的相对路径,即name隐藏了可存储的文件夹路径。
7.0的手机运行是没有问题,但是7.0以下会Crash。
因为低版本的系统,仅仅是把这个当成一个普通的Provider在使用,而我们没有授权,contentprovider的export设置的也是false;导致Permission Denial。
解决的核心是:给需要访问的Uri授权。
/**
* 裁剪
* @param fragment
* @param uri
* @param requestCode
*/
public static void startPhotoZoom(Fragment fragment, Uri uri, int requestCode) {
Context context = fragment.getActivity();
Intent intent = new Intent("com.android.camera.action.CROP");
String filePath = FileUtil.getPath(context, "Image") + "/" + System.currentTimeMillis() + ".png";//裁剪后
File file = new File(filePath);
Uri crop_uri = getUriForFile(context, file);
intent.setDataAndType(uri, "image/*");
if (Build.VERSION.SDK_INT < 24) {
grantPermissions(context, intent, uri, true);
}
//下面这个crop=true是设置在开启的Intent中设置显示的VIEW可裁剪
intent.putExtra("crop", "true");
intent.putExtra("scale", true);
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 600);
intent.putExtra("outputY", 600);
intent.putExtra("return-data", false);
intent.putExtra("noFaceDetection", true); // no face detection
intent.putExtra(MediaStore.EXTRA_OUTPUT, crop_uri);//裁剪后保存的路径Uri
if (Build.VERSION.SDK_INT < 24) {
grantPermissions(context, intent, crop_uri, true);
}
intent.putExtra("outputFormat", Bitmap.CompressFormat.PNG.toString());//保存格式
intent.putExtra("noFaceDetection", true); // no face detection
fragment.startActivityForResult(intent, requestCode);
}
/**
* 根据文件获取uri
*
* @param context
* @param file
* @return
*/
public static Uri getUriForFile(Context context, File file) {
Uri fileUri = null;
if (Build.VERSION.SDK_INT >= 24) {
fileUri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", file);
} else {
fileUri = Uri.fromFile(file);
}
return fileUri;
}
/**
* @param context
* @param intent
* @param uri
* @param writeAble 是否可读
*/
public static void grantPermissions(Context context, Intent intent, Uri uri, boolean writeAble) {
int flag = Intent.FLAG_GRANT_READ_URI_PERMISSION;
if (writeAble) {
flag |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
}
intent.addFlags(flag);
List resInfoList = context.getPackageManager()
.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resInfoList) {
String packageName = resolveInfo.activityInfo.packageName;
context.grantUriPermission(packageName, uri, flag);
}
}
鸿神已经解释的很详细了,具体可以看这个:
https://blog.csdn.net/lmj623565791/article/details/72859156