banner
jzman

jzman

Coding、思考、自觉。
github

Android 7.0 應用之間共享文件

開發中經常需要將某個文件向另一個應用程序傳遞,如圖片上傳到另一個應用程序、文件在不同存儲路徑之間的複製粘貼等都需要共享文件,可以這樣理解接收文件的應用是在向提供文件的應用發送請求。

從 Android 7.0 開始,Android 執行 StrictMode 策略,禁止在應用外部公開 file://URL,如果在 Android 7.0 以上的應用不使用 FileProvider,則會拋出 FileUriExposedException 異常,Android 7.0 以後要在應用之間共享文件要使用 content://URL 授予 URL 臨時訪問權限,即要使用 FileProvider 的方式來授予臨時訪問權限,具有臨時訪問權限的 URL 是安全的,這種臨時的 URL 會自動過期,其中 FileProvider 提供的 getUriForFile () 用於生成文件的內容。

在所有情況下,從您的應用程序向另一個應用程序提供文件的唯一安全方法是向接收應用程序發送文件的內容 URI,並授予該 URI 的臨時訪問權限。具有臨時 URI 訪問權限的內容 URI 是安全的,因為它們僅適用於接收 URI 的應用程序,並且它們會自動過期。 Android FileProvider 組件提供 getUriForFile()方法,用於生成文件的內容 URI。

這裡也會提到一個在 Android 7.0 及更高版本時經常出現的異常:FileUriExposedException,通過使用 FileProvider 就可以解決該異常,當然這也是 Android 系統在安全性上不斷完善的結果。

  1. 指定 FileProvider
  2. 指定文件共享路徑

指定 FileProvider#

在 AndroidManifest 文件中指定 Provider,參考如下:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp">
    <application
        ...>
        
        <!--android:authorities="${applicationId}.yourname"-->
        <provider
            android:name="android.support.v4.content.FileProvider"
            <!--authorities屬性指定要用於FileProvider生成的內容URI的URI權限,一般是applicationId.yourname"組成-->
            android:authorities="com.example.myapp.fileprovider"
            android:grantUriPermissions="true"
            android:exported="false">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/filepaths" />
        </provider>
        ...
    </application>
</manifest>

指定文件共享路徑#

上面代碼中在 meta-data 目錄中指定了要共享的文件目錄,文件目錄在 filepathd.xml 中定義,可在相應的 xml 中定義的路徑有以下幾種,具體參考如下:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
    <paths>

        <!--表示設備的根目錄(new File("/"))-->
        <root-path name="root" path="" />
        <!--表示context.getFileDir()-->
        <files-path name="files" path="" />
        <!--表示context.getCacheDir()-->
        <cache-path name="cache" path="" />
        <!--表示Environment.getExternalStorageDirectory()-->
        <external-path name="external" path="" />
        <!--表示context.getExternalFilesDirs()-->
        <external-files-path name="name" path="path" />
        <!--表示getExternalCacheDirs()-->
        <external-cache-path name="name" path="path" />

    </paths>
</resources>

在 xml 中表示某個路徑需要兩個屬性,path 表示當前指定目錄的子目錄,如果不指定則表示的是當前指定目錄下的根目錄及子目錄,name 表示會將 name 添加的 URL 後面作為該文件的訪問路徑,參考如下:

//表示現在要共享的文件會在 context.getFileDir() 目錄下的 images 子目錄下查找要共享的文件
<paths>
    <files-path path="images/" name="myImage" />
</paths>

//表示最終生成的共享的文件URL
content://com.example.myapp.fileprovider/myImage/image.jpg

獲取 Uri#

最後,配置完成之後,在所有需要使用文件相關的,在獲取 Url 時應該按照如下方式獲取,具體如下:

public Uri getUri(File file) {
    Uri uri = null;
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        uri = FileProvider.getUriForFile(mContext, mContext.getPackageName() + ".youName", file);
    } else {
        uri = Uri.fromFile(file);
    }
    return uri;
}

這樣就可以在 Android 7.0 以上愉快的共享文件了。

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。