还望支持个人博客站:http://www.enjoytoday.cn

概述

Android 7.0的新特性规定,对于android 7.0应用(仅仅对于android 7.0版本的sdk而言,若是编译版本低于25仍然不会受到影响),android框架使用StrictMode Api禁止我们的应用对外部(跨越应用分享)公开file://,若使用file://格式共享文件则会报FileUriExposedException异常,android 7.0应用间的文件共享需要使用content://类型的URI分享,并且需要为其提供临时的文件访问权限

(Intent.FLAG_GRANT_READ_URI_PERMISSION和Intent.FLAG_GRANT_WRITE_URI_PERMISSION),对此,官方给我们的建议是使用FileProvider类进行分享.目前,我已经在华为mate系列最新Android 7.0系统测试验证证实。下面主要看下FileProvider的使用方法,我会结合官网给的资料和FileProvider 25.0.1的源代码进行分析。

FileProvider

简介

获取是因为v4包的版本问题,导致我发现FileProvider原代码和android官网的介绍有些许差异或者说是接入的某些细节和我在使用的v4包所能作的工作不符合。我使用的v4包是23.0.1,下面我就以我这个版本的v4来介绍FileProvider的使用。

使用

注册

FileProvider是v4包中一个继承ContentProvider的子类,位置是android.support.v4.content,他可以通过File创建一个content://类型的Uri而不是file://类型的Uri.所以我们在使用的使用首先需要在清单文件中注册一个provider,如下所示:

 <manifest>
...
<application>
...
<provider
android:name="android.support.v4.content.FileProvider" //provider的类名
android:authorities="com.hfcai.fileprovider" //没有特定要求,自定义
android:exported="false" //不建议设置未true
android:grantUriPermissions="true"> //允许你有给其赋予临时访问权限的权力 <meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
...
</application>
</manifest>

这里是直接使用的v4包中的FileProvider,我们也可以直接继承FileProvider类,适当重写重载函数,但不建议如此做。下面来介绍上面的几个设置:

  • name:provider的类名,若使用默认的v4的FileProvider可使用”android.support.v4.content.FileProvider”,也可以设置为自定义的继承FileProvider的provider类;
  • authorities:一个签名认证,可以自定义,但在获取uri的时候需要保持一致;

    grantUriPermissions:使用FileProvider的使用需要我们给流出的URI赋予临时访问权限(READ和WRITE),该设置是允许我们行使该项权力;
  • meta-data:meta-data配置的是我们可以访问的文件的路径配置信息,需要使用xml文件进行配置,FileProvider会通过解析xml文件获取配置项,其中name名字不可改变为:android.support.FILE_PROVIDER_PATHS,resource为配置路径信息的配置项目。

路径配置

可访问的路径配置可以在res中建立一个xml文件下面建立一个配置文件,格式如下:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android"> <!-- "/" -->
<root-path name="test" path="test"/>
<!--Context.getFilesDir().-->
<files-path path="images" name="images"/>
<!-- getCacheDir().-->
<cache-path name="images1" path="images" />
<!-- Environment.getExternalStorageDirectory().-->
<external-path name="images2" path="images" />
<!--Context#getExternalFilesDir(String) Context.getExternalFilesDir(null). -->
<external-files-path name="images3" path="images" />
<!-- Context.getExternalCacheDir(). -->
<external-cache-path name="images4" path="images" />
</paths>

这里需要注意的是,如上的配置是25.0.1版本的配置信息,各个版本或许有点不同,具体的可选配置可以在原码中查看,关于配置文件的解析部分在FileProvider的parsePathStrategy方法里,相关的代码如下:

