Android 升级安装APK兼容Android7.0,解决FileUriExposedException
我们在开发app时避免不了需要添加应用内升级功能。当app启动时,如果检测到最新版本,将apk安装包从服务器下载下来,执行安装。
安装apk的代码一般写法如下,网上随处可以搜到
public static void installApk(Context context, File file) {
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri data = Uri.fromFile(file);
intent.setDataAndType(data, "application/vnd.android.package-archive");
context.startActivity(intent);
}
然而,当我们在Android7.0手机中执行时,会发现报如下错误日志
Caused by: android.os.FileUriExposedException: file:///storage/emulated/0/Android/data/net.csdn.blog.ruancoder/cache/test.apk exposed beyond app through Intent.getData()
at android.os.StrictMode.onFileUriExposed(StrictMode.java:)
at android.net.Uri.checkFileUriExposed(Uri.java:)
at android.content.Intent.prepareToLeaveProcess(Intent.java:)
at android.content.Intent.prepareToLeaveProcess(Intent.java:)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:)
at android.app.Activity.startActivityForResult(Activity.java:)
at android.support.v4.app.BaseFragmentActivityJB.startActivityForResult(BaseFragmentActivityJB.java:)
at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:)
at android.app.Activity.startActivityForResult(Activity.java:)
at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:)
at android.app.Activity.startActivity(Activity.java:)
at android.app.Activity.startActivity(Activity.java:)
我们来看一下FileUriExposedException官方文档
https://developer.android.google.cn/reference/android/os/FileUriExposedException.html
从Android 7.0开始,不再允许在app中把file:// Uri暴露给其他app,否则应用会抛出FileUriExposedException。原因在于,Google认为使用file:// Uri存在一定的风险。比如,文件是私有的,其他app无法访问该文件,或者其他app没有申请READ_EXTERNAL_STORAGE运行时权限。解决方案是,使用FileProvider生成content:// Uri来替代file:// Uri。
FileProvider官方文档:
https://developer.android.google.cn/reference/android/support/v4/content/FileProvider.html
下面我们使用FileProvider解决上述异常。
1.声明FileProvider
首先在清单文件中申明FileProvider。
<manifest>
...
<application>
...
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="net.csdn.blog.ruancoder.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
...
</application>
</manifest>
其中
android:name是固定写法。
android:authorities可自定义,是用来标识该provider的唯一标识,建议结合包名来保证authority的唯一性。
android:exported必须设置成 false,否则运行时会报错java.lang.SecurityException: Provider must not be exported 。
android:grantUriPermissions用来控制共享文件的访问权限。
<meta-data>节点中的android:resource指定了共享文件的路径。此处的file_paths即是该Provider对外提供文件的目录的配置文件,存放在res/xml/下。
2.添加file_paths.xml文件
文件格式如下
<paths>
<files-path name="name" path="path"/>
...
</paths>
其中根元素<paths>是固定的,内部元素可以是以下节点:
<files-path name="name" path="path" /> 对应getFilesDir()。
<cache-path name="name" path="path" /> 对应getCacheDir()。
<external-path name="name" path="path" /> 对应Environment.getExternalStorageDirectory()。
<external-files-path name="name" path="path" /> 对应getExternalFilesDir()。
<external-cache-path name="name" path="path" /> 对应getExternalCacheDir()。
此处,我们将下载的apk文件存放到sdcard中的Android/data/<package>/cache/download中,file_paths.xml文件如下。
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-cache-path name="cache_download" path="download"/>
</paths>
3.在Java代码中使用FileProvider
public static void installApk(Context context, File file) {
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri data;
// 判断版本大于等于7.0
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
// "net.csdn.blog.ruancoder.fileprovider"即是在清单文件中配置的authorities
data = FileProvider.getUriForFile(context, "net.csdn.blog.ruancoder.fileprovider", file);
// 给目标应用一个临时授权
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
} else {
data = Uri.fromFile(file);
}
intent.setDataAndType(data, "application/vnd.android.package-archive");
context.startActivity(intent);
}
Android 升级安装APK兼容Android7.0,解决FileUriExposedException的更多相关文章
- 升级安装APK兼容Android7.0,解决FileUriExposedException
见http://blog.csdn.net/ruancoder/article/details/67639621?utm_source=itdadao&utm_medium=referral
- 下载安装APK(兼容Android7.0)
我们使用手机的时候经常会看到应用程序提示升级,大部分应用内部都需要实现升级提醒和应用程序文件(APK文件)下载. 一般写法都差不多,比如在启动app的时候,通过api接口获得服务器最新的版本号,然后和 ...
- FileProvider N 7.0 升级 安装APK 选择文件 拍照 临时权限 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- 安装office2010提示要安装MSXML6.10.1129.0解决方法
系统win7 32位 安装office2010出现了错误,提示要安装MSXML6.10.1129.0解决方法 1.下载MSXML6.10.1129.0进行安装 2.若本机已安装过不管用: a.在运行里 ...
- Android N安装apk报错:android.os.FileUriExposedException
StackOverflow: http://stackoverflow.com/questions/38200282/android-os-fileuriexposedexception-file-s ...
- android intent安装apk
/** * 安装apk * * @param context * @param apkPath */ public static void installApk(Context context, St ...
- mysql 安装流程 兼容8.0.0以上版本 解决修改密码规则问题
背景介绍: 第一次安装mysql服务端,版本8.0.6 遇到了问题:1:不知道流程:2:8.0以上版本密码加密规则修改的解决方案: 1:下载mysql 服务端 https://dev.mysql. ...
- Android Studio安装apk失败
可能的情况 手机上已经安装了应用或者应用卸载不彻底 解决办法: adb uninstall yourpackagename 如果uninstall失败,可以考虑 clean一下Android Stud ...
- 关于部分Android手机安装apk,无法获取正常的logo
最近出现过类似的问题,主要出现是在,MediaPad X1 7.0和MediaPad M1 8.0. 发布应用的时候明明配置好了图标的,但是始终找不到原因,郁闷了好几个小时,也浪费了好几个小时. 如果 ...
随机推荐
- PatentTips – GPU Saving and Restoring Thread Group Operating State
BACKGROUND OF THE INVENTION The present invention relates generally to single-instruction, multiple- ...
- poj——1006 生理周期
生理周期 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 138291 Accepted: 44300 Descripti ...
- [转]《MEF程序设计指南》博文汇总
在MEF之前,人们已经提出了许多依赖注入框架来解决应用的扩展性问题,比如OSGI 实现以Spring 等等.在 Microsoft 的平台上,.NET Framework 自身内部包含组件模型和 Sy ...
- 去除ckeditor上传图片预览中的英文字母
去除ckeditor上传图片预览中的英文字母 CKEDITOR.replace('text', { filebrowserImageUploadUrl : 'upload_img.do', langu ...
- Java 注解入门实例 && 注解传參
參考 概念:java提供了一种原程序中的元素关联不论什么信息和不论什么元数据的途径和方法 JDK内置系统注解: @Override 用于修饰此方法覆盖了父类的方法; @Deprecated 用于修饰已 ...
- 使用深度双向LSTM模型构造社区问答系统
所看到的. 首先强调一下,这个结构也是一个解决对照两个句子类似性的通用RNN解决方式,不只能够使用在问答社区.凡是涉及到对照两个句子或者实体关系的场合全然能够套用这个模型来解决.这点希望读者注意. 首 ...
- [Vue-rx] Stream an API using RxJS into a Vue.js Template
You can map remote data directly into your Vue.js templates using RxJS. This lesson uses axios (and ...
- iOS: 学习笔记, Swift操作符定义
Swift操作符能够自行定义, 仅仅须要加上简单的标志符就可以. @infix 中置运算. 如+,-,*,/运算 @prefix 前置运算. 如- @postfix 后置运算. a++, a-- @a ...
- iOS 打开扬声器以及插入耳机的操作
废话不多说说一下现状 网上好多关于扬声器的操作,可是问题多多.SDK7.X 和SDK7.X以上版本号有点诧异 #import <Foundation/Foundation.h> #impo ...
- js上传文件
一.原始的XMLHttpRequestjs上传文件过程(參考地址:http://blog.sina.com.cn/s/blog_5d64f7e3010127ns.html) 用到两个对象 第一个对象: ...