前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于Android FileProvider 属性配置详解及FileProvider多节点问题

基于Android FileProvider 属性配置详解及FileProvider多节点问题

作者头像
砸漏
发布2020-10-16 11:28:39
2.7K0
发布2020-10-16 11:28:39
举报
文章被收录于专栏:恩蓝脚本

众所周知在android7.0,修改了对私有存储的限制,导致在获取资源的时候,不能通过Uri.fromFile来获取uri了我们需要适配7.0+的机型需要这样写:

1:代码适配

代码语言:javascript
复制
 if (Build.VERSION.SDK_INT   23) {//
        intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        Uri contentUri = FileProvider.getUriForFile(context, SysInfo.packageName + ".fileProvider", outputFile);
        intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
      } else {
        intent.setDataAndType(Uri.fromFile(outputFile), "application/vnd.android.package-archive");
      }

2:创建provider_paths.xml

代码语言:javascript
复制
<?xml version="1.0" encoding="utf-8"? 
<paths xmlns:android="http://schemas.android.com/apk/res/android" 
  <!-- /storage/emulated/0/Download/${applicationId}/.beta/apk-- 
  <external-path name="beta_external_path" path="Download/"/ 
  <!--/storage/emulated/0/Android/data/${applicationId}/files/apk/-- 
  <external-path name="beta_external_files_path" path="Android/data/"/ 
 
</paths 

其中 provider_path属性详解

name和path

name:uri路径片段。为了执行安全,这个值隐藏你所共享的子目录名。此值的子目录名包含在路径属性中。

path:你所共享的子目录。虽然name属性是一个URI路径片段,但是path是一个真实的子目录名。注意,path是一个子目录,而不是单个文件或者多个文件。

1.files-path

代表与Context.getFileDir()相同的文件路径

2.cache-path

<cache-path name=”name” path=”path” /

代表与getCacheDir()相同的文件路径

3.external-path

<external-path name=”name” path=”path” /

代表与Environment.getExternalStorageDirectory()相同的文件路径

4.external-files-path

<external-files-path name=”name” path=”path” /

代表与Context#getExternalFilesDir(String) 和Context.getExternalFilesDir(null)相同的文件路径

5.external-cache-path

<external-cache-path name=”name” path=”path” /

代表与Context.getExternalCacheDir()相同的文件路径

6:配置AndroidManifest.xml

android:authorities在FileProvider中使用

代码语言:javascript
复制
<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  

7:使用FileProvider

代码语言:javascript
复制
*** 返回URI:content://com.mydomain.fileprovider/my_images/default_image.jpg.

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

8.自定义FileProvider

class MyFileProvider extends FileProvider {}

AndroidMenifest.xml中配置 android:authorities即可

3:我们项目中可能会用到其他一些第三方sdk有用到拍照功能的话,他也为了适配android7.0也添加了这个节点,此时有些人可能就不知道如何下手了,其实很简单我们只要重写一个类 继承自FileProvider,然后就按上述方法在添加一个节点就可以了:

代码语言:javascript
复制
<provider
  android:name="com.blueZhang.MyFileProvider"
  android:authorities="${applicationId}.provider"
  android:grantUriPermissions="true"
  android:exported="false" 
  <meta-data
    android:name="android.support.FILE_PROVIDER_PATHS"
    android:resource="@xml/cust_file_paths" / 
</provider 

如果你不想自定义FileProvider,那么还有一种方法,那就是把第三方sdk中的路径配置copy到provider_paths.xml即可。

如下所示:

代码语言:javascript
复制
<?xml version="1.0" encoding="utf-8"? 
<paths xmlns:android="http://schemas.android.com/apk/res/android" 
  <!-- /storage/emulated/0/Download/${applicationId}/.beta/apk-- 
  <external-path name="beta_external_path" path="Download/"/ 
  <!--/storage/emulated/0/Android/data/${applicationId}/files/apk/-- 
  <external-path name="beta_external_files_path" path="Android/data/"/ 
 
  <external-path name="external_storage_root" path="."/ 
  <files-path name="files" path="."/ 
 
</paths 

注意⚠️:在使用provider时 配置路径 path=”.”代表所有路径

生成 Content URI

在 Android 7.0 出现之前,我们通常使用 Uri.fromFile() 方法生成一个 File URI。这里,我们需要使用 FileProvider 类提供的公有静态方法 getUriForFile 生成 Content URI。