private static PathStrategy parsePathStrategy(Context context, String authority)
throws IOException, XmlPullParserException {
final SimplePathStrategy strat = new SimplePathStrategy(authority); final ProviderInfo info = context.getPackageManager()
.resolveContentProvider(authority, PackageManager.GET_META_DATA);
final XmlResourceParser in = info.loadXmlMetaData(
context.getPackageManager(), META_DATA_FILE_PROVIDER_PATHS);
if (in == null) {
throw new IllegalArgumentException(
"Missing " + META_DATA_FILE_PROVIDER_PATHS + " meta-data");
} int type;
while ((type = in.next()) != END_DOCUMENT) {
if (type == START_TAG) {
final String tag = in.getName(); final String name = in.getAttributeValue(null, ATTR_NAME);
String path = in.getAttributeValue(null, ATTR_PATH); File target = null;
if (TAG_ROOT_PATH.equals(tag)) {
target = DEVICE_ROOT;
} else if (TAG_FILES_PATH.equals(tag)) {
target = context.getFilesDir();
} else if (TAG_CACHE_PATH.equals(tag)) {
target = context.getCacheDir();
} else if (TAG_EXTERNAL.equals(tag)) {
target = Environment.getExternalStorageDirectory();
} else if (TAG_EXTERNAL_FILES.equals(tag)) {
File[] externalFilesDirs = ContextCompat.getExternalFilesDirs(context, null);
if (externalFilesDirs.length > 0) {
target = externalFilesDirs[0];
}
} else if (TAG_EXTERNAL_CACHE.equals(tag)) {
File[] externalCacheDirs = ContextCompat.getExternalCacheDirs(context);
if (externalCacheDirs.length > 0) {
target = externalCacheDirs[0];
}
} if (target != null) {
strat.addRoot(name, buildPath(target, path));
}
}
} return strat;
}

查看FileProvider不难发现,这里有几点坑需要注意一下:

  1. 配置可以添加多条路径信息,这是最容易看出来的;
  2. 每条路径信息中的name是必须的,不能未空,且不可重复(可以自定义),路径信息中的name,path解析后被一个HashMap作为Key和value保存,若name重复则会导致path数据被覆盖;
  3. path的设置必须是一个目录名,不可为一个文件名,可以选择添加或不添加file的分割符,因为FileProvider会自动帮我们补充。

使用方法

使用FileProvider与其他共享文件的方法的唯一区别就是生成URI的方式,将之前使用Uri.formFile(File file)或者直接加上”file://”通过Uri.parse(String str)转化的方式改为FileProvider.getUriForFile(Context context,String auth,File file)方法获取。当然还需要给该uri添加临时访问权限,代码如下:

File imagePath = new File(Context.getFilesDir(), "images");
File newFile = new File(imagePath, "test.png");
Uri contentUri = FileProvider.getUriForFile(getContext(), "com.hfcai.fileprovider", newFile);
Intent intent=new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(contentUri,"image/*");
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
startActivity(intent);

这样就可以通过系统的相册或其他可查看图片的应用打开我们所创建的图片文件了,下面给了一个FileProvider使用的Demo原码,可供参考,不喜勿喷。

FileProvider 示例:FileProviderDemo

FileProvider的使用的更多相关文章

  1. .NET Core的文件系统[2]:FileProvider是个什么东西?

    在<读取并监控文件的变化>中,我们通过三个简单的实例演示从编程的角度对文件系统做了初步的体验,接下来我们继续从设计的角度来继续认识它.这个抽象的文件系统以目录的形式来组织文件,我们可以利用 ...

  2. android- FileProvider崩溃 - NPE试图调用一个空字符串XmlResourceParser(FileProvider crash - npe attempting to invoke XmlResourceParser on a null String)

    问题: This is a part of my manifest: <?xml version="1.0" encoding="utf-8"?> ...

  3. FileProvider是个什么东西?

    FileProvider是个什么东西? 在<读取并监控文件的变化>中,我们通过三个简单的实例演示从编程的角度对文件系统做了初步的体验,接下来我们继续从设计的角度来继续认识它.这个抽象的文件 ...

  4. Android开发之FileProvider

    最近做项目时,都需要用到FileProvider.于是就研究了下,现总结如下: 官方路径:http://developer.android.com/intl/zh-cn/training/secure ...

  5. ASP.NET Core 源码学习之 Logging[4]:FileProvider

    前面几章介绍了 ASP.NET Core Logging 系统的配置和使用,而对于 Provider ,微软也提供了 Console, Debug, EventSource, TraceSource ...

  6. FileProvider解决FileUriExposedException

    FileUriExposedException 在给app做版本升级的时候,先从服务器下载新版本的apk文件到sdcard路径,然后调用安装apk的代码,一般写法如下: private void op ...

  7. 如何兼容所有Android版本选择照片或拍照然后裁剪图片--基于FileProvider和动态权限的实现

    我们知道, Android操作系统一直在进化. 虽然说系统是越来越安全, 可靠, 但是对于开发者而言, 开发难度是越来越大的, 需要注意的兼容性问题, 也越来越多. 就比如在Android平台上拍照或 ...

  8. Android 7.0 通过FileProvider共享文件

    一.概述 Android 7.0后,提供了很多新特性,其中最主要的是禁止了通过file://URI直接在文件操作共享文件(该操作会触发FileUriExposedException),而是通过cont ...

  9. FileProvider的使用及应用更新时提示:解析包出错、失败等问题

    Android 7.0以上的版本更新采用系统自带的DownloadManager更新 DOWNLOADPATH ="/download/" https://www.jianshu. ...

  10. android 7.0+ FileProvider 访问隐私文件 相册、相机、安装应用的适配

    从 Android 7.0 开始,Android SDK 中的 StrictMode 策略禁止开发人员在应用外部公开 file:// URI.具体表现为,当我们在应用中使用包含 file:// URI ...

