解决Android N文件访问crash android.os.FileUriExposedException file:///storage/emulated/0/xxx

原因:

Android N对访问文件权限收回,按照Android N的要求,若要在应用间共享文件,您应发送一项 content://URI,并授予 URI 临时访问权限。
而进行此授权的最简单方式是使用 FileProvider类。
1.在mainfest中加入FileProvider注册

<application>     <providerandroid:authorities="你的应用名.fileprovider"              android:name="android.support.v4.content.FileProvider"android:grantUriPermissions="true"android:exported="false">         <meta-data           android:name="android.support.FILE_PROVIDER_PATHS"               android:resource="@xml/filepaths"/>    provider>application>

2.配置filepaths文件

<?xml version="1.0" encoding="utf-8"?><paths>    <external-path path="yang/" name="files_path" />paths>

其中:
files-path代表的根目录: Context.getFilesDir()
external-path代表的根目录: Environment.getExternalStorageDirectory()
cache-path代表的根目录: getCacheDir()

<external-path path="honjane/" name="files_path" />

path 代表要共享的目录
name 只是一个标示,随便取吧 自己看的懂就ok

for example:通过provider获取到的uri链接

content://com.ys.providerdemo.fileprovider/files_path/files/b7d4b092822.pdf

name对应到链接中的files_path

path对应到链接中的 files ,当然files是在ys/目录下
3.访问文件

/**     * 打开文件     * 当手机中没有一个app可以打开file时会抛ActivityNotFoundException     * @param context     activity     * @param file        File     * @param contentType 文件类型如:文本(text/html)          */    public static void startActionFile(Context context, File file, String contentType) throws ActivityNotFoundException {        if (context == null) {            return;        }        Intent intent = new Intent(Intent.ACTION_VIEW);        intent.addCategory(Intent.CATEGORY_DEFAULT);        intent.setDataAndType(getUriForFile(context, file), contentType);        if (!(context instanceof Activity)) {            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);        }        context.startActivity(intent);    }    /**     * 打开相机     *     * @param activity    Activity     * @param file        File     * @param requestCode result requestCode     */    public static void startActionCapture(Activity activity, File file, int requestCode) {        if (activity == null) {            return;        }        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);        intent.putExtra(MediaStore.EXTRA_OUTPUT, getUriForFile(activity, file));        activity.startActivityForResult(intent, requestCode);    }    private static Uri getUriForFile(Context context, File file) {        if (context == null || file == null) {            throw new NullPointerException();        }        Uri uri;        if (Build.VERSION.SDK_INT >= 24) {            uri = FileProvider.getUriForFile(context.getApplicationContext(), "你的应用名.fileprovider", file);        } else {            uri = Uri.fromFile(file);        }        return uri;    }

同样访问相机相册都通过FileProvider.getUriForFile申请临时共享空间
已写成工具类上传到github,需要直接下载
使用方法简单,一行代码搞定
打开文件:
打开文件:

 try {      FileUtils.startActionFile(this,path,mContentType);    }catch (ActivityNotFoundException e){ }

调用相机:

 FileUtils.startActionCapture(this, file, requestCode);

修复bug:

Java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/xxx/xxx/file/12b31d2cab6ed.pdf

external与storage/emulated/0/对应,乍一看貌似没什么问题,path设置的是external的根路径,对应Environment.getExternalStorageDirectory(),

然而这个方法所获取的只是内置SD卡的路径,所以当选择的相册中的图片是外置SD卡的时候,就查找不到图片地址了,因此便抛出了failed to find configured root that contains的错误。

通过分析FileProvider源码发现,在xml解析到对应的标签后,会执行 buildPath() 方法来将根标签(files-path,cache-path,external-path等)对应的路径作为文件根路径,

在buildPath(),会根据一些常量判断是构建哪个目录下的path,除了上面介绍的几种path外还有个TAG_ROOT_PATH = “root-path” ,只有当不是root-path时才会去构建其他path,

官方也没介绍这个root-path,测试了一下发现对应的是DEVICE_ROOT指向的整个存储的根路径,这个bug就修复了

修改filepaths文件:

<paths>      <root-path name="honjane" path="" />paths>

代码下载:https://github.com/yangsongsong/fileProviderDemo

更多相关文章

  1. eclipse+android开发logcat无法输出日志解决办法
  2. Android(安卓)Studio中项目资源出现: Validates resource referen
  3. Linux下使用android ndk编译FFmpeg(最新版FFmpeg 4.4.1)
  4. Android高仿微信相册选择器 多图片选择器、拍照
  5. Android4.0.3修改启动动画和开机声音
  6. Android面试、笔试、期中/末考试复习提纲总结
  7. Android动态添加布局LayoutInflater简单用法
  8. android sdk常用命令
  9. android property属性property_set()&& property_get() selinux

随机推荐

  1. error: Error retrieving parent for ite
  2. 用CSS3生成的一个漂亮的android客户端页
  3. Android命令行启动程序-am命令的使用-纠
  4. Android果然强大,连截字这种操作都集成了
  5. 利用html5开发android(转载)
  6. 【Android布局】在程序中设置android:gra
  7. Android(安卓)中 drawTextOnPath 文字效
  8. Android(安卓)如何去除Launcher上默认的g
  9. android 中的 openGL引擎的移植
  10. ROS(indigo) turtlebot2 + android一些有