Android 7.0相机适配及FileProvider重复那些坑
本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点
Android 7.0相机拍照适配
(1)首先必须获取拍照的权限
简单一点的可以直接用ActivityCompat
的requestPermissions
方法
ActivityCompat.requestPermissions(context, new String[]{permission}, requestCode);
权限请求的结果会在onRequestPermissionsResult
中回调
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { case 1://对应requestPermissions的requestCode if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {//如果一次申请多个权限,就按顺序依次grantResults[1]、grantResults[2]判断 Toasts.showShort("再次点击即可拍照"); } else { // Permission Denied } break; } }
(2)调用相机拍照
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); UUID uuid = UUID.randomUUID(); File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), uuid.toString() + ".jpeg");//拍照文件的路径 //判断是否是AndroidN以及更高的版本 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); Uri uri = FileProvider.getUriForFile(getContext(), BuildConfig.APPLICATION_ID + ".fileProvider", file); intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); } else { Uri uri = Uri.fromFile(file); intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); } startActivityForResult(intent, requestCode);
主要的适配就是Android 7.0以上发起调用的Uri必须通过FileProvider
来获取,也就是下面这句:
Uri uri = FileProvider.getUriForFile(getContext(), BuildConfig.APPLICATION_ID + ".fileProvider", file);
FileProvider
的getUriForFile
方法有三个参数:
- 第一个参数为
Context
,这个好理解 - 第二个参数为
FileProvider
的签名,也就是一个唯一标识,这个一个应用里面必须是唯一的,否则会有问题,后面会单独讲。一般为包名+自定义的标识,这个必须和AndroidManifest
中配置的Provider的authorities
属性一致 - 第三个参数也好立即,就是拍照将要生成的文件了
所以我们还需要对FileProvider
进行特别的处理
(3)在AndroidManifest文件中注册FileProvider
<!--Android N 相机--> <provider android:name=".provider.MyFileProvider" android:authorities="${applicationId}.myfileprovider"//这里表示授权信息 android:grantUriPermissions="true"//必须为true,表示同意权限 android:exported="false">//必须为false,否则会报错 <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
-
name
属性为FileProvider的路径 -
authorities
为授权的签名,一般为包名+自定义的标识,与生成的Uri的第二个参数对应 -
grantUriPermissions
属性必须为true -
exported
必须为false -
meta-data
中的resource
属性必须配置,为共享的文件路径,也就是系统相机应用和我们的应用共享的文件路径
(4)创建上面配置的file_paths
共享文件配置
文件内容就是指定的共享路径了
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="external_files" path="."/> </paths>
(5)最后在onActivityResult中接收照片
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); //拍照成功以后 if (resultCode == RESULT_OK) { switch (requestCode) { case FROM_CAMERA: //做照片的处理 ... } } else { ToastUtil.shortToast(this, R.string.cancel); } }
适配需要注意的坑
(1)FileProvider路径不一致
- 这里要特别注意上面获取Uri时的第二个参数,也就是包名+自定义的标识必须和
AndroidManifest
文件中配置的一致 - 第二个就比较坑了,如果是模块化开发,需要特别注意包名的一致
再来看看那句代码:
Uri uri = FileProvider.getUriForFile(getContext(), BuildConfig.APPLICATION_ID + ".fileProvider", file);
坑就在BuildConfig.APPLICATION_ID
这里,如果用BuildConfig
来获取APPLICATION_ID
,在模块化开发中就会出现不一致的情况。比如打开相机的模块是camera
,我们应用的包名是com.my.app
,那么BuildConfig.APPLICATION_ID
的值就不一样了:
camera模块:com.my.app.camera
我们app:com.my.app
这样导致的后果就是导调用相机的时候闪退,并且每次通过IDE安装应用的时候都会弹出下面的提示要重新安装App:
正确的姿势是用getPackageName()
的方式获取,也就是改成下面这样:
Uri uri = FileProvider.getUriForFile(mContext, mContext.getPackageName() + ".myfileprovider", file);
(2)FileProvider重复
这个也出现在模块话开发中,或是引用的三方库中也定义了FileProvider,就会报FileProvider重复的错误。
Attribute provider#android.support.v4.content.FileProvider@authorities value=(***.fileProvider) from AndroidManifest.xml:352:13-62 is also present at ...
解决方法也很简单,就是定义一个我们自己的FileProvider:
public class MyFileProvider extends FileProvider { }
是的,其他什么也不用干,直接继承FileProvider创建一个自己的FileProvider就好
然后,AndroidManifest文件中定义的FileProvider的name属性改成上面的MyFileProvider
的路径就好
<provider android:name=".xtreme.provider.MyFileProvider" //自定义的FileProvider的路径 android:authorities="${applicationId}.myfileprovider" android:grantUriPermissions="true" android:exported="false"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Swift 无限轮播图
ICycleView ICycleView是一个基于UICollectionView实现的轻量级无限轮播图 Content [Features]() [Requirements]() [CocoaPods]() [Usage]() [默认滚动视图]() [自定义图片宽度和指示器的位置和颜色]() [自定义Cell-纯代码和Xib创建都支持]() [Implementation]() [实现原理]() [主要代码]() [UICollectionView代理方法]() [循环轮播实现]() [Contact]() [Github]() Features 支持单张图片 支持滚动图片宽度设置 支持本地图片显示,网路图显示,本地图片和网路图混合显示 支持自定义图片展示Cell(纯代码和Xib创建都支持) 支持UIPageControl具体位置设置 支持UIPageControl显示颜色设置 支持图片点击回调 支持图片滚动回调 Requirements iOS 8.0+ Swift 4.0+ CocoaPods pod 'ICycleView', '~> 1.0.0' 在终端 pod se...
- 下一篇
Android 开发技术面总结
本来着 作者丨AffyFei ,原文地址:https://www.jianshu.com/p/b110f9c1384c 今天早上参加了深圳 OPPO 开发工程师的技术面试,总的来说面试过程不是很顺利。面试官并没有问一些很深奥的底层原理,基本都是一些 Java 基础以及 Android 四大组件内的基础,但是我自身在开发过程中并没有很重视这些理论基础,导致很多知识点都忘记了。整个面试过程耗时一小时,感谢两位面试官不厌其烦地给我提示,一方面让我能够回想起来那些遗忘的知识点,另一方面也缓解了尴尬的气氛。。。 顺便一说,OPPO 的保密工作还是做得比较严格的,进去后海卓越中心大楼前需要申请临时通行证才能进去。而在面试前还需要登记,并且把手机的前后摄像头都给用胶带封起来才能进行面试。废话少说,下面分成两部分汇总一下这次技术面试的知识点。 Java 1、如何理解Java的多态?其中,重载和重写有什么区别? 多态是同一个行为具有多个不同表现形式或形态的能力,多态是同一个接口,使用不同的实例而执行不同操作,多态就是程序运行期间才确定,一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS8编译安装MySQL8.0.19
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- SpringBoot2整合Redis,开启缓存,提高访问速度
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- Hadoop3单机部署,实现最简伪集群
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果