AndroidFileProvider属性配置详解及FileProvider多节点问题众所周知在android7.0,修改了对私有存储的限制,导致在获取资源的时候,不能通过Uri.fromFile来获取uri了我们需要适配7.0+的机型需要这样写:
1:代码适配
1 if (Build.VERSION.SDK_INT > 23) {//
2 intent.tFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
3 Uri contentUri = UriForFile(context, SysInfo.packageName + ".fileProvider", outputFile);名人成长故事
4 intent.tDataAndType(contentUri, "application/vnd.android.package-archive");
5 } el {
6 intent.tDataAndType(Uri.fromFile(outputFile), "application/vnd.android.package-archive");
7 }
2:创建l
1<?xml version="1.0" encoding="utf-8"?>
2<paths xmlns:android="/apk/res/android">
3 <!-- /storage/emulated/0/Download/${applicationId}/.beta/apk-->
4 <external-path name="beta_external_path" path="Download/"/>
5 <!--/storage/emulated/0/Android/data/${applicationId}/files/apk/-->
6 <external-path name="beta_external_files_path" path="Android/data/"/>
7
8</paths>
其中 provider_path属性详解
name和path
name:uri路径⽚段。为了执⾏安全,这个值隐藏你所共享的⼦⽬录名。此值的⼦⽬录名包含在路径属性中。
path:你所共享的⼦⽬录。虽然name属性是⼀个URI路径⽚段,但是path是⼀个真实的⼦⽬录名。注意,path是⼀个⼦⽬录,⽽不是单个⽂件或者多个⽂件。
介绍一种食物1.files-path
[html]
1. 代表与FileDir()相同的⽂件路径
2.cache-path
[html]
1. <cache-path name="name"path="path"/>
代表与getCacheDir()相同的⽂件路径
[html]
1. <external-path name="name"path="path"/>
代表与ExternalStorageDirectory()相同的⽂件路径
[html]
1. <external-files-path name="name"path="path"/>
代表与Context#getExternalFilesDir(String) 和ExternalFilesDir(null)相同的⽂件路径5.external-cache-path
[html]
1. <external-cache-path name="name"path="path"/>
代表与ExternalCacheDir()相同的⽂件路径
6:配置l
android:authorities在FileProvider中使⽤
村委会述职报告
[html]
1. <provider
2. android:name="android.t.FileProvider"
3. android:authorities="domain.fileprovider"
4. android:exported="fal"
5. android:grantUriPermissions="true">
6. <meta-data
7. android:name="android.support.FILE_PROVIDER_PATHS"
8. android:resource="@xml/file_paths"/>
9. </provider>
7:使⽤FileProvider
*** 返回URI:content://domain.fileprovider/my_images/default_image.jpg.
[java]
1. File imagePath = new FilesDir(), "images");
2. File newFile = new File(imagePath, "default_image.jpg");
3. Uri contentUri = getUriForFile(getContext(), "domain.fileprovider", newFile);
8.⾃定义FileProvider
[java]
1. class MyFileProvider extends FileProvider {}
2. l中配置android:authorities即可
3:我们项⽬中可能会⽤到其他⼀些第三⽅sdk有⽤到拍照功能的话,他也为了适配android7.0也添加
了这个节点,此时有些⼈可能就不知道如何下⼿了,其实很简单我们只要重写⼀个类 继承⾃FileProvider,然后就按上述⽅法在添加⼀个节点就可以了:
1<provider
2 android:name="com.blueZhang.MyFileProvider"
3 android:authorities="${applicationId}.provider"
4 android:grantUriPermissions="true"
5 android:exported="fal">
6 <meta-data
7 android:name="android.support.FILE_PROVIDER_PATHS"
8 android:resource="@xml/cust_file_paths" />
9</provider>
膝盖痛吃什么
如果你不想⾃定义FileProvider,那么还有⼀种⽅法,那就是把第三⽅sdk中的路径配置copy到l即可。
如下所⽰:
1<?xml version="1.0" encoding="utf-8"?>
说儒
2<paths xmlns:android="/apk/res/android">
3 <!-- /storage/emulated/0/Download/${applicationId}/.beta/apk-->
4 <external-path name="beta_external_path" path="Download/"/>
5 <!--/storage/emulated/0/Android/data/${applicationId}/files/apk/-->
bdg是什么意思6 <external-path name="beta_external_files_path" path="Android/data/"/>
7
8 <external-path name="external_storage_root" path="."/>
9 <files-path name="files" path="."/>
10
11</paths>
注意⚠ :在使⽤provider时 配置路径 path="."代表所有路径
⽣成 Content URI
在 Android 7.0 出现之前,我们通常使⽤ Uri.fromFile() ⽅法⽣成⼀个 File URI。这⾥,我们需要使⽤ FileProvider 类提供的公有静态⽅
法 getUriForFile ⽣成 Content URI。⽐如:
1Uri contentUri = UriForFile(this,
2 BuildConfig.APPLICATION_ID + ".fileProvider", myFile);
1
2
需要传递三个参数。第⼆个参数便是 Manifest ⽂件中注册 FileProvider 时设置的 authorities 属性值,第三个参数为要共享的⽂件,并且这个⽂件⼀定位于第⼆步我们在 path ⽂件中添加的⼦⽬录⾥⾯。
举个例⼦:
1String filePath = ExternalStorageDirectory() + "/images/"+System.currentTimeMillis()+".jpg";
2File outputFile = new File(filePath);
3if (!ParentFile().exists()) {
4 ParentFile().mkdir();
5}
6Uri contentUri = UriForFile(this,
7 BuildConfig.APPLICATION_ID + ".fileProvider", outputFile);
⽣成的 Content URI 是这样的:
content://com.provider/my_images/1493715330339.jpg
其中,构成 URI 的 host 部分为 <provider> 元素的 authorities 属性值(applicationId + customname),path ⽚段 my_images 为res/xml ⽂件中指定的⼦⽬录别名(真实⽬录名为:images)。
第四步,授予 Content URI 访问权限
⽣成 Content URI 对象后,需要对其授权访问权限。授权⽅式有两种:
第⼀种⽅式,使⽤ Context 提供的 grantUriPermission(package, Uri, mode_flags) ⽅法向其他应⽤授权访问 URI 对象。三个参数分别表⽰授权访问 URI 对象的其他应⽤包名,授权访问的 Uri 对象,和授权类型。其中,授权类型为 Intent 类提供的读写类型常量:
或者⼆者同时授权。这种形式的授权⽅式,权限有效期截⽌⾄发⽣设备重启或者⼿动调⽤ revokeUriPermission() ⽅法撤销授权时。
第⼆种⽅式,配合 Intent 使⽤。通过 tData() ⽅法向 intent 对象添加 Content URI。然后使⽤ tFlags() 或者 addFlags() ⽅法设置读写权限,可选常量值同上。这种形式的授权⽅式,权限有效期截⽌⾄其它应⽤所处的堆栈销毁,并且⼀旦授权给某⼀个组件后,该应⽤的其它组件拥有相同的访问权限。
第五步,提供 Content URI 给其它应⽤
拥有授予权限的 Content URI 后,便可以通过 startActivity() 或者 tResult() ⽅法启动其他应⽤并传递授权过的 Content URI 数据。当然,也有其他⽅式提供服务。
如果你需要⼀次性传递多个 URI 对象,可以使⽤ intent 对象提供的 tClipData() ⽅法,并且 tFlags() ⽅法设置的权限适⽤于所有Content URIs。
常见使⽤场景
前⾯介绍的内容都是理论部分,在 都有所介绍。接下来我们看看,实际开发⼀款应⽤的过程中,会经常遇见哪些 FileProvider 的使⽤场景。
⾃动安装⽂件
版本更新完成时打开新版本 apk ⽂件实现⾃动安装的功能,应该是最常见的使⽤场景,也是每个应⽤必备功能之⼀。常见操作为,通知栏显⽰下载新版本完毕,⽤户点击或者监听下载过程⾃动打开新版本 apk ⽂件。适配 Android 7.0 版本之前,我们代码可能是这样:
1File apkFile = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "app_sample.apk");
2
3Intent installIntent = new Intent(Intent.ACTION_VIEW);
4installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
5installIntent.tDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
6startActivity(installIntent)
keep过去分词现在为了适配 7.0 及以上版本的系统,必须使⽤ Content URI 代替 File URI。
在 res/xml ⽬录下新建⼀个 file_l ⽂件(⽂件名⾃由定义),并添加⼦⽬录路径信息:
1<?xml version="1.0" encoding="utf-8"?>
2<paths xmlns:android="/apk/res/android">
3
4 <external-files-path name="my_download" path="Download"/>
5
6</paths>
然后在 Manifest ⽂件中注册 FileProvider 对象,并链接上⾯的 path 路径⽂件:
1<provider
2 android:name="android.t.FileProvider"
3 android:authorities="com.provider"
4 android:exported="fal"
5 android:grantUriPermissions="true">
6
7 <meta-data
8 android:name="android.support.FILE_PROVIDER_PATHS"
9 android:resource="@xml/file_provider_paths"/>
10
11</provider>
修改 java 代码,根据 File 对象⽣成 Content URI 对象,并授权访问:
1File apkFile = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "app_sample.apk");
2Uri apkUri = UriForFile(this,
3 BuildConfig.APPLICATION_ID+".fileProvider", apkFile);
4
5Intent installIntent = new Intent(Intent.ACTION_VIEW);
6installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
7installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
8installIntent.tDataAndType(apkUri, "application/vnd.android.package-archive");
陶笛演奏
9startActivity(installIntent);
好了 有不明⽩的 及时联系