?
升級到Android7.0之后,啟動系統相機或者截圖,傳入URI的時候可能會導致程序閃退崩潰。這是因為7.0的新的文件權限導致的。下面是解決這個問題的快速解決方案。
?
問題代碼
?
在7.0可能會出問題的代碼:
?
final String CACHE_IMG = Environment.getExternalStorageDirectory()+"/demo/"
final int TAG_PHOTO_CAMERA=200;Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);String fileName = "defaultImage.jpg";File file = new File(CACHE_IMG, fileName);Uri uri = Uri.fromFile(file);intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);startActivityForResult(intent, TAG_PHOTO_CAMERA);
?
其中Uri uri = Uri.fromFile(file);這里會導致閃退。
?
解決方法
?
step1. 將Uri的生成方式改為由FileProvider提供的臨時授權路徑,并且在intent中添加flag
修改后代碼如下
?
final String CACHE_IMG = Environment.getExternalStorageDirectory()+"/demo/"
final int TAG_PHOTO_CAMERA=200;Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);String fileName = "defaultImage.jpg";File file = new File(CACHE_IMG, fileName);Uri imageUri=FileProvider.getUriForFile(activity,"me.xifengwanzhao.fileprovider", file);//這里進行替換uri的獲得方式intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//這里加入flagstartActivityForResult(intent, TAG_PHOTO_CAMERA);
?
step2.在AndroidManifest.xml中的application標簽中添加provider的配置
?
<application
...><provider
android:name="android.support.v4.content.FileProvider"android:authorities="me.xifengwanzhao.fileprovider"//這里需要和上面部分字符串相同android:exported="false"android:grantUriPermissions="true"><meta-data
android:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/file_paths" /></provider></application>
?
step3.在res/xml中新建一個文件file_paths.xml
?
<?xml version="1.0" encoding="utf-8"?>
<resource xmlns:android="http://schemas.android.com/apk/res/android"><external-path
name="images"path="demo/" />
</resource>
?
OK,大功告成,這樣就不會崩潰了
?
代碼解釋
?
我們先看Google官方的7.0行為變更介紹 (不需要翻墻)
?
對于面向 Android 7.0 的應用,Android 框架執行的 StrictMode API 政策禁止在您的應用外部公開 file:// URI。如果一項包含文件 URI 的 intent 離開您的應用,則應用出現故障,并出現 FileUriExposedException 異常。
要在應用間共享文件,您應發送一項 content:// URI,并授予 URI 臨時訪問權限。進行此授權的最簡單方式是使用 FileProvider 類。如需了解有關權限和共享文件的詳細信息,請參閱共享文件。
?
根據文檔提示我們使用FileProvider進行處理,同時利用xml對FileProvider進行配置
參考如下
?
java根路徑產生方式 | 對應xml根節點名稱 |
---|---|
Context.getFilesDir() | files-path |
getCacheDir() | cache-path |
Environment.getExternalStorageDirectory() | external-path |
Context#getExternalFilesDir(String) Context.getExternalFilesDir(null) | external-files-path |
Context.getExternalCacheDir() | external-cache-path |
?
節點中的name 不可重名,path為自定義
?
關于相冊選圖和相機裁剪
?
有同學反映相冊選圖和相機裁剪時候的報錯問題,這里也說一下
系統相冊選圖返回的Uri是可以直接使用的,不需要也不能使用FileProvider進行轉換
如果需要根據uri獲得轉換后的uri 可以參考如下方式
?
Uri fromUri;
if (uri.getScheme() != null && uri.getScheme().startsWith("file")) {fromUri =FileProvider.getUriForFile(mContext,"me.xifengwanzhao.fileprovider", new File(FileUtils.getPath(mContext, uri)));//這里進行替換uri的獲得方式intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//這里加入flag
} else {//相冊選圖適配fromUri = uri;
}
?
關于相機裁剪
相機裁剪 intent.setDataAndType(fromUri, “image/*”);這里是需要對uri進行轉換的,
而 intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));這里使用原來的方式獲取uri就可以了
那么啟動系統裁剪的方法可以寫成這樣
?
/*** 開啟截圖,啟動系統的截圖方法 返回requestCode為 {Constant.IMG_ZOOM}** @param mContext 必須為activity* @param uri 需要進行裁剪的圖片的uri* @param size 截圖的大小寬和高的數值,這里僅限截圖為1:1的正方形* @return path 截圖返回的路徑* @see Constant#IMG_ZOOM*/public static String startPhotoZoom(Activity mContext, Uri uri, int size) {//這里生成一個保存截圖用的臨時路徑并且返回出去String imgPath;File file = new File(Constant.ZOOM_IMAGE, Constant.getNewestImageName(mContext));imgPath = file.getPath();Intent intent = new Intent("com.android.camera.action.CROP");Uri fromUri;if (uri.getScheme() != null && uri.getScheme().startsWith("file")) {fromUri = FileProvider.getUriForFile(mContext, "me.xifengwanzhao.fileprovider", new File(FileUtils.getPath(mContext, uri)));//這里進行替換uri的獲得方式intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//這里加入flag} else {//相冊選圖適配fromUri = uri;}intent.setDataAndType(fromUri, "image/*");intent.putExtra("crop", "true");intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));if (android.os.Build.MANUFACTURER.contains("HUAWEI")) {// 華為特殊處理 不然會顯示圓intent.putExtra("aspectX", 9998);intent.putExtra("aspectY", 9999);} else {intent.putExtra("aspectX", 1);intent.putExtra("aspectY", 1);}intent.putExtra("outputX", size);intent.putExtra("outputY", size);mContext.startActivityForResult(intent, Constant.IMG_ZOOM);return imgPath;}
?
參考文檔
?
[1]Android N 調用相冊crash- FileUriExposedException
[2]根據 Android Training課程寫的FileProvider小例子
[3]使用FileProvider共享文件
[4]Android7.0適配教程與心得
[5]Android N 調用相冊crash- FileUriExposedException
---------------------
作者:夕楓晚照
來源:CSDN
原文:https://blog.csdn.net/xifengwanzhao/article/details/53587234
版權聲明:本文為作者原創文章,轉載請附上博文鏈接!