Android 7.0及以上打开相机,裁剪问题(私有文件的访问权限,兼容小米)

H5端跨平台二维码扫描方案:兼容WebView与原生浏览器的实践探索 本文深入探讨H5端跨平台二维码扫描方案,解决WebView与原生浏览器兼容性问题。通过环境检测、能力分级和多环境适配策略,实现高效二维码解析,提升用户体验。涵盖摄像头调用、图片上传解析等关键技术,为开发者提供实用解决方案。 阅读详情

在Android7.0之前,如果你想调用系统相机拍照可以通过以下代码来进行:

File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg");
if (!file.getParentFile().exists())file.getParentFile().mkdirs();
Uri imageUri = Uri.fromFile(file);
Intent intent = new Intent();
//设置Action为拍照
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
//将拍取的照片保存到指定URI
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent,1);

但是在android 7.0之后的手机上用以上代码打开相机、相册会报如下错误:

android.os.FileUriExposedException: ** exposed beyond app through Intent.getData()

原因:
在Android7.0系统上,Android 框架强制执行了 StrictMode API 政策禁止向你的应用外公开 file:// URI。 如果一项包含文件 file:// URI类型 的 Intent 离开你的应用,应用失败,并出现 FileUriExposedException 异常,如调用系统相机拍照,或裁切照片。

解决方法:
官方的解决方法(https://developer.android.google.cn/training/secure-file-sharing/setup-sharing.html)

1、在manifest清单文件中注册provider

<provider
      android:name="android.support.v4.content.FileProvider"
      android:authorities="包名.fileprovider"
      android:grantUriPermissions="true"
      android:exported="false">
      <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths" />
</provider>

也就是在application内加了一个provider:

  • name是固定的;
  • android:authorities推荐写您的应用包名+“.fileprovider”,其实这里不一定要写fileprovider,您也可以随便写,只要与后面使用FileProvider.getUriForFile()这个方法中的第二个参数authority对应起来即可;
  • android:grantUriPermissions固定true,表示uri访问授权;
  • android:exported固定的false,我试着写了true报安全异常。
  • android:resource表示我们app要共享文件的路径的资源文件。

2.res文件夹下,新建一个xml文件夹,名字就是上一步 android:resource=”@xml/file_paths”对应的内容

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <paths>
        <external-path path="" name="camera_photos" />
    </paths>
</resources>

为了指定访问的目录我们需要在资源(res)目录下创建一个xml目录

  • 命名为“file_paths”(名字可以随便起,只要和第一步中在manifest注册的provider所引用的resource保持一致即可)的资源文件。
  • 上述代码中 path=”“,是有特殊意义的,它指的是根目录,也就是说您可以向其它的应用访问根目录及其子目录下任何一个文件了,如果您将path设为 path=”pictures”,那么它代表着根目录下的pictures目录(eg:/storage/emulated/0/pictures),这时您访问pictures目录范围之外的文件是不行的。
  • files-path代表的根目录: Context.getFilesDir()
  • external-path代表的根目录: Environment.getExternalStorageDirectory()
  • cache-path代表的根目录: getCacheDir()

3.使用FileProvider

上述准备工作做完之后,现在我们就可以使用FileProvider了。
还是以调用系统相机拍照为例,我们需要将上述拍照代码修改为如下:

    /*
     *相册,选择一张图片
     */
    private void getPhoto(Context context) {
        // 这里用时间命名是发现用固定名命名后第二次裁剪图片任然是第一次的图,没有覆盖上一次图片资源;7.0之前固定名会替换
        File file = new File(Environment.getExternalStorageDirectory(), "/temp/" + System.currentTimeMillis() + ".jpg");
        if (!file.getParentFile().exists()) file.getParentFile().mkdirs();
        // 通过FileProvider创建一个content类型的Uri
        Uri imageUri = FileProvider.getUriForFile(context, "包名.fileprovider", file);
        Intent intent = new Intent();
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        // 设置Action为拍照
        intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
        // 将拍取的照片保存到指定URI
        intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
        // 开启一个带有返回值的Activity,请求码为PHOTO_REQUEST_GALLERY
        startActivityForResult(intent, MainActivity.PHOTO_REQUEST_GALLERY);
    }

上述代码通过FileProvider的Uri getUriForFile (Context context, String authority, File file)
静态方法来获取Uri,该方法中authority参数就是清单文件中注册provider的android:authorities=”包名.fileprovider”。

裁剪图片同理,修改后:

  /*
    * 剪切图片
    */
    private void crop(String path, int outWith, int outHeight) {
        File file = new File(path);
        if (!file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }
        Uri uri;

        // 裁剪图片意图
        Intent intent = new Intent("com.android.camera.action.CROP");

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
            //添加这一句表示对目标应用临时授权该Uri所代表的文件
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            //通过FileProvider创建一个content类型的Uri
            uri = FileProvider.getUriForFile(this, "包名.fileProvider", file);
        } else{
            uri = Uri.fromFile(file);
        }

        intent.setDataAndType(uri, "image/*");
        intent.putExtra("crop", "true");
        // 裁剪框的比例,1:1
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        // 裁剪后输出图片的尺寸大小
        intent.putExtra("outputX", outWith);
        intent.putExtra("outputY", outHeight);

        // 图片格式
        intent.putExtra("outputFormat", "JPEG");
        // 取消人脸识别
        intent.putExtra("noFaceDetection", true);

        /**
         * 此方法返回的图片只能是小图片(测试为高宽160px的图片)
         * 故将图片保存在Uri中,调用时将Uri转换为Bitmap,此方法还可解决miui系统不能return data的问题
         */
        //intent.putExtra("return-data", true); // 重点:小米的系统这个会使返回数据为null,改为下面方法传递数据

        //uritempFile为Uri类变量,实例化uritempFile
        uritempFile = Uri.parse("file://" + "/" + Environment.getExternalStorageDirectory().getPath() + "/" + "small.jpg");
        intent.putExtra(MediaStore.EXTRA_OUTPUT, uritempFile);
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());

        // 开启一个带有返回值的Activity,请求码为PHOTO_REQUEST_CUT
        startActivityForResult(intent, MainActivity.PHOTO_REQUEST_CUT);
    }

