Android——android.os.FileUriExposedException: xxx.apk exposed beyond app through Intent.getData()解决办法
【问题】:Android APP实现升级apk安装时,会出现这样的错误:android.os.FileUriExposedException: xxx.apk exposed beyond app through Intent.getData()。
【原实现代码】:
private void installAPK() {
String fileName = xxxx;
String directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();
File apkFile = new File(directory+fileName);
if (!apkFile.exists()){
Toast.makeText(MyApplication.getContext(),"安装包文件不存在",Toast.LENGTH_SHORT).show();
return;
}
Intent intent = new Intent(Intent.ACTION_VIEW);
//安装完成后,启动app
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
startActivity(intent);
}
【问题根因】:FileUriExposedException,文件Uri暴露异常。实际上,以上代码在Android7.0版本以下仍然是好用的,但是到了7.0以上的版本就不行了,这也是Google在安全性方面的考虑。当你的应用把file:// Uri暴露给其他App的时候就会出现这种异常,因为接收方可能不具备访问该共享资源的权限,所以应该用content:// Url来拓展临时权限。
【解决办法】:使用FileProvider
1)在AndroidManifest.xml文件的application中添加
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="包名.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
2)在res的xml包中创建provider_paths.xml文件
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="sdcard_root" path="."/>
</paths>
其中paths下的子节点含义:
子节点 | 含义 |
<root-path> | 设备的根目录 new File("/") |
<files-path> | Context.getFileDir() |
<catch-path> | Context.getCatchDir() |
<external-path> | Environment.getExternalStorageDirectory() |
<external-files-path> | Context.getExternalFilesDirs() |
<external-catch-path> | Context.getExternalCatchDirs() |
以上xml文件,代表可以使用你所声明的sd卡根目录当前文件夹以及其子文件夹。
3)使用FileProvider解决高于Android7.0版本的兼容性问题
private void installAPK() {
String fileName = xxx;
String directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();
File apkFile = new File(directory+fileName);
if (!apkFile.exists()){
Toast.makeText(MyApplication.getContext(),"安装包文件不存在",Toast.LENGTH_SHORT).show();
return;
}
Intent intent = new Intent(Intent.ACTION_VIEW);
//安装完成后,启动app
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Uri uri = FileProvider.getUriForFile(this, this.getPackageName() + ".fileprovider", apkFile);
intent.setDataAndType(uri, "application/vnd.android.package-archive");
} else {
intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
}
startActivity(intent);
}
注意,兼容前后都不要忘了在AndroidManifest.xml文件中添加必要的权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
———————————————————————————————————————
本文为博主原创文章,转载请注明出处!
若本文对您有些许帮助,轻抬您发财的小手,关注/评论/点赞/收藏,就是对我最大的支持!
祝君升职加薪,鹏程万里!
本文地址:https://blog.csdn.net/w464960660/article/details/107188214
上一篇: 微信退款通知XML数据处理,以及req_info的解密
下一篇: 北京理工大学