Storage Access Framework

纪成礼
2023-12-01

SAF是4.4(API 19)开始使用的数据访问机制。包含以下几个部分:
1. Document Provider:是DocumentsProvider的字类,用来让存储设备显示内容,Android自带Downloads,Images,Videos等这几种。
2. 客户端app:使用ACTION_OPEN_DOCUMENT和ACTION_CREATE_DOCUMENT的intent以及获取返回内容
3. picker:选择文件的界面。

每个document provider包含一个或多个roots,一个root拥有一个独特的COLUMN_ROOT_ID,指向了单个文件或者目录,而这个文件可以指向n个文件,而每个文件又可以指向n个文件。

分享文件

设置分享

V4包中的FileProvider这个类可以为文件生成对应的content URI。
1. 定义FileProvider
使用FileProvider首先需要在Manifest文件中定义,其中需要指明生成content URI的权限名称,以及一个指定了可分享目录的xml文件。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp">
    <application
        ...>
        <provider
            android:name="android.support.v4.content.FileProvider"
            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>

其中android:authorities属性需要指定为包名+.fileprovider,meta-data标签中resource的值@xml/filepaths是指res/xml/filepath.xml文件。该文件包含了可分享目录的路径。

res/xml/filepath.xml的格式如下:

<paths>
    <files-path path="images/" name="myimages" />
</paths>

其中<files-path/>标签用来指定分享的根目录是app内部存储的files/目录,path属性指定所要分享的具体目录,示例中为images目录。name属性指定了所生成URI的自定义路径名。
<paths>标签可以有多个子标签,标签种类可以包括内部存储<files-path>和外部存储<external-path>以及内部缓存<cache-path>

如果分享了images/目录下的default_image.jpg文件,则会生成对应的URI为
content://com.example.myapp.fileprovider/myimages/default_image.jpg

  1. 分享文件
    要创建一个Activity来接收ACTION_PICK的intent。界面省略。
<activity
    android:name=".FileSelectActivity"
    android:label="@File Selector" >
    <intent-filter>
        <action
            android:name="android.intent.action.PICK"/>
        <category
            android:name="android.intent.category.DEFAULT"/>
        <category
            android:name="android.intent.category.OPENABLE"/>
        <data android:mimeType="text/plain"/>
        <data android:mimeType="image/*"/>
    </intent-filter>
</activity>

确认了要分享的文件后,最好不要使用Uri.fromFile()来生成file://类型的URI,因为这个方法一是要求分享方在4.4及以下时需要有WRITE_EXTERNAL_STORAGE权限。二是要求请求方需要有READ_EXTERNAL_STORAGE权限,一些app可能会没有,比如说Gmail。最好通过FileProvider.getUriForFile()来生成可授予权限的URI并授予权限

File requestFile = new File(mImageFilename[position]);
// Use the FileProvider to get a content URI
try {
    fileUri = FileProvider.getUriForFile(
            MainActivity.this,
            "com.example.myapp.fileprovider",
            requestFile);
    if (fileUri != null) {
        // Grant temporary read permission to the content URI
        mResultIntent.addFlags(
            Intent.FLAG_GRANT_READ_URI_PERMISSION);

        // Put the Uri and MIME type in the result Intent
        mResultIntent.setDataAndType(                        
            fileUri,                           
            getContentResolver().getType(fileUri));
        // Set the result                  
        MainActivity.this.setResult(Activity.RESULT_OK,                           
        mResultIntent);
    } else {
        mResultIntent.setDataAndType(null, "");
        MainActivity.this.setResult(RESULT_CANCELED,
                                mResultIntent);
    }
} catch (IllegalArgumentException e) {
    Log.e("File Selector",
          "The selected file can't be shared: " +
          clickedFilename);
}

 类似资料:

相关阅读

相关文章

相关问答