然后在你的onActivityResult回调中这样接收

if (requestCode == V3MainActivity.PHOTO_REQUEST_CUT) {
            //将Uri图片转换为Bitmap
            try {
                Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uritempFile));
                //TODO 将获取的bitmap展示在你的控件上
            } catch (FileNotFoundException e) {
                ToastUtils.showShort("未找到裁剪图片");
            }
}

ps:另外发现严苛模式(StrictMode)也可以避免这个FileUriExposedException问题,在您的Application中OnCreate()方法中加入以下代码即可。这样您可以按照7.0之前方法调用相机。

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
            StrictMode.setVmPolicy(builder.build());
        }

但毕竟这方法不是官方推荐的,所以知道就行,不建议使用。

更新:

我们会发现拍照出来的照片在手机相册中没有显示出来,而自己去翻文件夹却又能够找到该照片,这时想要在手机相册中显示刚拍摄的图片需要在回调函数里加入如下代码,发送个广播通知系统。

//在手机相册中显示刚拍摄的图片
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri contentUri = Uri.fromFile(file);
mediaScanIntent.setData(contentUri);
sendBroadcast(mediaScanIntent);

参考:
官方推荐解决方案
Android 7.0手机打开相机或相册报错解决方案
Android 7.0 文件读取适配,及适配相机及裁剪图片
严苛模式


为了向别人、向世界证明自己而努力拼搏,而一旦你真的取得了成绩,才会明白:人无须向别人证明什么,只要你能超越自己。

LilyGO T-Watch学习(一)环境搭建,编译下载 1、安装arduino IDE, 安装后按照说明添加lib IDE上选择“项目->加载库->添加.ZIP库”,选择C:\Users\用户名\Documents\Arduino\libraries\下的TTGO_TWatch_Library-master.zip; 查看是否添加成功: 项目->加载库,滑到最后可看见已添加的TTGO... 参考:https://github.com/Xinyuan-LilyGO/TTGO_TWatch_Library 2、安装esp32 ardui 阅读详情

相关推荐

论文选题难?7种AI加持的万能选题法(全专业通用+工具实测)

AI时代学术选题新范式:7大智能方法破解研究痛点 传统选题方法面临范围失控、资料难寻、创新不足三大痛点,本文提出AI赋能的7种选题方法论: 1.现象+群体法:自动抓取热点与人群特征 2.理论+场景法:经典理论与新兴场景匹配 3.技术+问题法:前沿技术与领域痛点结合 4.对比+变量法:时空维度与变量关系分析 5.热点+理论法:事件传播与理论深挖融合 6.微调+变量法:已有选题变量置换创新 7.AI全流程法:关键要素智能迭代生成 同时警示AI使用的伦理边界,需规避虚构文献、伪造数据等风险,并提供针对本科生、研究

