Android7.0行为变更之适配File Provider的方法

作者:TheShy_ 时间:2021-09-24 08:02:38 

两个小解释:

FileProvider是ContentProvider特殊的子类,ContentProvider通过创建content:// Uri来替代file:/// Uri。

在Android 7.0的以上的系统中,尝试传递file://URI可能会触发FileUriExposedException

FileProvider的这个概述包括以下主题:

1.定义FileProvider

2.指定可用文件

3.检索文件的Content URI

4.授予URI的临时权限

5.将内容URI提供给其他应用程序

第一步:定义FileProvider:


//清单文件中
<provider
   android:name="android.support.v4.content.FileProvider"//固定
   android:authorities="${applicationId}.yourname"//根据您控制的域将属性设置为URI权限
   android:exported="false"//FileProvider不需要公开
   android:grantUriPermissions="true">//允许您授予对文件的临时访问权限
   ...
</provider>

第二步:指定可用文件


//新建一个xml文件用于存放应用需要共享的目录文件
//以下paths元素告诉FileProvider您打算为images/私有文件区域的子目录请求内容URI
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
 <files-path name="my_images" path="images/"/>
 ...
</paths>

该元素必须包含一个或多个以下子元素:


//代表内部存储空间应用私有目录下的 files/ 目录,等同于 Context.getFilesDir() 所获取的目录路径;
<files-path name = “ name ” path = “ path ” />
//代表内部存储空间应用私有目录下的 cache/ 目录,等同于 Context.getCacheDir() 所获取的目录路径;
<cache-path name = “ name ” path = “ path ” />
//代表外部存储空间根目录,等同于 Environment.getExternalStorageDirectory() 所获取的目录路径;
<external-path name = “ name ” path = “ path ” />
//代表外部存储空间应用私有目录下的 files/ 目录,等同于 Context.getExternalFilesDir(null) 所获取的目录路径;
<external-files-path name = “ name ” path = “ path ” />
//代表外部存储空间应用私有目录下的 cache/ 目录,等同于 Context.getExternalCacheDir();
<external-cache-path name = “ name ” path = “ path ” />
//代表外部媒体区域根目录中的文件。等同于Context.getExternalMediaDirs()。
<external-media-path name = “ name ” path = “ path ” />

这些子元素都使用两个相同的属性:

name="name"
一个URI路径段。 用于给 path 属性所指定的子目录名称取一个别名 为了提高安全性,此值将隐藏您要共享的子目录的名称。该值的子目录名称包含在该 path属性中。
path="path"
你正在分享的子目录。虽然该name属性是一个URI路径段,但该path值是实际的子目录名称。请注意,该值是指一个子目录,而不是独立文件名。您无法通过文件名共享单个文件,也无法使用通配符指定文件的子集。

第三步:检索文件的 Content URI


//使用 FileProvider 类提供的公有静态方法 getUriForFile 生成 Content URI
//第一个参数:context上下文
//第二个参数: Manifest 文件中注册 FileProvider 时设置的 authorities 属性值
//第三个参数:要共享的文件,并且这个文件一定位于第二步我们在 path 文件中添加的子目录里面
Uri contentUri = FileProvider.getUriForFile(this,
  BuildConfig.APPLICATION_ID + ".myprovider", myFile);

第四步:授予URI的临时权限

授权方式有两种:

第一种方式:


//调用方法:
//参数1:授权访问 URI 对象的其他应用包名
//参数2:授权访问的 Uri 对象
//参数3:授权类型FLAG_GRANT_READ_URI_PERMISSION 或者 FLAG_GRANT_WRITE_URI_PERMISSION
   (或者二者同时授权。这种形式的授权方式,权限有效期截止至发生设备重启或者手动调用 revokeUriPermission() 方法撤销授权时)
grantUriPermission(package, Uri, mode_flags)

第二种方式:


//配合intent使用
//权限有效期截止至其它应用所处的堆栈销毁,并且一旦授权给某一个组件后,该应用的其它组件拥有相同的访问权限。
Intent.setFlags() 或者 Intent.addFlags()
Intent.setData(Uri uri);

