Android 7.0 调取系统相机崩溃解决android.os.FileUriExposedException
一、写在前面
最近由于廖子尧忙于自己公司的事情和 OkGo (一款专注于让网络请求更简单的网络框架) ,故让LZ 接替维护 ImagePicker(一款支持单、多选、旋转和裁剪的图片选择器),也是处理了诸多bug,最近总算趋于稳定了,这里就把Android N (API 24) 以上的相机适配方案分享给大家。
Android Nougat 也是被更新很久了,作为一名 Andorid 开发者,我们有义务时刻准备自己调整 targetSdkVersion 为最近的一个,于是从之前的 23 直接提高到了 25 。
和往常一样,每当我们调整targetSdkVersion,我们需要检查我们的代码的每一部分工作的非常好。如果你只是简单地更改代码,我可以说,你的应用程序正在崩溃或故障的高风险。在这种情况下,当你改变你的应用程序的targetSdkVersion 24,我们需要检查每一个功能完美的作品在Android的牛轧糖(24)以上。
拿到 7.0 的小米5测试机后,迫不及待对自己维护的 ImagePicker 测试了一个遍,然而的确和大家所提的issuse一样,在调用系统相机的时候直接崩溃了。
二、到底是什么引发了 7.0 相机崩溃
跟进错误日志到源码发现,在我们调用相机获取 Uri 的时候发生了崩溃。
原因很明显,file:// 不被允许作为一个附加的 Uri 的意图,否则会抛出 FileUriExposedException 。
三、为什么在 Android Nougat 下 file:// 不被允许?
你可能会很好奇为什么 Android 团队决定改变这种行为。
其实背后有一个很好的理由,如果文件路径被发送到目标应用程序(相机应用程序在这种情况下),文件将完全访问通过相机应用程序的过程,而不仅仅只有发起者能收到。
但让我们考虑一下,实际上是由我们的应用程序去启动摄像头拍照,并保存作为我们的应用程序的代表文件。因此,该文件的访问权限应该是我们的应用程序而不是摄像头应用程序本身。这就是为什么现在 file:// 在 targetSdkVersion 24 中要求每一位开发者都去完成这个任务。
四、那到底怎么解决?
既然 file:// 不再被允许,那我们应该怎么处理呢?答案是通过 FileProvider 去解决它。
我们应该怎么让 FileProvider 解决好它。
1、首先是在 AndroidManifest.xml 中申明
<provider
android:authorities="${applicationId}.provider"
android:name=".ImagePickerProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>
2、创建一个provider_paths.xml 文件在 res文件夹下的 xml 文件夹下。
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="external_files" path="."/>
</paths>
3、在适当的地方去替换它
Uri uri;
if (VERSION.SDK_INT <= VERSION_CODES.M){
uri = Uri.fromFile(takeImageFile);
}else{
/**
* 7.0 调用系统相机拍照不再允许使用Uri方式,应该替换为FileProvider
* 并且这样可以解决MIUI系统上拍照返回size为0的情况
*/
uri = FileProvider.getUriForFile(activity, ProviderUtil.getFileProviderName(activity), takeImageFile);
} Log.e("nanchen",ProviderUtil.getFileProviderName(activity));
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,uri);
五、几点说明
对于上面的三步操作,做几点说明:
1、在 AndroidManifest.xml 文件中对 provider 的 name 属性申明为什么是 .magePickerProvider (实际上这是一个继承自 FileProvider 但什么也没实现的类) 而不直接把name赋为android.support.v4.content.FileProvider ?
这是因为 ImagePicker 作为一个图片选择框架,而你的 App 中同样可能会有申明,为了避免 Android Studio 在编译的时候 merge 各个 Module 导致冲突,这里保险起见的申明了一个不一样的名字。
2、为什么在 AndroidManifest.xml 文件中申明的 authority 属性为 ${applicationId}.provider , 而不是固定的名字。
这是因为在 Android 中,要求 authority 必须是唯一的,如果你在定义一个 provider 的时候为它指定一个唯一的 authority,这里且拿 ImagePicker 做比方,假如你在一个 App 上使用了 ImagePicker 作为图片选择框架,而你在另外一个应用中再次使用 ImagePicker 的时候,系统会检查当然已安装应用的 authority 是否和你要安装应用的 authority 相同,如果相同则会弹出下面的警告,并安装失败。
所以我们在定义 authorities 的时候采用 applicationId + provider 的形式,在获取 authorities 的时候,我们可以通过包名 + provider 的方式获取。代码如下:
package com.lzy.imagepicker.util; import android.content.Context; /**
* 用于解决provider冲突的util
*
* Author: nanchen
* Email: liushilin520@foxmail.com
* Date: 2017-03-22 18:55
*/ public class ProviderUtil { public static String getFileProviderName(Context context){
return context.getPackageName()+".provider";
}
}
六、写在最后
以上便解决了 Android N 的相机崩溃问题,如有写的不对的地方,欢迎大家在评论区留言。
图片框架 ImagePicker 地址:https://github.com/jeasonlzy/ImagePicker
该文章同步发表到简书:http://www.jianshu.com/p/57ba0d1511b9
Android 7.0 调取系统相机崩溃解决android.os.FileUriExposedException的更多相关文章
- 【适配整理】Android 7.0 调取系统相机崩溃解决android.os.FileUriExposedException
一.写在前面 最近由于廖子尧忙于自己公司的事情和 OkGo (一款专注于让网络请求更简单的网络框架) ,故让LZ 接替维护 ImagePicker(一款支持单.多选.旋转和裁剪的图片选择器),也是处理 ...
- android 7.0 调用系统相机崩溃的解决方案(非谷歌官方推荐)
解决方案: 1.(推荐)7.0之后你的app就算有权限,给出一个URI之后手机也认为你没有权限. 不用修改原有代码,在Application的oncreate方法中:(或者直接放在调用相机的activ ...
- Android权限管理之Android 6.0运行时权限及解决办法
前言: 今天还是围绕着最近面试的一个热门话题Android 6.0权限适配来总结学习,其实Android 6.0权限适配我们公司是在今年5月份才开始做,算是比较晚的吧,不过现在Android 6.0以 ...
- android 4.0.4系统下实现apk的静默安装和启动
转 android 4.0.4系统下实现apk的静默安装和启动 分类: Android 2013-02-14 14:13 1762人阅读 评论(10) 收藏 举报 最近在android 4.0.4系统 ...
- Android下载图片/调用系统相机拍照、显示并保存到本地
package com.example.testhttpget; import java.io.BufferedReader; import java.io.FileNotFoundException ...
- 【转】android 5.0 64bit系统加载库文件失败问题浅析
原文网址:http://blog.csdn.net/andrewblog/article/details/43601303 最近公司的一个项目使用android 5.0 64 bit平台,相对以前版本 ...
- Android7.0调用系统相机拍照、读取系统相册照片+CropImageView剪裁照片
Android手机拍照.剪裁,并非那么简单 简书地址:[我的简书–T9的第三个三角] 前言 项目中,基本都有用户自定义头像或自定义背景的功能,实现方法一般都是调用系统相机–拍照,或者系统相册–选择照片 ...
- 关于 Android 5.0 原生系统网络图标上的感叹号问题解决方法
解决方案 adb shell settings put global captive_portal_server g.cn 参考 关于 android 5.0 网络图标上的感叹号及其解决办法
- 【Android学习】调用系统相机
Android调用系统相机分三步走: 首先是要设置调用相机的权限. 其次是给按钮加打开相机的事件. 最后是拍照后进行图片的保存. 第一步,添加权限: <!-- 调用系统相机 --> < ...
随机推荐
- 《JAVASCRIPT高级程序设计》闭包
一.闭包的概念 闭包是JAVASCRIPT中最重要的概念之一,闭包是指有权访问另一个函数作用域中变量的函数:创建闭包常见的方式,就是在一个函数内部,创建另一个函数.以下的例子创建了一个闭包,加粗的两行 ...
- Disruptor深入解读
将系统性能优化到极致,永远是程序爱好者所努力的一个方向.在java并发领域,也有很多的实践与创新,小到乐观锁.CAS,大到netty线程模型.纤程Quasar.kilim等.Disruptor是一个轻 ...
- hashMap_使用
转]Java中HashMap遍历的两种方式原文地址: http://www.javaweb.cc/language/java/032291.shtml 第一种: Map map = new HashM ...
- 简单三层分页aspnetpager控件(欢迎指点)
首先添加引用AspNetpager.dll(将.dll文件放在bin中进行引用) 接着添加<%@ Register Assembly="AspNetPager" Namesp ...
- ASP.NET Core中的缓存[1]:如何在一个ASP.NET Core应用中使用缓存
.NET Core针对缓存提供了很好的支持 ,我们不仅可以选择将数据缓存在应用进程自身的内存中,还可以采用分布式的形式将缓存数据存储在一个“中心数据库”中.对于分布式缓存,.NET Core提供了针对 ...
- Apache Derby倒斗之路-01小道消息
1.DERBY是什么: Apache Derby 是IBM于2004年贡献给Apache软件基金会的数据库,于2005年正式成为开源项目,Derby作为一个基于JAVA的关系型数据库框架,他拥有许多便 ...
- 关于 <textarea ></textarea >标签在苹果微信浏览器出现 内阴影
解决方法:(去除浏览器默认的样式元素) textarea { box-shadow:0px 0px 0px rgba(0,0,0,0); -webkit-appearance:none; }
- RDLC系列(一)ASP.NET RDLC 报表自定义数据源
最近一段时间开发ERP系统中要用到不少报表打印,在网上找了一圈发现想些好用的报表控件大部分要收费,一些面免费要么不好用要么IE8不兼容,最后还是用了微软自带的RDLC报表,把自己遇到的坑和技巧整理分享 ...
- c++中,int *a=new int(120)语句的意思
int *a=new int(120); 申请一个整型变量空间,赋初值为120,并定义一个整型指针a指向该地址空间 int *a=new int[120]; 申请120个整型变量空间,没有赋初值,并定 ...
- 自己写的python脚本(抄的别人的,自己改了改,用于整理大量txt数据并插入到数据库)
昨天,遇到了一个问题,有100w条弱口令数据,需要插入到数据库中,而且保存格式为txt. 身为程序员不可能一条一条的去写sql语句吧(主要是工作量太大,我也懒得干).所以,我 就百度了一下,看有没有相 ...