Conan_0728的博客 1876

Android中com.android.camera.action.CROP(图片裁剪)所有属性

Exta Options Table for image/* crop: 附加选项 数据类型 描述 crop String 发送裁剪信号 aspectX int X方向上的比例 aspectY int Y方向上的比例 outputX int 裁剪区的宽 outputY int 裁剪区的高

猿子 1万+

算法面经手撕系列(2)--手撕BatchNormlization

手动实现/手撕BatchNormlization

罟霖同学的站点 865

安卓系统-图片裁剪 com.android.camera.action.CROP

调用安卓系统进行图片裁剪问题,在此记录! 遇到的问题: 1、裁剪框形状问题 方形-设置比例为1:1时为圆型,其它为方形。 2、裁剪宽高异常问题-aspect和output设置的是312:200 结果显示的是 200:312,导致图片被拉伸变形,只需要设置aspect,不设置output,这样系统的裁剪比例是固定的。 3、裁剪后白屏问题-return-data 设置为false,添加MediaStore.EXTRA_OUTPUT,保存到自定义路径。 public void cropPhoto(.

asia_mrli的博客 3352

FPGA音频处理入门:手把手教你用Verilog实现I2S接收模块(附完整代码)

本文详细介绍了如何使用Verilog在FPGA上实现I2S接收模块,涵盖I2S协议原理、Verilog架构设计、完整代码实现及优化技巧。通过实战案例,帮助开发者快速掌握数字音频处理技术,适用于嵌入式音频系统开发。

weixin_30335575的博客 417

esp32移植canopen协议栈(二)

本文续接上一篇文章,之前我们已经搭建好了esp32的开发环境,以及初始工程。接下来我们开始实现can驱动相关,以及使用c++封装can接口。本文使用esp32实现c++实现can驱动层的封装。下一步移植canopen!!!嘻嘻。

qq_50267418的博客 1905

关于Android实现裁剪功能总结

总结如何实现Android中的图片裁剪效果

superxlcr的博客 7515

比Synergy更轻量!Barrier鼠标共享工具实测:5分钟实现Win/Mac/Linux三设备无缝切换

本文实测了开源免费的Barrier鼠标共享工具,详细指导用户如何在5分钟内于Windows、macOS和Linux三台设备间实现一套键鼠的无缝切换。文章对比了其与Synergy的优势,提供了分平台安装、核心服务端-客户端配置、防火墙设置等完整教程,并分享了解决连接问题的关键技巧,是提升多设备办公效率的实用指南。

weixin_29304021的博客 594

android crop 大图,com.android.camera.action.CROP 实现图片剪裁

APP 中选取图片之后,有时候需要进行剪裁,比如头像。以下是启动代码。在我的项目中,传的是 filePath,所以我转了一下,但实际上从相册选择图片后,用 data.getData() 就可获得 uri。Uri uri = Uri.fromFile(new File(filePath));Intent intent = new Intent("com.android.camera.action.C...

weixin_29191761的博客 972

Sentinel--哨兵系列数据下载地址及流程更新【202310】

哨兵系列数据下载地址及流程更新。哨兵系列卫星作为哥白尼计划的一部分,主要目标便是对地球的观测任务。哥白尼计划由三部分组成:空间部分(哨兵系列太空任务与其他太空机构任务)、测量部分(提供海洋、大陆表面和大气信息的陆基和机载数据收集网络)、数据管理与全球共享。

twg666的博客 3万+

深入CARLA地图底层:OpenDRIVE文件如何影响你的仿真效果与避坑指南

本文深入解析CARLA仿真中OpenDRIVE地图文件的核心作用,揭示其如何影响车道连接、交通规则和导航逻辑。通过实战案例和代码示例,提供五大典型地图问题的诊断与修复方案,帮助开发者优化仿真效果并规避常见陷阱。

weixin_34180452的博客 276

Android 7.0 系统相机崩溃解决android.os.FileUriExposedException

最近市场开始强行要求适配7.0,无奈之下发现不少好文章,特此收藏记录。

mackkill的专栏 4276

华为校招实习机试&华为社招机试20240619-2.排列组合的回文字符串[200分]( Java | Python3 | C++ | C语言 | JsNode | Go)实现100%通过率

如果一个字符串和它反转后的字符串相同,我们称这个字符串为回文字符串,如"aba"是一个回文字符串,"abb"不是一个回文字符串(长度为1的字符串也是回文字符串)。现给定一个字符串,其长度范围为:[1,1000),返回其通过重新排列组合后所有可能的回文字符串的个数(需要去除重复的组合)。返回其通过重新排列组合后所有可能的回文字符串的个数,去除重复的组合后的回文字符串是"abba","baab",因此返回2。解释:排列组合后的回文字符串是"abba" , "baab",因此结果为2。

算法算法算法!!! 829

调用Android 7.0系统摄像头的正确姿势

今日科技快讯 近日,AcFun(A站)美剧几乎全部被下架,连美剧专区都被撤了,大量字幕组翻译的各类美剧也不再更新,网友直呼“最后的净土”遭“沦陷”。A站客服表示,因涉及版权问题,AcFun相关资源目前正在整改中,具体恢复时间尚未确定。

郭霖 1079

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Android FileProvider详细解析和踩坑指南

详细梳理一下android的文件系统,以及做一下FileProvider的解析。

wxz的博客 14万+

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

Android 7.0 调取系统相机崩溃解决android.os.FileUriExposedException

该文章同步发表到博客园:http://www.cnblogs.com/liushilin/p/6602364.html 一、写在前面      最近由于廖子尧忙于自己公司的事情和OkGo(一款专注于让网络请求更简单的网络框架) ,故让LZ 接替维护ImagePicker(一款支持单、多选、旋转和裁剪的图片选择器),也是处理了诸多bug,最近总算趋于稳定了,这里就把Android N (

刘世麟的博客 747

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

Android N 7.0 应用间共享文件(FileProvider)

Android N 之前的 Uri 常规Uri有两种: 媒体文件的Uri是content://, 表示这是一个数据库数据。去数据库查询正常返回。 其他的文件Uri是file://, 表示这个是一个文件。这个uri是通过Uri.fromFile(File file)方法生成。 Android N 之前,这些uri可以传递到其他应用。 Android N 中共享文件 Android

薛瑄的博客 13万+

【适配整理】Android 7.0 调取系统相机崩溃解决android.os.FileUriExposedException

目录 一、写在前面二、到底是什么引发了 7.0 相机崩溃三、为什么在 Android Nougat 下 file:// 不被允许?四、那到底怎么解决?五、几点说明六、写在最后   正文 回到顶部 一、写在前面      最近由于廖子尧忙于自己公司的事情和 OkGo (一款专注于让网络请求更简单的网络框架) ,故让LZ 接替维护 ImagePicker(一款支

AIFBD 789

Android 7.0 调用系统相机崩溃解决 android.os.FileUriException

转自南尘:点击打开链接 写在前面 最近由于廖子尧忙于自己公司的事情和 OkGo (一款专注于让网络请求更简单的网络框架) ,故让LZ 接替维护 ImagePicker(一款支持单、多选、旋转和裁剪的图片选择器),也是处理了诸多bug,最近总算趋于稳定了,这里就把 Android N (API 24) 以上的相机适配方案分享给大家。   Android No

BillyLu的博客 1568

android 7.0以上共享文件(解决调用系统照相和图片剪切出现的FileUriExposedException崩溃问题)...

   在android7.0开始试共享“file://”URI 将会导致引发 FileUriExposedException。 如果应用需要与其他应用共享私有文件,则应该使用 FileProvider, FileProvider的 getUriForFile() 方法可以产生一个文件的content URI, FLAG_GRANT_READ_URI_PERMISSION,FLAG_GRANT_WR...

weixin_34150224的博客 120

Android的FileProvider使用解释

FileProvider是android support v4包提供的,是ContentProvider的子类,便于将自己app的数据提供给其他app访问。

Jason_Lee155的博客 19万+

Gemini安卓版为何没有官方APK下载?深度解析Play Integrity校验机制

Gemini并非传统独立APP,而是依托谷歌云服务与设备端协同的AI服务架构。其核心原理在于服务端大模型推理+本地轻量界面+Play Integrity动态设备校验,技术价值体现在安全可控、隐私合规与跨端一致。典型应用场景包括语音交互、图像理解、代码生成等,但所有功能均以设备完整性认证为前提。当用户搜索‘Gemini安卓APK官方下载’时,实际面临的是系统级准入限制而非分发缺失——关键卡点正是Play Integrity API的三重验证(设备可信性、账户资格、区域策略),这也解释了为何手动安装APK普遍遭

weixin_33720078的博客 3807
上一篇: android应用数据清除管理器
下一篇: DrawerLayout NavigationView 实现侧滑(Android MD风格一)
皮小智
博客等级 码龄10年 56粉丝 34原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值