第一步: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相关推荐

  1. 安卓开发小米4,酷派 手机适配和调用系统相机相册做图片上传的问题

    // 启动相机startCamera.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {/ ...

  2. Android调用系统相机,相册裁切图片展示的实现

    效果图: MainActivity package com.example.administrator.rxxjava;import android.content.Intent; import an ...

  3. Android开发 调用系统相机相册图片功能,解决小米手机拍照或者图片横竖相反问题,及小米手机相册图片路径问题

    Android开发 调用系统相机相册图片功能,解决小米手机拍照或者图片横竖相反问题,及小米手机相册图片路径问题 1.调用相机,兼容7.0 AndroidManifest配置 <providera ...

  4. android调用系统相机并获取图片

    如果不是特别的要求,通过拍照的方式取得图片的话,我们一般调用系统的拍照来完成这项工作,而没必要再自己去实现一个拍照功能.调用系统相机很简单,只需要一个intent就可以跳转到相几界面,然后再通过onA ...

  5. android 三星手机拍照旋转90度,解决三星调用系统相机拍照显示图片旋转90度横着的问题...

    /** * 调用系统相机拍照工具类 * @author yao * */ public class CaremaUtil { private static String strImgPath = &q ...

  6. 解决三星调用系统相机拍照显示图片旋转90度横着的问题

    最近项目有个功能是调用系统相机拍照上传图片的功能,发现别的手机都没有ok,只有三星的显示图片很明显是旋转了90度,横着的.后来百度了解是三星对android相机单独做了优化(android碎片化,各种 ...

  7. (复习)android 调用系统相机 图库 裁剪-图片上传-客服端-服务器

    引用转载http://www.cnblogs.com/eyu8874521/archive/2012/07/20/2600697.html 效果: 客服端代码: package com.cn.lxz. ...

  8. android 调用系统播放器播放视频,适配android 7.0以上

    1.新一个类并继承 FileProvider 类,不做其他事情 public class AppFileProvider extends FileProvider {} 2.AndroidManife ...

  9. android在主程序中调用图片,009android初级篇之APP中使用系统相机相册等集成应用...

    009android初级篇之APP中使用系统相机相册等集成应用 android应用中使用相机功能,大致有两种方式实现: 直接调用系统内部的相机程序,显示的也是系统预设的界面(简单,只有简单的拍照功能) ...

  10. android 相机拍照返回,Android6.0机型上调用系统相机拍照返回的resultCode值始终等于0的问题...

    版权声明:本文为博主原创文章,未经博主允许不得转载. 正常情况下调用系统相机拍照: 如果拍照后点击的是"确定"图标,返回的resultCode = -1(Activity.RESU ...

最新文章

  1. 一起谈.NET技术,asp.net控件开发基础(20)
  2. 控制器描述者(ControllerDescriptor),行为方法描述者(ActionDescriptor),参数描述者(ParameterDescriptor)的小结...
  3. WPF自定义控件的三种方式
  4. 看Kubernetes源码,学习怎么用Go实现调度队列
  5. Java基础学习总结(160)——JDK15正式发布,划时代的ZGC同时宣布转正
  6. 18 张图彻底弄懂 HTTPS 的原理!
  7. SharePoint:扩展DVWP - 第8部分:挂接了工作流列表表单操作
  8. boot客户管理系统源码_开源 SpringBoot+vueJs 前后端管理系统模版
  9. C向Python传递数组和List参数
  10. 解锁lintcode数字图像识别
  11. 基于3DGIS+BIM的房屋出售管理系统
  12. ZXing条码扫描----竖屏解决方案
  13. linux系统支持什么输入法,Linux系统常用输入法框架
  14. 差分放大电路及动态分析
  15. 【DBC专题】-4-DBC文件中的Signal信号字节顺序Motorola和Intel介绍
  16. 关于PCB的机械层和差分布线、RC滤波
  17. 回文树/回文自动机 引入
  18. rsync 同步本地文件到远端
  19. ibm aix 抓包命令_在IBM AIX上模拟丢弃的TCP / IP数据包
  20. 04-0006 MATLAB 弹幕壁纸

热门文章

  1. 在线文本比较工具及查询工具
  2. element-ui table自定义斑马条纹颜色
  3. 界面设计的八条黄金法则
  4. Googlr VR SDK
  5. HCIP第十八天笔记
  6. 树言树语 金山毒霸宣布免费, 用意何在
  7. usb启动计算机boss设置方法,教程方法;U盘装系统中bios设置USB启动图文教程电脑技巧-琪琪词资源网...
  8. Jolicloud是一款适合上网本的漂亮新操作系统
  9. iMail Basic 更新日志
  10. java中config是什么意思,详解Spring中的JavaConfig注解