android7.0 獲取uri
android7.0以後,使用Uri.fromFile會報FileUriExposedException異常,這是因為android7.0以後執行了更加嚴格的檔案管理,要解決這一錯誤需要使用7.0新新增的FileProvide類,FileProvider官方文件:官方連結
FileProvider使用步驟:
1、定義一個FileProvider
在manifest裡面定義一個FileProvider:
<manifest>
...
<application>
...
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.mydomain.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
...
</provider>
...
</application>
</manifest>
name直接使用系統的android.support.v4.content.FileProvider,如果需要自己繼承FileProvider,則在這裡寫自己的FileProvider,一定要寫全名,即:包名+類名。exported設定為false,即FileProvider不需要共享,grantUriPermissions設定為true,即允許獲取臨時讀取uri的許可權。
2、指定可用檔案
在res資原始檔夾下建立xml資料夾,在xml資料夾下建立一名為file_paths的資原始檔:
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="my_images" path="images"/>
...
</paths>
paths元素必須包含以下一個或者多個子元素:
- files-path 對應目錄Context.getFilesDir()
- cache-path 對應目錄Context.getCacheDir()
- external-path 對應目錄Environment.getExternalStorageDirectory()
- external-files-path 對應目錄Context,getExternalFilesDir(String) 或者Context.getExternalFilesDir(null)
- external-cache-path 對應目錄Context.getExternalCacheDir()。
這一點要謹記,在後面建立檔案時會用到。
name 是分享的檔案路徑的一部分,它會覆蓋要分享的真實的路徑,即path指定的路徑。
path 即檔案真實路徑,最後創建出來的檔案路徑為(參照上述例子):Context.getFilesDir()+path+”/”+檔名。
然後在第一步的provider中引用這個資原始檔:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.mydomain.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
3、生成Uri
首先建立檔案:
File imagePath = new File(Context.getFilesDir(), "images");
File newFile = new File(imagePath, "default_image.jpg");
在建立第一個檔案即imagePath時,使用Context.getFilesDir()是因為第二步的資原始檔裡面使用了files-path,如改成external-path,則這裡要改成Environment.getExternalStorageDirectory(),其餘皆同。“images”對應的是第二步資原始檔裡面的path資源。最終newFile的檔名為:Context.getFilesDir()+”images/default_image.jpg”。
接下來,生成Uri:
Uri contentUri = FileProvider.getUriForFile(getContext(), "com.mydomain.fileprovider", newFile);
getUriForFile方法中的第二個引數要與第一步中在manifest檔案裡面建立的provider裡面的android:authorities名稱一樣。
4、分享
使用intent分享檔案時,要加入臨時許可權,已拍照為例:
Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
i.putExtra(MediaStore.EXTRA_OUTPUT, contentUri);
startActivity(i);