大家都知道android7.0相册由于权限问题 需要先查询是否获得系统权限 不然就会报错
这个也是这样的原因
报错代码
android.os.FileUriExposedException: file:///XXX exposed beyond app through ClipData.Item.getUri() at android.os.StrictMode.onFileUriExposed(StrictMode.java:1799) at android.net.Uri.checkFileUriExposed(Uri.java:2346) at android.content.ClipData.prepareToLeaveProcess(ClipData.java:832) at android.content.Intent.prepareToLeaveProcess(Intent.java:8909)
没有做适配就报错了 然后网上找了资料 处理下
Android不再允许在app中把file://Uri暴露给其他app,包括但不局限于通过Intent或ClipData 等方法。
原因在于使用file://Uri会有一些风险,比如:
- 文件是私有的,接收
file://Uri
的app无法访问该文件。 - 在Android6.0之后引入运行时权限,如果接收file://Uri的app没有申请
READ_EXTERNAL_STORAGE
权限,在读取文件时会引发崩溃。
因此,google提供了FileProvider
,使用它可以生成content://Uri
来替代file://Uri
。
之前我是直接
File apkFile = new File(file);
if (!apkFile.exists()) {
return;
}
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// intent.setDataAndType(Uri.parse("file://" + apkFile.toString()), "application/vnd.android.package-archive");
public void installAPK(String file) {
File apkFile = new File(file);
if (!apkFile.exists()) {
return;
}
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// intent.setDataAndType(Uri.parse("file://" + apkFile.toString()), "application/vnd.android.package-archive");
if (Build.VERSION.SDK_INT >= 24) {
Uri apkUri = FileProvider.getUriForFile(getApplicationContext(), "com.wy.toy.FileProvider", apkFile);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
} else {
intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
}
startActivity(intent);
}
在AndroidManifest.xml添加
<provider android:name="android.support.v4.content.FileProvider" android:authorities="com.wy.toy.FileProvider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/rc_file_path" /> </provider>
资源文件下加上
<?xml version="1.0" encoding="utf-8"?> <paths> <external-path name="files_root" path="/sdcard/updateAPK/" /> </paths>
android:authorities
是用来标识provider的唯一标识,在同一部手机上一个"authority"串只能被一个app使用,冲突的话会导致app无法安装。android:exported
必须设置成false
,后面异常会讲为什么android:grantUriPermissions
用来控制共享文件的访问权限,也可以在java代码中设置
res/xml/provider_paths.xml
这是指定路径和转换规则
<paths>中可以定义以下子节点
子节点 对应路径 例子
files-path Context.getFilesDir()
cache-path Context.getCacheDir()
external-path Environment.getExternalStorageDirectory() /storage/emulated/0/
external-files-path Context.getExternalFilesDir(null)
external-cache-path Context.getExternalCacheDir()
加入我要替换的目录是
/storage/emulated/0/sdcard/updateAPK/
那么配置应该写成
path="/sdcard/updateAPK/"
我碰见的异常
Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.PackageItemInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference
com.wy.toy.FileProvider 中的FP大小写错误就一直报错了
最后写一个有趣的事情 我在小米手机上 低版本的覆盖高版本的会报错说下载的文件损坏无法安装 然后借用同事的手机就会直接提示 无法降级 记录下 希望大家遇见相同的错误不要走这么多弯路了