Android进阶封装之一个类实现兼容Android 6.0权限、适配Android7.0 拍照: 相机与相册上传图片就用我好啦!
来源:互联网 发布:ubuntu 卸载自带jdk 编辑:程序博客网 时间:2024/05/18 12:43
Android进阶封装之“史无前例”一个类实现兼容Android 6.0权限、适配Android 拍照7.0: 相机与相册上传图片就用我好啦!
一、前言。
本篇博客从基本的AndroidN开始说怎么适配其拍照,其与7.0以下有何区别?
再详细分析如何封装在 avtivity和fragment中的区别? (重点)
再详细说明下本封装库如何集成与使用。
博主最近为了适配 AndroidN的拍照,浏览了很多技术文章,有些是需要4到5个类来实现、有些不能在fragment中实现… … ,个人敢想 “可以一个类实现封装全部拍照工作吗?” , 扬起袖子就是干!在辛苦的四个小时,终于把这个封装给弄出来的!
已经放在GitHub上了(强烈推荐Star):https://github.com/xuhongv/TakePhotoAndroidN-master
已经兼容在小米手机出现Attempt to invoke interface method ‘boolean Android.database.Cursor.moveToFirst()问题 。(2017/8/19)
已经兼容在fragment出现权限授权不回调的bug。(2017/8/19)
已经兼容在fragmenr出现图片不回调的bug。(2017/8/18)
二、Android7.0和其以下的版本在拍照时候有何区别?
由于从Android7.0(下面统一为AndroidN)开始,直接使用真实的路径的Uri会被认为是不安全的,会抛出一个FileUriExposedException这样的异常。需要使用FileProvider,选择性地将封装过的Uri共享到外部。
出于以上问题,很多事情都意味着要适配,比如你在AndroidN以下,可以跳转到拍照和图库界面,但是在AndroidN就不行了!但是会有error等级的log输出,出现FileUriExposedException这样的异常,原因是Andorid7.0的“私有目录被限制访问”,“StrictMode API 政策”。
谷歌这样做,出自用户隐私的考虑。既然这样,我们就必须要通过FileProvider(Provider的一个子类)共享其URL到外部即可。
问题来了,FileProvider应该如何写?
- 1.在manifest中添加provider,毕竟Provider也是属于四大组件之一。配置中的authorities按照江湖规矩一般加上包名,${applicationId}是获取当前项目的包名,前提是在module下的gradle.buile文件中defaultConfig{}闭包中要有applicationId属性哦。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
2、在您工程的 res 文件夹根目录下创建一个xml文件夹,里面再新建一个file_provider_paths文件夹,其对应都是在上面的meta-data标签下面的android:resource值的。
- 代码中path=”“,是有特殊意义的,它代码根目录,也就是说你可以向其它的应用共享根目录及其子目录下任何一个文件了。其file_provider_paths内容如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
- 3、 自此为止,已经把FileProvider的基本的环境搭建好了,别忘了加拍照权限、读取和存储SD卡的权限哦:
- 1
- 2
- 3
- 1
- 2
- 3
三、熟悉拍照的整个流程。
①、你先要创建一个URL作为你拍照后得到的图片的URL , 这里我们使用 intent , 制定Action为 MediaStore.ACTION_IMAGE_CAPTURE , 这样就可以跳转到相机界面了 ,别忘了,在intent上把你要传的URL放上去,名字一定要是 :MediaStore.EXTRA_OUTPUT 。最后使用startActivityForResult()跳转,别忘了回调码。
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);intent.putExtra(MediaStore.EXTRA_OUTPUT, imgUri);startActivityForResult(intent, CODE_ORIGINAL_PHOTO_CAMERA)
②、等到跳转相机界面后,我们不需理会用户怎么操作,我们只需关心传回来的Uri数据是否为空,毕竟在拍照后用户可能点击了舍弃,导致拿到相片为空。
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) { //相片处理 if (resultCode != RESULT_CANCELED) { switch (requestCode) { //相册数据,回调码要和上面一致。 case IMAGE_REQUEST_CODE: //判断返回的数据Uri是否为空? if(imgUri!=null){ //doyourthings } break; } }
下面是整个拍照流程图:
四、熟悉从图库拿图片的整个流程。
- ①、从本地图库拿图片的原理和相机拍照一样,也是靠Intent跳转到图库界面,指定的Action为Intent.ACTION_PICK,Type为 “image/*” ,别忘了回调码。
- 1
- 2
- 3
- 1
- 2
- 3
- ②、与拍照不同的是,onActivityResult()方法成功返回的话。那么传回来的是一个图片文件哦。同样,先判断是否为空?
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
下面是整个相册选择图片流程图:
五、动态权限?
让不少人烦恼的是,在安卓6.0之后,需要动态授权,那么作为拍照、写入SD卡和读取SD卡,这些“危险权限”,动态授权是必然的。
我这里采用郭神的做法,如果用户拒绝的某些权限的话,会通过接口提示。代码如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
六、关于裁剪的代码!
private void statZoom(File srcFile, File output) { Intent intent = new Intent("com.android.camera.action.CROP"); intent.setDataAndType(getImageContentUri(mContext, srcFile), "image/*"); // crop为true是设置在开启的intent中设置显示的view可以剪裁 intent.putExtra("crop", "true"); // 是否缩放?如果不缩放,会出现黑边哦 intent.putExtra("scale", true); // aspectX aspectY 是宽高的比例 intent.putExtra("aspectX", aspectX); intent.putExtra("aspectY", aspectY); // outputX,outputY 是剪裁图片的宽高 intent.putExtra("outputX", outputX); intent.putExtra("outputY", outputY); intent.putExtra("return-data", false);//true:不返回uri,false:返回uri intent.putExtra("scaleUpIfNeeded", true); intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(output)); intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); //此处兼容在fragment不会回调图片问题 if (isActicity) { mActivity.startActivityForResult(intent, CODE_TAILOR_PHOTO); } else { mFragment.startActivityForResult(intent, CODE_TAILOR_PHOTO); } }
七、封装的主角来了!
6.1 、介绍只需三步的环境集成:
- 第一步:把 demo下的res的 xml文件夹整个复制到你的工程res文件夹根目录下:
- 第二步:在你AndroidManifest.xml下的Application节点下加入以下代码:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 如下所示
-第三步 :把demo的就仅仅一个类 TakePictureManager.class 复制过去就可以啦!别忘了在清单文件加相关权限哦!
6.2 、怎么使用?
示例:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
使用详细步骤:
①、先new一个TakePictureManager 对象,构造方法只需传this即可(不管你在Activity还是在Fragment)。
②、重写onActivityResult()方法,调用对象的attachToActivityForResult()方法,参数依次是onActivityResult()回调的参数。 实现把拍照或相册回调发数据绑定在对象方法处理。
③、重写onRequestPermissionsResult()方法,调用对象的onRequestPermissionsResult()方法,参数依次是onRequestPermissionsResult()回调的参数。 实现把权限回调绑定在对象方法处理。
④、这时候,你只需调用对象方法,即可轻松调用相机或相册。具体的方法参数说明如下:
八、造轮子时候遇到的问题:
在Fragment使用时候,回调的相片数据被依附的activity的onActivityResult()方法拦截了!相信这个问题困扰许多人的问题,在使用他人代码时候,在Activity可以使用,但是在Fragment却失败。原因在于:
- 在Fragment就存在startActivityForResult()方法,不需要 getActivity().startActivityForResult() , 也就是说不需要调用 依附的Activity的此方法,本身就有此方法。这是我翻阅 Fragment源码发现。截图如下:
- 于是乎我在封装时候,特意这样做:
好了,到此为止了,如果你们在使用遇到什么问题,随时在本博客留言啦!
已经放在GitHub上了(推荐Star,你以后肯定会用到哦):https://github.com/xuhongv/TakePhotoAndroidN-master
- Android进阶封装之一个类实现兼容Android 6.0权限、适配Android7.0 拍照: 相机与相册上传图片就用我好啦!
- Android进阶封装之一个类实现兼容Android 6.0权限、适配Android7.0 拍照!
- 调用系统相机、相册、剪裁图片并上传(常用于上传头像,兼容Android7.0)
- 调用系统相机、相册、剪裁图片并上传(常用于上传头像,兼容Android7.0)
- Android7.0调用系统相机拍照、相册选择图片、裁剪
- android studio 适配android7.0 android 6.0拍照调用系统裁剪工具实现头像上传功能
- HTML5拍照上传图片&Phonegap封装HTML5调用Android相机拍照上传到PHP端
- Android拍照和从相册获取图片(解决android7.0打开相机崩溃的问题),同时也解决了拍完照后图片方向不正的问题
- Android实现图片(拍照+相册)上传功能
- Android调用相机实现拍照并裁剪图片,调用手机中的相册图片并裁剪图片
- Android WebView 选择图片并上传(调用相机拍照/相册/选择文件)
- android 调用相机 相册 及图片上传
- android上传图片(相机,相册)
- Android拍照,相册选择图片以及Android6.0权限管理
- Android拍照,相册选择图片以及Android6.0权限管理
- Android拍照,相册选择图片以及Android6.0权限管理
- Android启动相机拍照、相册选取图片,裁剪图片
- Android7.0调用系统相机拍照、相册选择图片、裁剪 图片压缩
- 经验分享 |【PDF下载】双11技术峰会之面对双11的前端“极限挑战”
- scala中的reduceLeft,reduceRight,foldLeft,foldRight方法
- Android-onCreate与virtual function
- LRUCache算法的简单实现
- slf4j的包使用说明
- Android进阶封装之一个类实现兼容Android 6.0权限、适配Android7.0 拍照: 相机与相册上传图片就用我好啦!
- atoi()函数的实现
- SQLServer
- Lucene学习笔记(一)
- 代理模式
- django模型的用法
- 一天写多少行代码才算是好程序员?
- 如何用Xshell快速连接远程电脑
- android 7.0 适配