FileProvider使用以及遇到的坑記錄

爲什麼用FileProvider

7.0和更高的版本使用FilrProvider,這是都知道的事情,但是爲什麼要使用FilrProvider,因爲Android 7.0不允許intent帶有file://的URI離開自身的應用了,要不然會拋出FileUriExposedException

想要在自己應用和其他應用之間共享File數據,只能使用content://的方式

(1)建議使用自己的FileProvider

建立自己的FileProvider,因爲一個程序中在使用FileProvider時候,可能你調用的第三方的裏面也用到了
FileProvider,那麼在使用的時候就會存在衝突,建議你在使用時候直接自定義一個:

public class MyFileProvider extends FileProvider {
}

(2)必須在清單文件中配置

在清單文件中註冊:

 <provider
            android:name=".bases.MyFileProvider"
            android:authorities="包名.provider"
            android:exported="false"
            android:grantUriPermissions="true"
            tools:replace="android:authorities"
            >
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/files_names"
                tools:replace="android:resource"
                />
        </provider>
        /***android:name 它的值是固定的,是你的FileProvider,也可以用系統的自帶的
        android:authorities:屬性的值必須要和代碼中使用的時候一樣。
        <meat - data >標籤用來指定Uri的共享路徑。並且引用了一個@xml/file_paths資源
      
*/

###(3)
建立資源文件,對應於清單文件中配置的android:resource:屬性
在res - New - Directory - xml目錄 - New - File

<paths xmlns:android="http://schemas.android.com/apk/res/android">

    <!--填寫你要所要申請訪問的目錄地址,name最好是你的目錄名,path是你要申請的目錄-->
    <external-path name="camera_photos" path="."  />
    <external-path name="cache" path="Android/data/com.xuezj.fileproviderdemo/cache" />
    <external-path name="images" path="Pictures/" />
    <external-path name="dcim" path="DCIM/" />
    //可以配置多個
</paths>

擴展 paths標籤 如何去完成

上述只是演示了外部存儲的一種,其實Google還提供以下幾種方法

(1)
<files-path name="name" path="path" />  對應於getFilesDir()所表示的文件路徑
(2)
<cache-path name="name" path="path" /> 對應於getCacheDir()所表示的文件路徑
(3)
<external-path name="name" path="path" /> 對應於Environment.getExternalStorageDirectory(沒有參數)所表示的文件路徑,
(4)
<external-files-path name="name" path="path" />
 對應於getExternalFilesDir(String) 或者getExternalFilesDir(null) 所表示的文件路徑
 (5)
 <external-cache-path name="name" path="path" /> 對應於getExternalCacheDir()表示的文件路徑
 (6)
 <external-media-path name="name" path="path" /> 對應於Context.getExternalMediaDirs()所表示的文件路徑

你可以選擇你想要的存儲位置,進行選擇,對於這些存儲位置不懂得,可以參考文件存儲體系

上面有關鍵兩個屬性,都有name 與 path,下面展示兩個例子

實例一:

路徑配置:

<paths>
    <external-path   name="my_images"   path="Pictures" />
 </paths>

使用:

 File file = new File( Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),test.jpeg),;
 Uri contentUri = FileProvider.getUriForFile(Main2Activity.this,"與清單文件中配置的android:authorities一樣",file);
intent.setDataAndType(contentUri, "application/vnd.android.package-archive"); //可以使用Uri了
前面提到的path = Pictures ,所以這裏使用的參數是Environment.DIRECTORY_PICTURES
前面如果是DCIM,這裏相應的也要變成這個Environment.DIRECTORY_DCIM

實例二:

路徑配置

 <files-path name= "suiyidemingzi" path="apk_path" />

使用

    private File apkpath = null;
    private File contentFile = null;
    apkpath = new File(getFilesDir(),"apk_path"); //先建立與路徑配置中你自定義的path一致的子目錄 
    ,實例一通過傳參的方式得到的(因爲上述路徑是系統肯定自帶的)
    contentFile = new File(apkpath,"test.jepg"); //這裏文件名無所謂了,隨便配置了
    Uri contentUri = FileProvider.getUriForFile(Main2Activity.this, "和清單文件中配置的android:authorities一樣",contentFile );
    這時候就得到7.0以上版本使用的Uri了

發現name可以隨便取,但是不能重複了,而path則要慎重用,和文件存儲中的內部存儲,外部存儲一一相關,作用是爲了抽象Uri中路徑,不讓外部應用直接得到使用.
這裏寫圖片描述

上面的話如果難懂,下面是我自己的理解:

在xml中定義的標籤:
external-path  就等於 代碼中調用 Environment.getExternalStoragePublicDirectory這個方法得到的路徑,path就是子路徑
path表示的就是具體的哪個路徑如Pictures文件夾
兩者的作用一個樣,但是要對應起來,這樣系統在對外使用uri的時候纔不爲空。
files-path 就等於 getFilesDir()得到的路徑。
如果上面的話很難理解,不妨可以這樣想:
files-path + path 拼接成的路徑 必須保證和你代碼中構建的file路徑一致。

(4)

使用:在7.0之前的版本還是使用Uri.fromFile();方法的得到Uri

Uri uriP;
uriP = FileProvider.getUriForFile(MineStudentFragment.this.getContext()
                                , "包名.建議是自定義的provider"
                                , file);
                                /**這裏的參數二和清單文件註冊時候的android:authorities一致*/

(5)

權限,還是需要的。如果是想像外部存儲空間中存儲

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

錯誤:java.lang.IllegalArgumentException: Failed to find configured root that contains xxx文件路徑

再後來的使用中有些手機會返回這個異常,經過查找資料,發現需要額外配置如下:

<root-path
        name = "root_path"
        path="."
        />

這樣就可以解決部分機型因爲使用外置sd卡或者應用分身導致的問題。
華爲 p9與華爲 nove 2s在使用微信應用分身時候,會導致這個問題。
所以沒事就配置上就可以!!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章