androidAndroid精选

FileProvider文档翻译

2017-06-26  本文已影响64人  Arnold_J

自己简单的翻译了一下整篇文档,然后和网络上对比了一下,感觉还是太菜,所以转了其他人的翻译,感觉更适合。稍微修改了一下个别错别字,英文留空有空再改。
参考:http://www.bendaidai.top/?p=100


FileProvider 是 ContentProvider ( 有助于 App 共享文件更加安全的组件 )的一个特殊的子类,通过 content:// Uri 获取一个文件而不是 file:/// Uri。 当你创建一个包含有 content URI 的 Intent 的时候,Content URI赋予你临时的读写权限。为了可以给一个目标app( 原文client app,这里应该是目标App )发送一个特定的content URI,你也可以通过调用Intent.setFlags() 去添加权限,这些权限一直有效,只要接收的 Activity 在栈中还存活着。要是跳转到Service,只要这个Service在运行,权限就有效。相比较而言,用file:/// Uri来获取文件,你不得不修改系统底层的文件权限.在你改变文件权限之前,你授予权限,对于任何app都是可用的,所以授予这个级别的权限从根本上是不安全的.(就是liunx的rwx) content URI提高了文件安全访问的级别,使FileProvider成为Android的安全体系重要组成部分。

FileProvider 可大致分为下面几个部分:

1.自定义一个FileProvider

因为FileProvider的默认功能已经包含了将一个文件生成Content URI,所以,你不需要再在你的代码里去定义一个子类.相应的,你完全可以在你App的XML中通过 元素去指定一个FileProvider,包括指定FileProvider的组件,给 android.support.v4.content.FileProvider设置 android:name属性,基于你的控制域给 android:authorities设置一个属性.例如,如果你控制mydomain.com域,你应该用com.mydomain.fileprovider授权.设置 android:exported属性为false; FileProvider不需要成为一个共有的类,设置android:grantUriPermissions这个属性为true,则允许你给文件临时授权.例子

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

如果你想要重写FileProvider中默认的方法,请继承FileProvider,并且要在 元素下的android:name写上全类名

2.指定可用文件

一个FileProvide仅仅只能为你生成一个预先在目录中指定的文件的content URI,在XML中,用的子元素去指定一个目录,并指定它的存储区域和路径.例如,下面这个paths元素告诉FileProvider,你打算去访问你的images/子目录下面私有文件的content URI

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

元素必须有一个或多个下面类似的子标签 它表示你的app的内部存储区根目录的文件,该子目录的根路径等同于Context.getFileDir

<cache-path name="name" path="path" />

它表示你的app的内部缓存区根目录的文件,该子目录的根路径等同于getCacheDir()

<external-path name="name" path="path" />

它表示你app的外部缓存区根目录的文件,该子目录的根路径等同于Environment.getExternalStorageDirectory().

<external-files-path name="name" path="path" />

它表示你的app的外部存储区根目录的文件,该子目录的根路径等同于Context.getExternalFilesDir(null).

<external-cache-path name="name" path="path" />

它表示你的app的外部缓存区根目录的文件,该子目录的根路径等同于Context.getExternalCacheDir().
这些子元素都有相同的属性

name="name"

一个URI路径段,为了确保安全,这个值隐藏了你将要分享的子目录的名字,这个子目录的名字被包含在path的属性值中.

path ="path"

你将要分享的子目录,虽然name属性是一个URI路径片段,但是path的值是一个真正的路径名字.注意这个值只能引用一个子目录,不能是一个或多个文件,你不能通过文件名单独的分享一个文件,也不能用通配符来指定某一类型的文件
你必须为你想要content URI文件的每个目录指定子元素.例如,这写xnl元素指定了两个目录

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

把<paths>元素和它的子元素放到你项目中的一个xml中,例如,你可以把它们添加到一个叫 res/xml/file_paths.xml 的文件中,为了让它和 FileProvider 联系起来,在定义好FileProvider的元素下添加一个 <meta-data> 做为 FileProvider
的子元素,并设置 "android:name" 属性为 android.support.FILE_PROVIDER_PATHS。设置 "android:resource" 属性为 @xml/file_paths (注意不要指定.xml扩展名).例如

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

3.给文件生成content URI

为了给另一个app通过content URI分享文件,因此,你的app不得不生成一个content URI.为了生成content URI,首先要给文件new File,然后传递File 到getUriForFile(),你可以通过 把getUriForFile()返回的content URI放在Intent中传递给另一个app,目标app收到这个content URI就能打开这个文件并且通过调用 ContentResolver.openFileDescriptor得到ParcelFileDescriptor进而读取它的内容.

例如,假设你的app正要通过拥有 com.mydomain.fileprovider权限的FileProvider给另一个app提供文件,你可以通过下面的代码去得到一个在images/ 子目录下的default_image.jpg的content URI:

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

由于先前片段截取的结果,getUriForFile()返回这样一个结果: content://com.mydomain.fileprovider/my_images/default_image.jpg

4.授予URI一个临时权限

想要授予从getUriForFile()获取content URI一个访问权限,可以通过下面任意一种方式:

5.给另一个App提供URI

有各种各样的方式去吧一个文件的content URI提供给目标app.一个通用的方式是通过调用startActivityResult()有目标app启动你的app,目标app给你的app发送一个Intent去启动你的一个Activity,对此,你的app可以及时的给目标app返回一个content URI或者提供一个界面供用户选择文件.在最后一种情况下,一旦用户选择了文件,你的app就能返回它的content URI.以上联众情况,你的app都可以通过setREsult()发送包含有content URI的Intent

你也可以把content URI放到ClipData对象中,然后把对象添加到Intent中发送给你的目标app.要做到这一点,调用Intent.setClipData().当你用这个方法的时候,你能添加多种ClipData对象给Intent,每一个都有自己的content URI,当你调用通过Intent调用Intent.setFlags()设置临时权限的时候,所有的content URI都将有相同的权限.

注:该Intent.setClipData()方法只适用于平台版本16(安卓4.1)及更高版本。如果你想保持与以前版本的兼容性,你应该在一个时间发送一个内容URI Intent。设置行动ACTION_SEND,并通过调用把URI数据 setData()。

上一篇下一篇

猜你喜欢

热点阅读