Android 開發 關於7.0 FileUriExposedException異常 詳解

異常緣由

  Android再也不容許在app中把file://Uri暴露給其餘app,包括但不侷限於經過Intent或ClipData 等方法。緣由在於使用file://Uri會有一些風險,好比:android

  • 文件是私有的,接收file://Uri的app沒法訪問該文件。
  • 在Android6.0以後引入運行時權限,若是接收file://Uri的app沒有申請READ_EXTERNAL_STORAGE權限,在讀取文件時會引起崩潰。

所以,google提供了FileProvider,使用它能夠生成content://Uri來替代file://Uri安全

解決流程

  1. 添加res/xml/provider_paths.xml 文件
  2. AndroidManifest.xml中添加provider
  3. 在代碼裏使用FileProvider.getUriForFile()方法得到Url

 

添加res/xml/provider_paths.xml 文件

在 res/xml 目錄下新建一個 xml 文件,用於存放應用須要共享的目錄文件。這個 xml 文件的內容相似這樣:app

<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="cam" path="images" />
</paths>
目錄表
  • <files-path>:內部存儲空間應用私有目錄下的 files/ 目錄,等同於 Context.getFilesDir() 所獲取的目錄路徑;
  • <cache-path>:內部存儲空間應用私有目錄下的 cache/ 目錄,等同於 Context.getCacheDir() 所獲取的目錄路徑;
  • <external-path>:外部存儲空間根目錄,等同於 Environment.getExternalStorageDirectory() 所獲取的目錄路徑;
  • <external-files-path>:外部存儲空間應用私有目錄下的 files/ 目錄,等同於 Context.getExternalFilesDir(null) 所獲取的目錄路徑;
  • <external-cache-path>:外部存儲空間應用私有目錄下的 cache/ 目錄,等同於 Context.getExternalCacheDir();

  能夠看出,這五種子元素基本涵蓋內外存儲空間全部目錄路徑,包含應用私有目錄。同時,每一個子元素都擁有 name path 兩個屬性。其中,path 屬性用於指定當前子元素所表明目錄下須要共享的子目錄名稱。注意:path 屬性值不能使用具體的獨立文件名,只能是目錄名。而 name 屬性用於給 path 屬性所指定的子目錄名稱取一個別名。後續生成 content:// URI 時,會使用這個別名代替真實目錄名。這樣作的目的,很顯然是爲了提升安全性。若是咱們須要分享的文件位於同級別目錄下不一樣的子目錄中,就須要添加多個子元素逐一指定要分享的文件目錄,或者共享他們通用的父目錄也行。ide

  不一樣的app可能會有要求不一樣的共享目錄,這個要求的共享目錄能夠在報錯裏找到,添加對應的報錯路徑便可.this

AndroidManifest.xml中添加provider

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="com.yt.demo.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true"> <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/provider_paths" /> 
</provider>

請注意authorities這行,須要添加你的包名 加 後綴google

在代碼裏使用FileProvider.getUriForFile()方法得到Url

例子代碼以下:spa

String filePath = Environment.getExternalStorageDirectory() + "/images/"+System.currentTimeMillis()+".jpg"; 
File outputFile = new File(filePath); 
if (!outputFile.getParentFile().exists()) { 
    outputFile.getParentFile().mkdir(); 
} 
Uri contentUri = FileProvider.getUriForFile(this, getPackageName()+".fileprovider", outputFile);
相關文章
相關標籤/搜索