调用系统相机、相册、剪裁图片,适配Android 12
第一步:FileProvider相关准备工作
在AndroidManifest.xml中增加provider节点:
<providerandroid:name="androidx.core.content.FileProvider"android:authorities="com.choosecrop.fileprovider"android:grantUriPermissions="true"android:exported="false"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/filepaths" /></provider>
其中:
android:authorities 表示授权列表,填写你的应用包名,当有多个授权时,用分号隔开。
android:exported 表示该内容提供器(FileProvider)是否能被第三方程序组件使用,必须为false,否则会报异常: java.lang.SecurityException: Provider must not be exported。
android:grantUriPermissions=“true” 表示授予 URI 临时访问权限。
接着,需要在res目录下建立一个xml目录,
<?xml version="1.0" encoding="utf-8"?>
<paths><external-files-path name="DCIM" path="." />
</paths>
说明:
files-path name=“name” path=“path” 对应 Context.getFilesDir()
cache-path name=“name” path=“path” 对应 getCacheDir()
external-path name=“name” path=“path” 对应Environment.getExternalStorageDirectory()
external-files-path name=“name” path=“path” 对应 Context.getExternalFilesDir()
external-cache-path name=“name” path=“path” 对应 Context.getExternalCacheDir()
external-media-path name=“name” path=“path” 对应 Context.getExternalMediaDirs()
注意:ExternalStorageDirectory在29后废弃,官方推荐使用Context.getExternalFilesDir()
可被使用的特定目录:
public static String DIRECTORY_ALARMS = “Alarms”;
public static String DIRECTORY_AUDIOBOOKS = “Audiobooks”;
public static String DIRECTORY_DCIM = “DCIM”;
public static String DIRECTORY_DOCUMENTS = “Documents”;
public static String DIRECTORY_DOWNLOADS = “Download”;
public static String DIRECTORY_MOVIES = “Movies”;
public static String DIRECTORY_MUSIC = “Music”;
public static String DIRECTORY_NOTIFICATIONS = “Notifications”;
public static String DIRECTORY_PICTURES = “Pictures”;
public static String DIRECTORY_PODCASTS = “Podcasts”;
第二步:使用FileProvider
在这之前,我们需要在AndroidManifest.xml中增加必要的读写权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
1. 通过相机获取图片
在通过Intent跳转系统相机前,我们需要对版本进行判断,如果在Android7.0以上,使用FileProvider获取Uri,代码如下:
/*** 从相机获取图片*/private void getImgFromCamera() {//用于保存调用相机拍照后所生成的文件tempFile = new File(this.getExternalFilesDir(DIRECTORY_DCIM), System.currentTimeMillis() + ".png");//跳转到调用系统相机Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);//判断版本if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //如果在Android7.0以上,使用FileProvider获取Uriintent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);Uri contentUri = FileProvider.getUriForFile(MainActivity.this, "com.choosecrop.fileprovider", tempFile);intent.putExtra(MediaStore.EXTRA_OUTPUT, contentUri);} else { //否则使用Uri.fromFile(file)方法获取Uriintent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(tempFile));}startActivityForResult(intent, CAMERA_REQUEST_CODE);}
2.通过相册获取图片
/*** 从相册获取图片*/private void getImgFromDicm() {Intent photo = new Intent(Intent.ACTION_PICK);photo.setType("image/*");photo(photoPickerIntent, DICM_REQUEST_CODE);}
3.剪裁图片
/*** 裁剪图片*/private void cropPhoto(Uri uri) {Intent intent = new Intent("com.android.camera.action.CROP");// Intent intent = new Intent("android.intent.action.EDIT");// intent.setAction("android.intent.action.EDIT");// intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);intent.setDataAndType(uri, "image/*");// intent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);intent.putExtra("crop", "true");intent.putExtra("aspectX", 1);intent.putExtra("aspectY", 1);intent.putExtra("outputX", 100);intent.putExtra("outputY", 100);intent.putExtra("return-data", false);File cropTemp = this.getExternalFilesDir(DIRECTORY_DCIM);File cropTempName = new File(cropTemp, System.currentTimeMillis() + "_crop_temp.png");Log.e("getPath", cropTempName.getAbsolutePath());Uri uriForFile = FileProvider.getUriForFile(this, "com.choosecrop.fileprovider", cropTempName);intent.putExtra(MediaStore.EXTRA_OUTPUT, uriForFile);grantPermissionFix(intent, uriForFile);startActivityForResult(intent, CROP_REQUEST_CODE);}
此处应设置return-data为false。
如果设置为true,是直接返回bitmap格式的数据,不仅耗费内存,最重要的是在Android 12,会报错:
src:content://com.miui.gallery.open/raw/%2Fstorage%2Femulated%2F0%2FPictures%2FWeiXin%2Fmmexport1662718600424.jpg, des: null。
所以设置为false。然后,设置裁剪完之后保存的路径,在这里使用URI方式传递数据,即:intent.putExtra(MediaStore.EXTRA_OUTPUT, uriForFile);
同时需要给系统裁剪APP赋予临时权限,
private void grantPermissionFix(Intent intent, Uri uri) {intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);List<ResolveInfo> resolveInfos = getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);for (ResolveInfo resolveInfo : resolveInfos) {String packageName = resolveInfo.activityInfo.packageName;grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);intent.setAction(null);intent.setComponent(new ComponentName(resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name));break;}}
第三步:接收图片信息
在onActivityResult方法中获得返回的图片信息,
先调用剪裁去剪裁图片,然后对剪裁返回的图片进行设置、保存、上传等操作。
@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent intent) {switch (requestCode) {case CAMERA_REQUEST_CODE: //调用相机后返回if (resultCode == RESULT_OK) {//用相机返回的照片去调用剪裁也需要对Uri进行处理if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {Uri contentUri = FileProvider.getUriForFile(MainActivity.this, "com.choosecrop.fileprovider", tempFile);cropPhoto(contentUri);} else {cropPhoto(Uri.fromFile(tempFile));}}break;case DICM_REQUEST_CODE: //调用相册后返回if (resultCode == RESULT_OK) {Uri uri = intent.getData();if (null != uri)cropPhoto(uri);else {Log.e("e", "null");}}break;case CROP_REQUEST_CODE: //调用剪裁后返回Log.e("d", "--------------222222222-------");if (null != intent) {Log.e("d", "---------------------not null");Uri data = intent.getData();mHeader_iv.setImageURI(data);
// Bundle bundle = intent.getExtras();
// if (bundle != null) {
// //在这里获得了剪裁后的Bitmap对象,可以用于上传
// Bitmap image = bundle.getParcelable("data");
// //设置到ImageView上
// mHeader_iv.setImageBitmap(image);
// //也可以进行一些保存、压缩等操作后上传String path = saveImage("crop", image);
// }} else {Log.e("d", "---------null");}break;}}
因为使用uri方式传递的文件,所以这样获取数据,
Uri data = intent.getData();
第四步:保存
public String save(String name, Bitmap bmp) {File dir = new File(this.getExternalFilesDir(DIRECTORY_DCIM).getPath());if (!dir.exists()) {dir.mkdir();}String fileName = name + ".png";File file = new File(dir, fileName);try {FileOutputStream fos = new FileOutputStream(file);bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);fos.flush();fos.close();return file.getAbsolutePath();} catch (IOException e) {e.printStackTrace();}return null;}
至此,Android 12 的兼容就OK了。
完整代码,可以到Github下载,别忘给star哦:
https://github.com/AlbertShen0211/ChooseCrop
调用系统相机、相册、剪裁图片,适配Android 12相关推荐
- 安卓开发小米4,酷派 手机适配和调用系统相机相册做图片上传的问题
// 启动相机startCamera.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {/ ...
- Android调用系统相机,相册裁切图片展示的实现
效果图: MainActivity package com.example.administrator.rxxjava;import android.content.Intent; import an ...
- Android开发 调用系统相机相册图片功能,解决小米手机拍照或者图片横竖相反问题,及小米手机相册图片路径问题
Android开发 调用系统相机相册图片功能,解决小米手机拍照或者图片横竖相反问题,及小米手机相册图片路径问题 1.调用相机,兼容7.0 AndroidManifest配置 <providera ...
- android调用系统相机并获取图片
如果不是特别的要求,通过拍照的方式取得图片的话,我们一般调用系统的拍照来完成这项工作,而没必要再自己去实现一个拍照功能.调用系统相机很简单,只需要一个intent就可以跳转到相几界面,然后再通过onA ...
- android 三星手机拍照旋转90度,解决三星调用系统相机拍照显示图片旋转90度横着的问题...
/** * 调用系统相机拍照工具类 * @author yao * */ public class CaremaUtil { private static String strImgPath = &q ...
- 解决三星调用系统相机拍照显示图片旋转90度横着的问题
最近项目有个功能是调用系统相机拍照上传图片的功能,发现别的手机都没有ok,只有三星的显示图片很明显是旋转了90度,横着的.后来百度了解是三星对android相机单独做了优化(android碎片化,各种 ...
- (复习)android 调用系统相机 图库 裁剪-图片上传-客服端-服务器
引用转载http://www.cnblogs.com/eyu8874521/archive/2012/07/20/2600697.html 效果: 客服端代码: package com.cn.lxz. ...
- android 调用系统播放器播放视频,适配android 7.0以上
1.新一个类并继承 FileProvider 类,不做其他事情 public class AppFileProvider extends FileProvider {} 2.AndroidManife ...
- android在主程序中调用图片,009android初级篇之APP中使用系统相机相册等集成应用...
009android初级篇之APP中使用系统相机相册等集成应用 android应用中使用相机功能,大致有两种方式实现: 直接调用系统内部的相机程序,显示的也是系统预设的界面(简单,只有简单的拍照功能) ...
- android 相机拍照返回,Android6.0机型上调用系统相机拍照返回的resultCode值始终等于0的问题...
版权声明:本文为博主原创文章,未经博主允许不得转载. 正常情况下调用系统相机拍照: 如果拍照后点击的是"确定"图标,返回的resultCode = -1(Activity.RESU ...
最新文章
- 一起谈.NET技术,asp.net控件开发基础(20)
- 控制器描述者(ControllerDescriptor),行为方法描述者(ActionDescriptor),参数描述者(ParameterDescriptor)的小结...
- WPF自定义控件的三种方式
- 看Kubernetes源码,学习怎么用Go实现调度队列
- Java基础学习总结(160)——JDK15正式发布,划时代的ZGC同时宣布转正
- 18 张图彻底弄懂 HTTPS 的原理!
- SharePoint:扩展DVWP - 第8部分:挂接了工作流列表表单操作
- boot客户管理系统源码_开源 SpringBoot+vueJs 前后端管理系统模版
- C向Python传递数组和List参数
- 解锁lintcode数字图像识别
- 基于3DGIS+BIM的房屋出售管理系统
- ZXing条码扫描----竖屏解决方案
- linux系统支持什么输入法,Linux系统常用输入法框架
- 差分放大电路及动态分析
- 【DBC专题】-4-DBC文件中的Signal信号字节顺序Motorola和Intel介绍
- 关于PCB的机械层和差分布线、RC滤波
- 回文树/回文自动机 引入
- rsync 同步本地文件到远端
- ibm aix 抓包命令_在IBM AIX上模拟丢弃的TCP / IP数据包
- 04-0006 MATLAB 弹幕壁纸