使用FileProvider

   2016-11-10 0
核心提示:像这样的代码:privatevoidinstall(File apkFile){ Uri uri = Uri.fromFile(apkFile); Intent intent = newIntent(Intent.ACTION_VIEW); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setDataAndType(uri, "application/vnd.android.package-arch

像这样的代码:

privatevoidinstall(File apkFile){
 Uri uri = Uri.fromFile(apkFile);
 Intent intent = newIntent(Intent.ACTION_VIEW);
 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 intent.setDataAndType(uri, "application/vnd.android.package-archive");
 startActivity(intent);
}

在Android7.0+会报错:

android.os.FileUriExposedException: file:///storage/emulated/0/xxx/yyy/zzzz.apk exposed beyond app through Intent.getData()

关键点

一开始不好理解FileProvider的场景,所以有必要强调2个关键点:

  1. File:文件
  2. Uri:不排除应用内Uri使用,但是这里强调的是应用间的Uri传递。

所以,应用间的文件交互需要使用FileProvider,常见的场景:

  1. 调用系统相册裁剪照片
  2. 调用系统安装应用
  3. 应用之间共享文件
  4. … …

使用步骤

下面以安装APK为例,逐步适配FileProvider。

第一步,在AndroidManifest.xml中定义provider。

和ContentProvider的使用很类似:

<manifestxmlns:android="http://schemas.android.com/apk/res/android"
package="com.jayfeng.lesscode.update">

<application>
<provider
android:authorities="@string/less_provider_file_authorities"
android:name="android.support.v4.content.FileProvider"
android:grantUriPermissions="true"
android:exported="false">
<meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"/>
</provider>
</application>

</manifest>

注意几个地方:

  1. authorities必须唯一,避免多个应用冲突而不能安装
  2. exported必须为false,否则会报错FileProvider exported must not be true

第二步,制定路径file_paths。

这个文件名是随便写的,可以取任意名。

<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-pathpath="."name="external_storage_root"/>
</paths>

位置在res/xml目录下。

第三步,调用FileProvider生成Uri。

原来的Uri.fromFile(apkFile)要改成FileProvider.getUriForFile( ,

, apkFile),代码如下:

Uri uri = FileProvider.getUriForFile(this, getString(R.string.less_provider_file_authorities), apkFile);
Intent intent = newIntent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(uri, "application/vnd.android.package-archive");
startActivity(intent);

注意,务必要记得设置这个Flag值:FLAG_GRANT_READ_URI_PERMISSION。

然后就不会在Android7.0+上安装APK崩溃了。

兼容

但是,在Android7.0以下就有问题了,所以有必要区分一下版本号,代码如下:

privatevoidinstall(File apkFile){
 Intent intent = newIntent(Intent.ACTION_VIEW);
 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 Uri uri;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
 uri = FileProvider.getUriForFile(this, getString(R.string.less_provider_file_authorities), apkFile);
 intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
 } else{
 uri = Uri.fromFile(apkFile);
 }
 intent.setDataAndType(uri, "application/vnd.android.package-archive");
 startActivity(intent);
}

小结

为了简化这些配置,我在LessCode-Update中已经实现了上述配置,唯一要做的就是自定义authorities:

可以在string中配置:

<stringname="less_provider_file_authorities"><xxxxxxpackageNamexxxxxx>.fileprovider</string>

或者在build.gradle中动态配置:

android {
 defaultConfig {
 resValue "string","less_provider_file_authorities","<xxxxx packageName xxxx>.fileprovider"
 }
}

authorities可以是任意唯一值,最好是用包名开始,不容易重复。

代码参考: https://github.com/openproject/LessCode-Update

 
标签: XML 安卓开发
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • View绘制详解
    View绘制详解
    在介绍View绘制之前先来介绍一下LayoutInflater,而介绍LayoutInflater之前,先介绍一种单例实现模式:使用容器实现单例模式public class SingletonManager {   private static MapString, Object objMap = new HashMapString,Object();  private Singlet
  • Android 中处理 XML 的四种方式-XPath
    适用场景:只取 XML中的部分节点值非常方便,我很喜欢 XPath,关于 XPath语法请参考SelectNodes 与 XPath,这是 C#中的,但是 XPath语法是通用的。import org.xml.sax.InputSource;import java.io.ByteArrayInputStream;import java.io.IOException;import ja
  • Android 中处理 XML 的四种方式-PULL
    PULL和 SAX很相像,都是在节点中走,然后遇到开始节点了、结束节点会触发事件,此时就可以获取值。import org.xmlpull.v1.XmlPullParser;import org.xmlpull.v1.XmlPullParserException;import java.io.ByteArrayInputStream;import java.io.IOException;impo
  • Android 中处理 XML 的四种方式-SAX
    SAX(Simple API for XML)解析速度快,占用内存少。适用为 SAX的场景:映射为对象很方便。流程SAX通过一个 Handler将 XML“映射”到一个对象。XML - Handler - ObjectXML示例?xml version=1.0?rootsiteName千一网络/siteNamesiteUrlhttp://www.cftea.com//si
  • Android 中处理 XML 的四种方式-DOM
    Android 中处理 XML 的几种方式连载中,我们就不介绍合成 XML了,因为合成 XML可以直接拼接字符串,虽然看起很不高大上,但却很有效。我们主要介绍如何取 XML中的值。适用 DOM的场景:只取 XML中的部分节点值方便,但还不如 XPath方便。DOM解析小 XML很快,大
  • 炫酷:一句代码实现标题栏、导航栏滑动隐藏。ByeBurger库的使用和实现
    炫酷:一句代码实现标题栏、导航栏滑动隐藏。By
    其实上周五的时候已经发过一篇文章。基本实现了底部导航栏隐藏的效果。但是使用起来可能不是很实用。因为之前我实现的方式是继承了系统的导航栏,并且提供了响应的隐藏显示方法。这样就变相等于强制使用这个view,体验不是很好。所以抽时间把他优化了一下。因
  • LayoutInflater踩坑日记
    Android开发中ayoutInflater还是比较常见的,例如在Adapter或是Fragment中加载Layout布局,拿Adapter来说,在onCreateViewHolder中加载布局然后传给自定义的ViewHolder,通常我们都是这么用的:@Override public CustomViewHolder onCreateViewHolder(ViewGro
  • Android - 自定义View冷知识之动态替换layout.x
    在开发迭代中,有这么一个场景:我们给TextView定制了不少功能,在下一个版本,需要把程序中的所有TextView都替换成我自己的CustomTextView,这个时候你会怎么做?有没有一种方法在不改动布局文件的情况下就能实现动态替换呢?原理:layout.xml - Java 对象首
    10-10 安卓开发
  • Gank中的MVP模式
    Gank中的MVP模式
    第一次看到 Gank,还是源于 drakeet 的 Meizhi 项目,后来各种干货项目层出不穷,自己的项目中也借鉴了其中不少的写法,恰好最近公司决定让我做点前端了,同时项目经理也和我一样偏爱 Material Design,在说服了老板后,我就开始边学边用 Materialize 框架重
    10-01 MVC模式XML
  • Android学习笔记---重新学习自定义View#01
    Android学习笔记---重新学习自定义View#01
    最近发现自己对Android的学习只在表面,并没有深入的理解,我不喜欢这种感觉,而且没有自己的理解,学习到的内容也很难为我所用.所以从本次开始,我要写点自己理解的东西,但要对知识有自己的理解,那就必须深入了解它的原理.而我觉得Android的自定义View是一个很好
点击排行