第五步:将内容URI提供给其他应用程序


//通过以下方法启动其他应用并传递授权过的 Content URI 数据。当然,也有其他方式提供服务。
startActivity()

或者


startActivityResult()

或者


setResult()

官方原文(需要自备梯子,想自己搭的教程点击这里): Google Develpers - FileProvider

以下是一个我这边的例子:

场景:版本更新完成时打开新版本 apk 文件实现自动安装


//在 res/xml 目录下新建一个filepath文件 并指定子目录路径信息
<?xml version="1.0" encoding="utf-8"?>
<paths>
 <external-path name="external_path" path="."/>
 <cache-path name="cache_path" path="."/>
</paths>

//Manifest 文件中注册 FileProvider 对象,并链接上面的 path 路径文件
<provider
 android:name="android.support.v4.content.FileProvider"
 android:authorities="com.xxx.FileProvider"
 android:exported="false"
 android:grantUriPermissions="true">
 <meta-data
   android:name="android.support.FILE_PROVIDER_PATHS"
   android:resource="@xml/filepath"/>
</provider>

//授权 打开安装管理器安装apk包
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addCategory("android.intent.category.DEFAULT");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
Uri uri = UriUtil.getUriForFile(BitZApplication.mContext.get(), new File((String) msg.obj));
intent.setDataAndType(uri, "application/vnd.android.package-archive");
startActivity(intent);
//UriUtil工具类:
public static Uri getUriForFile(Context context, File file) {
   if (context == null || file == null) {
     throw new NullPointerException();
   }
   Uri uri;
   if (Build.VERSION.SDK_INT >= 24) {
     uri = FileProvider.getUriForFile(context, "com.xxx.FileProvider", file);
   } else {
     uri = Uri.fromFile(file);
   }
   return uri;
 }

来源:https://juejin.im/post/5ad1d4e96fb9a028d44503e6

标签:Android,行为变更
0
投稿

猜你喜欢

  • Java操作pdf的工具类itext的处理方法

    2023-07-14 11:51:53
  • C# wpf简单颜色板的实现

    2022-02-11 20:08:38
  • Java实现的不同图片居中剪裁生成同一尺寸缩略图功能示例

    2023-08-23 14:53:15
  • Android自定义View实现遥控器按钮

    2021-12-27 09:50:47
  • Spring MVC的web.xml配置详解

    2023-08-10 04:45:01
  • SpringCloud 客户端Ribbon负载均衡的实现方法

    2023-03-22 16:42:43
  • 详解WPF中用户控件和自定义控件的使用

    2023-07-25 12:20:26
  • C语言对CSV文件从最后往前一行一行读取的实现方法

    2023-06-24 08:05:57
  • 浅析Java中Split函数的用法技巧

    2023-02-19 09:13:27
  • Java常用排序算法及性能测试集合

    2022-01-15 22:29:09
  • spring boot使用logback实现多环境日志配置详解

    2022-10-03 20:38:24
  • Java数据结构与算法之稀疏数组与队列深入理解

    2022-05-31 06:33:11
  • C#使用DirectX.DirectSound播放语音

    2022-08-28 01:22:33
  • C# WinForm打开PDF文件并在窗体中显示

    2023-11-14 10:47:49
  • Android动态修改ToolBar的Menu菜单示例

    2021-10-29 15:36:07
  • .NET C#利用ZXing生成、识别二维码/条形码

    2022-03-25 12:20:45
  • 解决MyEclipse10.7部署报错抛空指针异常问题的方法

    2023-10-14 23:52:34
  • Android ListView用EditText实现搜索功能效果

    2021-05-29 09:05:25
  • 在SpringBoot中整合使用Netty框架的详细教程

    2023-03-26 23:59:53
  • Android Fragment滑动组件ViewPager的实例详解

    2022-06-10 05:23:10
  • asp之家 软件编程 m.aspxhome.com