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

两个小解释:

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;
  }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android 7.0行为变更 FileUriExposedException解决方法

    Android 7.0行为变更 FileUriExposedException解决方法 当我们开发关于[在应用间共享文件]相关功能的时候,在Android 7.0上经常会报出此运行时异常,那么Android 7.0以下没问题的代码,为什么跑到Android 7.0+的设备上运行就出问题了呢?,这主要来自于Android 7.0的一项[行为变更]! 对于面向 Android 7.0 的应用,Android 框架执行的 StrictMode API 政策禁止在您的应用外部公开 file:// URI

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

    两个小解释: FileProvider是ContentProvider特殊的子类,ContentProvider通过创建content:// Uri来替代file:/// Uri. 在Android 7.0的以上的系统中,尝试传递file://URI可能会触发FileUriExposedException FileProvider的这个概述包括以下主题: 1.定义FileProvider 2.指定可用文件 3.检索文件的Content URI 4.授予URI的临时权限 5.将内容URI提供给其他

  • Android7.0开发实现Launcher3去掉应用抽屉的方法详解

    本文实例讲述了Android7.0开发实现Launcher3去掉应用抽屉的方法.分享给大家供大家参考,具体如下: 年初做过一个项目,有一个需求就是需要将桌面变为单层不需要二级菜单.最近几次有小伙伴有这个问我这个解决办法.现在我将分享给大家. 先上效果图:   功能分解 1. 去除Allapp键,调整HotSeat布局 2. 将所有应用摆在launcher第一层 3. 去掉长按时删除选项 解决方案 一.设置总开关 按照6.0 Launcher3 的模式,添加一个开关,控制是否去掉抽屉. Launc

  • Python 读写文件和file对象的方法(推荐)

    1.open 使用open打开文件后一定要记得调用文件对象的close()方法.比如可以用try/finally语句来确保最后能关闭文件. file_object = open('thefile.txt') try:      all_the_text = file_object.read( ) finally:      file_object.close( ) 注:不能把open语句放在try块里,因为当打开文件出现异常时,文件对象file_object无法执行close()方法. 2.读文

  • 适配android7.0获取文件的Uri的方法

    前言# Android 7.0已经发布很久了,虽然市场份额还不是很高,但是流行起来都是早晚的事,所以适配Android 7.0刻不容缓. Android 7.0 对系统进行了很多的优化:例如文件访问权限,省电,网络,后台等等,其中最突出的就是应用外的Uri访问. 什么时候会用到Uri的应用外访问呢?举一个简单的例子,下载apk更新,这个时候会调用系统功能来安装这个apk,这就是应用外访问文件,需要传入文件的Uri. 但是这样可能会显得不太安全,万一是什么非常重要的文件就糟糕了,所以Android

  • Android圆形头像拍照后“无法加载此图片”的问题解决方法(适配Android7.0)

    Feature: 点击选择拍照或者打开相册,选取图片进行裁剪最后设置为圆形头像. Problem: 拍好照片,点击裁剪,弹Toast"无法加载此图片". Solution: 在裁剪的class里加两行代码 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 主要代码如下: public static final S

  • Android7.0自动更新适配 包解析异常

    在Android7.0的手机上,自动更新的时候出现包解析异常,在其他的手机上没有这个问题. 原因: Android7.0引入私有目录被限制访问和StrictMode API .私有目录被限制访问是指在Android7.0中为了提高应用的安全性,在7.0上应用私有目录将被限制访问.StrictMode API是指禁止向你的应用外公开 file:// URI. 如果一项包含文件 file:// URI类型 的 Intent 离开你的应用,则会报出异常. 解决办法: 第一步:在AndroidManif

  • Android7.0版本影响开发的改进分析

    本文总结分析了Android7.0版本影响开发的改进.分享给大家供大家参考,具体如下: 低电耗模式 会对闹铃.GPS 和 Wi-Fi 扫描 产生限制. 可参考Optimizing for Doze and App Standby 使用GCM来发送和接受消息 后台优化 Android N 删除了三项隐式广播,隐式广播会在后台频繁启动已注册侦听这些广播的应用. 删除这些广播可以显著提升设备性能和用户体验. 侦听网络变化的主线程广播改为: CONNECTIVITY_CHANGE. 对所有应用都无法 发

  • android7.0实现分享图片到朋友圈功能

    本文实例为大家分享了android实现分享图片到朋友圈功能的具体代码,供大家参考,具体内容如下 在Android7.0中,系统对scheme为file://的uri进行了限制,所以通过这种uri来进行分享的一些接口就不能用了,比如使用代码来调用分享朋友圈的接口. 此时就得使用其他的URI scheme来代替 file://,比如MediaStore的 content://.直接上代码: private static boolean checkInstallation(Context contex

  • 解决Android7.0更新后无法安装的问题

    最近在我们的应用中加入更新功能,按照往常一样加入代码 if (!apkfile.exists()) { Toast.makeText(mContext, "下载的安装包不存在", Toast.LENGTH_SHORT).show(); return; } Intent install = new Intent(Intent.ACTION_VIEW); install.setDataAndType(Uri.fromFile(apkfile), "application/vnd.

随机推荐