比如:

Uri contentUri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + “.fileProvider”, myFile);

需要传递三个参数。第二个参数便是 Manifest 文件中注册 FileProvider 时设置的 authorities 属性值,第三个参数为要共享的文件,并且这个文件一定位于第二步我们在 path 文件中添加的子目录里面。

举个例子:

代码语言:javascript
复制
String filePath = Environment.getExternalStorageDirectory() + "/images/"+System.currentTimeMillis()+".jpg";
File outputFile = new File(filePath);
if (!outputFile.getParentFile().exists()) {
  outputFile.getParentFile().mkdir();
}
Uri contentUri = FileProvider.getUriForFile(this,
    BuildConfig.APPLICATION_ID + ".fileProvider", outputFile);

生成的 Content URI 是这样的:

content://com.yifeng.samples.myprovider/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 类提供的读写类型常量:

FLAG_GRANT_READ_URI_PERMISSION FLAG_GRANT_WRITE_URI_PERMISSION

或者二者同时授权。这种形式的授权方式,权限有效期截止至发生设备重启或者手动调用 revokeUriPermission() 方法撤销授权时。

第二种方式,配合 Intent 使用。通过 setData() 方法向 intent 对象添加 Content URI。然后使用 setFlags() 或者 addFlags() 方法设置读写权限,可选常量值同上。这种形式的授权方式,权限有效期截止至其它应用所处的堆栈销毁,并且一旦授权给某一个组件后,该应用的其它组件拥有相同的访问权限。

第五步,提供 Content URI 给其它应用

拥有授予权限的 Content URI 后,便可以通过 startActivity() 或者 setResult() 方法启动其他应用并传递授权过的 Content URI 数据。当然,也有其他方式提供服务。

如果你需要一次性传递多个 URI 对象,可以使用 intent 对象提供的 setClipData() 方法,并且 setFlags() 方法设置的权限适用于所有 Content URIs。

常见使用场景

前面介绍的内容都是理论部分,在 开发者官方 FileProvider 部分 都有所介绍。接下来我们看看,实际开发一款应用的过程中,会经常遇见哪些 FileProvider 的使用场景。

自动安装文件

版本更新完成时打开新版本 apk 文件实现自动安装的功能,应该是最常见的使用场景,也是每个应用必备功能之一。常见操作为,通知栏显示下载新版本完毕,用户点击或者监听下载过程自动打开新版本 apk 文件。适配 Android 7.0 版本之前,我们代码可能是这样:

代码语言:javascript
复制
File apkFile = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "app_sample.apk");
 
Intent installIntent = new Intent(Intent.ACTION_VIEW);
installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
installIntent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
startActivity(installIntent)

现在为了适配 7.0 及以上版本的系统,必须使用 Content URI 代替 File URI。

在 res/xml 目录下新建一个 file_provider_paths.xml 文件(文件名自由定义),并添加子目录路径信息:

代码语言:javascript
复制
<?xml version="1.0" encoding="utf-8"? 
<paths xmlns:android="http://schemas.android.com/apk/res/android" 
 
  <external-files-path name="my_download" path="Download"/ 
 
</paths 

然后在 Manifest 文件中注册 FileProvider 对象,并链接上面的 path 路径文件:

代码语言:javascript
复制
<provider
  android:name="android.support.v4.content.FileProvider"
  android:authorities="com.yifeng.samples.myprovider"
  android:exported="false"
  android:grantUriPermissions="true" 
 
  <meta-data
    android:name="android.support.FILE_PROVIDER_PATHS"
    android:resource="@xml/file_provider_paths"/ 
 
</provider 

修改 java 代码,根据 File 对象生成 Content URI 对象,并授权访问:

代码语言:javascript
复制
File apkFile = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "app_sample.apk");
Uri apkUri = FileProvider.getUriForFile(this,
    BuildConfig.APPLICATION_ID+".fileProvider", apkFile);
 
Intent installIntent = new Intent(Intent.ACTION_VIEW);
installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
installIntent.setDataAndType(apkUri, "application/vnd.android.package-archive");
startActivity(installIntent);

好了 有不明白的 及时联系

以上这篇基于Android FileProvider 属性配置详解及FileProvider多节点问题就是小编分享给大家的全部内容了,希望能给大家一个参考。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-09-11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档