FileProvider文档翻译

自己简单的翻译了一下整篇文档,然后和网络上对比了一下,感觉还是太菜,所以转了其他人的翻译,感觉更适合。稍微修改了一下个别错别字,英文留空有空再改。
参考: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
  • 2.指定可用文件
  • 3.给文件生成content URI
  • 4.授予URI一个临时权限
  • 5.给另一个App提供URI

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一个访问权限,可以通过下面任意一种方式:

  • 1.把content:// Uri传入 Context.grantUriPermission(package, Uri, mode_flags) 方法中,用你想要的模式标签,这将授予content URI指定的包临时访问权限,你可以把mode_flags参数的值设置为 FLAG_GRANT_READ_URI_PERMISSION,FLAG_GRANT_WRITE_URI_PERMISSION ,或者都设置上.这个授权将在你调用revokeUriPermission()或者重启设置之前一直有效.
  • 2.通过Intent调用setData()把content URI放进去
  • 3.接下来,调用Intent.setFlags()设置为FLAG_GRANT_READ_URI_PERMISSION,FLAG_GRANT_WRITE_URI_PERMISSION,至少一个.
  • 4.最后,发送Intent到另一个app,大多数情况下,你可通过调用setResult()来实现它.
  • 5.在接受方Activity在栈中存活的情况下,被赋予Intent权限中仍然有效.当栈被销毁的时候,权限将自动被移除.权限将自动扩展到该app的其他组件,并授权给其中的一个Activity.

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()。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容