7.0 Build.VERSION_CODES.N 24
为什么要适配
在7.0中 ,Uri.from(file),可能会触发FileUriExposedException
和动态权限一样,如果target选择24以下是不需要适配的,但还是应该尽早适配
解决办法:在24及以上,使用content:// 替代 file:// (Uri.from(file))
适配步骤
1.在res下,新建一个xml目录,在其中创建一个任意名字的xml文件,如file_provider_paths.xml
<?xml version="1.0" encoding="utf-8"?> <paths> <external-path name="external" path="." /> </paths>
xml说明
external-path 等同于 Environment.getExternalStorageDirectory() 如果将path设置为path=“pic”,则共享的文件限制为/storage/emulated/0/pic/ 为空,则共享文件目录为storage/emulated/0/ <root-path/> 代表设备的根目录new File("/"); <files-path/> 代表context.getFilesDir() <cache-path/> 代表context.getCacheDir() <external-path/> 代表Environment.getExternalStorageDirectory() <external-files-path>代表context.getExternalFilesDirs() <external-cache-path>代表context.getExternalCacheDirs()
2.在Manifest文件中注册FileProvider对象
<provider android:name="android.support.v4.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_provider_paths"/> </provider>
3.修改java代码,场景拍照,裁剪,安装apk
fp=context.getPackageName()+".fileprovider";
3.1 拍照
imgPath = FileUtil.generateImgePath(); File imgFile = new File(imgPath); //设置拍照后的图片的保存位置 Log.i("TAG", imgFile.getAbsolutePath()); Uri imgUri = null; Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //通过FileProvider创建一个content类型的Uri imgUri = FileProvider.getUriForFile(activity, fp, imgFile); //添加这一句表示对目标应用临时授权该Uri所代表的文件 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } else { imgUri = Uri.fromFile(imgFile); } intent.putExtra(MediaStore.EXTRA_OUTPUT, imgUri); final Uri uri = imgUri; activity.startActivityForResult(intent, new CallBackIntent() { @Override public void onResult(Intent data) { if (data == null || data.getData() == null) // ToastUtils.startShort(activity, "拍照数据返回为空"); Log.i("TAG", "拍照数据返回为空"); startPhotoZoom(uri, activity, new IntentCallBack() { @Override public void onIntent(Intent intent) { callBack.onBitmap(getImageView(intent)); } }); } });
imgPath,就是拍照后图片保存的路径
3.2 裁剪
//适配7.0的uri,(文件uri转化为ContentUri) public Uri getImageContentUri(Context context, File imageFile) { String filePath = imageFile.getAbsolutePath(); Cursor cursor = context.getContentResolver().query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[] { MediaStore.Images.Media._ID }, MediaStore.Images.Media.DATA + "=? ", new String[] { filePath }, null); if (cursor != null && cursor.moveToFirst()) { int id = cursor.getInt(cursor .getColumnIndex(MediaStore.MediaColumns._ID)); Uri baseUri = Uri.parse("content://media/external/images/media"); return Uri.withAppendedPath(baseUri, "" + id); } else { if (imageFile.exists()) { ContentValues values = new ContentValues(); values.put(MediaStore.Images.Media.DATA, filePath); return context.getContentResolver().insert( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); } else { return null; } } }
如果是由相机或者相册之后调用裁减,无需转化uri
如果是单独使用裁减功能,则需要利用上述方法进行转化
private void cropPicture(Uri uri) { Intent innerIntent = new Intent("com.android.camera.action.CROP"); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //添加这一句表示对目标应用临时授权该Uri所代表的文件 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } innerIntent.setDataAndType(uri, "image/*"); innerIntent.putExtra("crop", "true"); //不是1比1 主要是为了适配华为手机一比一时,裁减是圆形的 innerIntent.putExtra("aspectX", 9998); innerIntent.putExtra("aspectY", 9999); innerIntent.putExtra("outputX", 320); innerIntent.putExtra("outputY", 320); innerIntent.putExtra("return-data", true); innerIntent.putExtra("scale", true); activity.startActivityForResult(intent, new CallBackIntent() { @Override public void onResult(Intent data) { callBack.onIntent(data); //裁减后的图片 //Bitmap bitmap = data.getParcelableExtra("data"); } }); }
3.3 安装apk
private void installAPK(UpdateInfo updateInfo) { File apkfile = new File(mSavePath, updateInfo.getClientVersionName()); if (!apkfile.exists()) { return; } String cmd = "chmod 777 " + apkfile.toString(); try { Runtime.getRuntime().exec(cmd); } catch (Exception e) { e.printStackTrace(); } // 通过Intent安装APK文件 Intent i = new Intent(Intent.ACTION_VIEW); if (Build.VERSION.SDK_INT >= 24) { //适配安卓7.0 i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); Uri apkFileUri = FileProvider.getUriForFile(context.getApplicationContext(), fp, apkfile); i.setDataAndType(apkFileUri, "application/vnd.android.package-archive"); } else { i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); i.setDataAndType(Uri.parse("file://" + apkfile.toString()),"application/vnd.android.package-archive"); } context.startActivity(i); //关闭当前程序 int pid = android.os.Process.myPid(); android.os.Process.killProcess(pid); }