FileProvider

1.問題

Android7.0開始,應用私有目錄被限制訪問,官方做了如下限制:
1.私有文件的文件權限不應再由所有者放寬,使用MODE_WORLD_READABLE/MODE_WORLD_WRITEABLE將拋出異常
2.嚮應用外傳遞file://URI會出發FileUriExposedException

2.FileProvider

當targetSdkVersion>=24時,會存在上述問題,可能涉及到的場景有:拍照,程序安裝等。
同時,官方在v4包(api=22開始)中引入FileProvider類用於程序間私有文件的共享。該類繼承自ContentProvider,使用時需要在清單文件中註冊。

這裏寫圖片描述

 <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.example.servertest.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
        </provider>

設置可訪問的共享文件
FileProvider只能對聲明的文件夾下的文件生成uri,該文件夾的聲明是在xml中使用標籤完成的,下面的例子就是聲明私有文件目錄下images/下的文件可以臨時訪問(文件在res/xml/目錄下),下面時一個簡單的樣式:

<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <files-path name="my_images" path="images/"/>
</paths>

因爲的子標籤可以有多種,這裏對所有進行說明:
這裏寫圖片描述

子標籤中屬性說明:
這裏寫圖片描述

Android7.1.1的路徑:

files-path
Context.getFilesDir():

/data/user/0/包名/files

cache-path
Context.getCacheDir():

/data/user/0/包名/cache

external-path
Environment.getExternalStorageDirectory():

/storage/emulated/0

external-files-path
Context.getExternalCacheDir():

/storage/emulated/0/Android/data/包名/cache

Android4.4的路徑:

file-path
Context.getFilesDir():

/data/data/包名/files

cache-path
Context.getCacheDir():

 /data/data/包名/cache

external-path
Environment.getExternalStorageDirectory():

 /storage/sdcard

external-files-path
Context.getExternalCacheDir():

/storage/sdcard/Android/data/包名/cache

以上便是Android官方文檔上介紹的FileProvider所有支持的所以path類型,這些類型在Android手機內部存儲區文件共享是可以行的通的,但對於外置SD卡是不行的,如果你想通過FileProvider.getUriForFile()獲取一個外置SD卡的Uri則會報出如下異常:

這裏寫圖片描述

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <root-path name="my_images" path=""/>
</paths>

root-path代表/也就是Android設備的根目錄,該目錄下包含着手機內部存儲器,外置SD卡等所有文件的目錄。

然後我們允許程序,發現將path設置爲root-path解決了FileProvider無法使用外置SD卡的問題。

完成配置

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

說明:
name:爲固定值android.support.FILE_PROVIDER_PATHS
resource:所對應的xml文件路徑

使用
1、通過路徑生成要分享的文件File對象
2、使用FileProvider生成uri—FileProvider.getUriForFile()

authrity爲”com.example.servertest.fileprovider”的FileProvider,獲取到文件”image.jpg”文件,該文件位於”images”目錄下

File imagesPath = new File(getFilesDir(), "images");
File newFile = new File(imagesPath, "picture.jpg");
Uri contentUri = getUriForFile(getContext(), "com.mydomain.fileprovider", newFile);

沒被封裝的uri爲:

/data/user/0/com.example.cameraalbumtest/files/images/picture.jpg

封裝後的uri爲:

content://com.example.cameraalbumtest.fileprovider/my_images/picture.jpg

com.example.cameraalbumtest.fileprovider: 這個是provider的標識符

my_images: 就是file-path 它代表的路徑就是/data/user/0/com.example.cameraalbumtest/files/images

臨時權限的授予方式
1、使用Context.grantUriPermission(package,Uri,mode_flags)方法,使用想要的模式。這個方法通過mode_flags方法授予客戶端package的臨時權限,有兩個取值,FLAG_GRANT_URI_PERMISSION和FLAG_GRANT_WRITE_URI_PERMISSOIN。該方式允許後,可通過revokeUriPermission終止,或者手機重啓後
2、通過Intent

  1. 通過Intent的setData()方法將該uri放入Intent中
  2. 可以爲Intent設置flag,設置一個或兩個, FLAG_GRANT_URI_PERMISSION和FLAG_GRANT_WRITE_URI_PERMISSOIN
  3. 將Intent發送給其他app,大部分情況,通過setResult()來做這種方法獲取的權限,當接收的Activity在棧中一直活躍時都會保留,當activity棧finish時,權限會自動移除。被允許的activity所在的app的其他組件也會被允許該權限。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章