文章目录

      • 原因
      • 解决方法
      • 解决方法2

最近在Android N 上 安装Apk时报错

AndroidJavaException: android.os.FileUriExposedException: file:///storage/emulated/0/Android/data/com.linxinfa.mygame/files/game_demo.apk exposed beyond app through Intent.getData()

原因

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。

解决方法

1 在AndroidManifest.xml中添加如下代码

<provider android:name="android.support.v4.content.FileProvider"  android:authorities="app的包名.fileProvider"  android:grantUriPermissions="true"  android:exported="false">  <meta-data    android:name="android.support.FILE_PROVIDER_PATHS"    android:resource="@xml/file_paths" />provider>

注意:
authorities:app的包名.fileProvider
grantUriPermissions:必须是true,表示授予 URI 临时访问权限
exported:必须是false
resource:中的@xml/file_paths是我们接下来要添加的文件

2 在res目录下新建一个xml文件夹,并且新建一个file_paths的xml文件(如下图)
Android N 7.0中报错:android.os.FileUriExposedException的解决方法_第1张图片
3、打开file_paths.xml文件添加如下内容

<?xml version="1.0" encoding="utf-8"?><paths>  <external-path path="Android/data/app的包名/" name="files_root" />  <external-path path="." name="external_storage_root" />paths>

path:需要临时授权访问的路径(.代表所有路径)
name:就是你给这个访问路径起个名字

4、修改代码适配Android N

Intent intent = new Intent(Intent.ACTION_VIEW);//判断是否是AndroidN以及更高的版本if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {  intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);  Uri contentUri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".fileProvider", apkFile);  intent.setDataAndType(contentUri, "application/vnd.android.package-archive");} else {  intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");  intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);}startActivity(intent);

1、首先我们对Android N及以上做判断;
2、然后添加flags,表明我们要被授予什么样的临时权限
3、以前我们直接 Uri.fromFile(apkFile)构建出一个Uri,现在我们使用FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + “.fileProvider”, apkFile);
4、BuildConfig.APPLICATION_ID直接是应用的包名


解决方法2

看到别人说有更简单粗暴的办法,直接禁用新特性,如下:
在库的onCreate方法里,添加如下代码

if(Build.VERSION.SDK_INT>=24){    try{        Method m = StrictMode.class.getMethod("disableDeathOnFileUriExposure");        m.invoke(null);    }catch(Exception e){        e.printStackTrace();    }}

经测试,在安卓7,安卓8,安卓9成功。

更多相关文章

  1. Android 文件打开方式
  2. android 获取服务器文件流 hander
  3. Android 文件及文件夹操作

随机推荐

  1. cocos2d-x-2.1.4在NDK r9下的编译问题
  2. 【Android开发小记--9】触摸事件---实现
  3. Android(安卓)导入项目出错
  4. Android(安卓)inject input events 注入T
  5. android 自定义PopupMenu详解
  6. Android(安卓)setLayerType 硬件加速问题
  7. Android和IOS开发资料
  8. Android(安卓)内核源代码交叉编译纺
  9. android的零星基础点(多媒体)之一
  10. android sd卡数据库读取