随机推荐

  1. Selenium(十二):操作Cookie、调用JavaScript、HTML5的视频播放

    1. 操作Cookie 有时候我们想要验证浏览器中cookie是否正确,因为基于真实cookie的测试是无法通过白盒和集成测试的.WebDriver提供了操作Cookie的相关方法,可以读取.添加和删 ...

  2. python-schedule模块(定时任务)基于官方文档总结

    一.模块安装 pip3 install schedule 官方文档 二.常用的使用案例 #基本格式 #创建方法 def func(): print("方法") #创建定时 sche ...

  3. Java学习 1.2——简述JVM,JRE,JDK的关系

    在上一节中,我们了解了JVM相关的知识,有兴趣的话可以先去看一下: Java学习 1.1——(JVM介绍)Java为什么能够跨平台? 这个篇主要分享的是JRE,JDK,JVM三者的区别,简言之: JD ...

  4. Pycharm2019最新激活注册码(pycharm激活教程)

    给大家分享一下PyCharm2019最新可用的激活注册码.激活Pycharm专业版的方法有很多,这里主要给大家分享最有效的两种,一种是使用最新可用的注册激活码,一种是使用破解补丁的方法,这种方法虽然麻 ...

  5. JNDI学习总结(一)——JNDI数据源的配置

    原文地址:http://www.cnblogs.com/xdp-gacl/p/3951952.html 一.数据源的由来 在Java开发中,使用JDBC操作数据库的四个步骤如下:   ①加载数据库驱动 ...

  6. IDEA中GitLab的使用

    首先安装git https://git-scm.com/downloads/ 下载对应的版本 下载好了,安装打开 Windows. 打开之后2步走,与git连接 首先选择仓库,进行git init本地 ...

  7. Win10家庭版激活方法

    由于电脑换过主板,系统过了段时间显示未激活的状态,当时没注意随着主板口袋里的密匙,当作垃圾一起扔了,在网上试了几种方式,以下这个方法让我成功激活了系统 对开始菜单点击右键,选择Windows Powe ...

  8. Pymysql的常见使用方法

    cursor.fetchone()与cursor.fetchall()的区别: cursor.fetchone():只能显示一个数据 cursor.fetchall():才能显示查出来的所有数据  P ...

  9. Linux 和 Windows 查看当前运行的 python 进程及 GPU、CPU、磁盘利用率

    目录 查看当前 python 进程 Linux Windows 查看 GPU 利用率 Linux Windows Linux CPU 利用率 Linux 磁盘利用率 查看当前 python 进程 Li ...

  10. Least Common Multiple (HDU - 1019) 【简单数论】【LCM】【欧几里得辗转相除法】

    Least Common Multiple (HDU - 1019) [简单数论][LCM][欧几里得辗转相除法] 标签: 入门讲座题解 数论 题目描述 The least common multip ...