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

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

1:代码适配

 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

<?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中使用

<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

*** 返回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,然后就按上述方法在添加一个节点就可以了:

<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即可。

如下所示:

<?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 文件中添加的子目录里面。

举个例子:

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 版本之前,我们代码可能是这样:

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 文件(文件名自由定义),并添加子目录路径信息:

<?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 路径文件:

<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 对象,并授权访问:

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多节点问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 史上最全的Android build.gradle配置教程

    前言 Android Studio是采用gradle来构建项目的,gradle是基于groovy语言的,如果只是用它构建普通Android项目的话,是可以不去学groovy的.当我们创建一个Android项目时会包含两个Android build.gradle配置详解文件,如下图: 一.Project的build.gradle文件: 对应的build.gradle代码如下: // Top-level build file where you can add configuration optio

  • AndroidManifest.xml中含盖的安全问题详解

    0x00 关于AndroidManifest.xml AndroidManifest.xml 是每个android程序中必须的文件.它位于整个项目的根目录,Manifest文件提供有关应用程序到Android系统的基本信息,系统必须具有该信息才能运行任何应用程序的代码.换句话说APP是跑在Android系统上,既然要跑在其上,就必须提供信息给Android System,这些信息就存在AndroidManifest中.AndroidManifest.xml 存放在 app/src/main/ 目

  • Android Studio 中aidl的自定义类的使用详解

    自己折腾了好久,记录一下. service端: 1:创建类Dog,需要实现Parcelable接口: 2:aidl下创建 Dog.aidl,里面两句话就可以了 (1)package s包名; (2)parcelable Dog; 3:interface.aidl引入Dog类, import s包名.Dog; Client 端: 1:创建类Dog,需要实现Parcelable接口: 2:aidl下创建 Dog.aidl, (1)package c包名; (2)parcelable Dog; 注意:

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

    众所周知在android7.0,修改了对私有存储的限制,导致在获取资源的时候,不能通过Uri.fromFile来获取uri了我们需要适配7.0+的机型需要这样写: 1:代码适配 if (Build.VERSION.SDK_INT > 23) {// intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); Uri contentUri = FileProvider.getUriForFile(context, SysInfo.packageN

  • 史上最全Android build.gradle配置详解(小结)

    Android Studio是采用gradle来构建项目的,gradle是基于groovy语言的,如果只是用它构建普通Android项目的话,是可以不去学groovy的.当我们创建一个Android项目时会包含两个Android build.gradle配置详解文件,如下图: 一.Project的build.gradle文件: 对应的build.gradle代码如下: // Top-level build file where you can add configuration options

  • 基于Android RxCache使用方法详解

    前言 我为什么使用这个库? 事实上Android开发中缓存功能的实现选择有很多种,File缓存,SP缓存,或者数据库缓存,当然还有一些简单的库/工具类,比如github上的这个: [ASimpleCache]:a simple cache for android and java 但是都不是很好用(虽然可能学习成本比较低,因为它使用起来相对简单),我可能需要很多的静态常量来作为key存储缓存数据value,并设置缓存的有效期,这可能需要很多Java代码去实现,并且过程繁琐. 如果您使用的网络请求

  • Android studio 混淆配置详解

    混淆 studio 使用Proguard进行混淆,其是一个压缩.优化和混淆java字节码文件的一个工具. 功能:Shrinking(压缩).Optimization(优化).Obfuscattion(混淆).Preverification(预校验)四个操作. 优点: 1.删除项目无用的资源,有效减小apk大小: 2.删除无用的类.类成员.方法和属性,还可以删除无用的注释,最大限度的优化字节码文件: 3.使用简短无意义的名称重命名已存在的类.方法.属性等,增加逆向工程的难度. 配置 buildTy

  • VS2019属性配置详解

    如何在vs中添加参数? 属性->配置属性->调试->命令参数 参数之间为空格 如何配置第三方库的头文件? 属性->C/C++/常规->附加包含目录 使用管理员权限执行cmd 属性->链接器->清单文件->UAC执行级别 vs使用MFC时如何使用printf增加调试信息? 配置属性->生成事件->生成后事件->命令行 加入: editbin /SUBSYSTEM:CONSOLE "$(OUTDIR)\$(ProjectName).e

  • Spring中基于XML的AOP配置详解

    1. 准备工作 1.1 创建工程 day03_eesy_03SpringAOP 1.2 在配置文件pom.xml中添加依赖 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  • Android ImgView属性图文详解

    ImageView是用于界面上显示图片的控件. 属性 1.为ImageView设置图片 ①android:src="@drawable/img1": src设置图片,默认图片等比例放缩,以最适应的大小显示. ②android:background="@drawable/img1" background是组件通用属性,不仅可以设置组件的背景颜色,也可以用图片做背景. [提示] ①以图片做背景,那么图片将适应组件的大小. ②但如果控件是宽高为wrap_content,则

  • 基于Android ContentProvider的总结详解

    1.适用场景1) ContentProvider为存储和读取数据提供了统一的接口2) 使用ContentProvider,应用程序可以实现数据共享3) android内置的许多数据都是使用ContentProvider形式,供开发者调用的(如视频,音频,图片,通讯录等)2.相关概念介绍1)ContentProvider简介当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据.虽然使用其他方法也可以对外共享数据,但数据访问方式会因数据存储的

  • Android clipChildren属性实例详解

    前言 前几天有在微博上推荐过一个博客,看他文章时发现了这个属性.有些属性不常用,但需要的时候非常有用,于是做了个例子,正好项目用到,与大家分享一下.  正文 一.效果图 看到这个图时你可以先想想如果是你,你怎么实现这个效果.马上想到用RelativeLayout?NO,NO,NO,,,  二.实现代码 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="h

  • 基于AnDroid FrameLayout的使用详解

    今天在学习实现墨迹天气那样的拖动效果时,看到用的是重写FrameLayout.翻了翻书,突然想明白,为什么用FrameLayout.在FrameLayout中,用我看的书中的话说是,空间永远用不完. 复制代码 代码如下: <?xml version="1.0" encoding="utf-8"?><FrameLayout    xmlns:android="http://schemas.android.com/apk/res/androi

随机推荐