Android 调用自带相机抛FileUriExposedException异常

2023-10-29 02:40

本文主要是介绍Android 调用自带相机抛FileUriExposedException异常,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

     最近公司业务需求,做一个类似淘宝,京东的拍照搜索商品的功能,这里搜索引擎使用的是百度的AI搜图,效果整体还不错。服务端接口接收的参数是一个图片文件,这里就需要使用到Android自带相机,按照常规的用法写完后在某些手机上报错,查看log FileUriExposedException,抛出这样一个异常.

  上网查阅了资料后得知在Android 7.0以后的应用,Android 框架执行的 StrictMode API 政策禁止在您的应用外部公开 file:// URI。如果一项包含文件 URI 的 intent 离开您的应用,则应用出现故障,并出现 FileUriExposedException 异常。

   解决办法:

   Google给出的解决办法使用FileProvider ,FileProvider是v4包中一个继承ContentProvider的子类,位置是android.support.v4.content,他可以通过File创建一个content://类型的Uri而不是file://类型的Uri.

使用步骤:

1.manifest中申明FileProvider


android:name:provider你可以使用v4包提供的FileProvider,或者自定义您自己的,只需要在name申明就好了,一般使用系统的就足够了。
android:authorities:类似schema,命名空间之类,后面会用到。
android:exported:false表示我们的provider不需要对外开放。
android:grantUriPermissions:申明为true,你才能获取临时共享权限

2.res/xml中定义对外暴露的文件夹路径

在res文件夹下创建名为xml的文件夹,然后再xml文件夹下创建名为file_paths.xml(注:在manifest android:resource="@xml/file_paths"处引用此文件
)


name:一个引用字符串。

path:文件夹“相对路径”,完整路径取决于当前的标签类型。


paths节点下有很多取值:

<files-path name="name" path="path" /> 物理路径相当于Context.getFilesDir() + /path/。
<cache-path name="name" path="path" /> 物理路径相当于Context.getCacheDir() + /path/。
<external-path name="name" path="path" /> 物理路径相当于Environment.getExternalStorageDirectory() + /path/。
<external-files-path name="name" path="path" /> 物理路径相当于**Context.getExternalFilesDir(String) **+ /path/。
<external-cache-path name="name" path="path" />物理路径相当于Context.getExternalCacheDir() + /path/。

<root-path name="name" path="path" /> 物理路径相当于/path/。

3.生成content://类型的Uri

平常我们写法是这样的,在7.0后就会抛出FileUriExposedException:

File picFile = xxx;
Uri picUri = Uri.fromFile(picFile);

所以我们需要使用content来生成URL

Url  uri = FileProvider.getUriForFile(fragment.getActivity(), "com.jiemeihome.internal", getFile());


4.给Uri授予临时权限

intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);  
Intent.FLAG_GRANT_READ_URI_PERMISSION //表示可读
Intent.FLAG_GRANT_WRITE_URI_PERMISSION//表示可写

权限的添加视项目需求而定.

5.使用Intent传递Uri

项目中需要使用到相机和相册代码如下:

public static void startCarmera(Fragment fragment) {Uri uri;
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        uri = FileProvider.getUriForFile(fragment.getActivity(), "com.jiemeihome.internal", getFile());
        intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
    } else {intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(getFile()));
    }fragment.startActivityForResult(intent, RESULT_CAMERA);
}
public static void startGallery(Activity activity) {Intent intentGallery = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    activity.startActivityForResult(intentGallery, RESULT_GALLERY);
}

public static File getFile() {File newFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+ "/images/" + System.currentTimeMillis() + ".jpg");
    if (!newFile.exists()) {newFile.getParentFile().mkdirs();
    }mCurrentPhotoPath = newFile.getAbsolutePath();
    return newFile;
}

然后再onActivityResult()中处理接收返回的图片:

protected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == RESULT_OK) {if (requestCode == RESULT_CAMERA) {upload(CarmeraUtil.mCurrentPhotoPath);
        } else if (requestCode == RESULT_GALLERY && data != null) {//处理来自图库的照片
            Uri selectedImage = data.getData();
            String[] filePathColumn = {MediaStore.Images.Media.DATA};
            Cursor cursor = getContentResolver().query(selectedImage,
                    filePathColumn, null, null, null);
            cursor.moveToFirst();
            int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
            String picturePath = cursor.getString(columnIndex);
            cursor.close();
            upload(picturePath);
        }}
}
 

 

这篇关于Android 调用自带相机抛FileUriExposedException异常的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/297711

相关文章

Android 实现一个隐私弹窗功能

《Android实现一个隐私弹窗功能》:本文主要介绍Android实现一个隐私弹窗功能,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 效果图如下:1. 设置同意、退出、点击用户协议、点击隐私协议的函数参数2. 《用户协议》、《隐私政策》设置成可点击的,且颜色要区分出来res/l

Java调用Python的四种方法小结

《Java调用Python的四种方法小结》在现代开发中,结合不同编程语言的优势往往能达到事半功倍的效果,本文将详细介绍四种在Java中调用Python的方法,并推荐一种最常用且实用的方法,希望对大家有... 目录一、在Java类中直接执行python语句二、在Java中直接调用Python脚本三、使用Run

Python如何调用指定路径的模块

《Python如何调用指定路径的模块》要在Python中调用指定路径的模块,可以使用sys.path.append,importlib.util.spec_from_file_location和exe... 目录一、sys.path.append() 方法1. 方法简介2. 使用示例3. 注意事项二、imp

Android实现一键录屏功能(附源码)

《Android实现一键录屏功能(附源码)》在Android5.0及以上版本,系统提供了MediaProjectionAPI,允许应用在用户授权下录制屏幕内容并输出到视频文件,所以本文将基于此实现一个... 目录一、项目介绍二、相关技术与原理三、系统权限与用户授权四、项目架构与流程五、环境配置与依赖六、完整

Android 12解决push framework.jar无法开机的方法小结

《Android12解决pushframework.jar无法开机的方法小结》:本文主要介绍在Android12中解决pushframework.jar无法开机的方法,包括编译指令、框架层和s... 目录1. android 编译指令1.1 framework层的编译指令1.2 替换framework.ja

Android开发环境配置避坑指南

《Android开发环境配置避坑指南》本文主要介绍了Android开发环境配置过程中遇到的问题及解决方案,包括VPN注意事项、工具版本统一、Gerrit邮箱配置、Git拉取和提交代码、MergevsR... 目录网络环境:VPN 注意事项工具版本统一:android Studio & JDKGerrit的邮

Android实现定时任务的几种方式汇总(附源码)

《Android实现定时任务的几种方式汇总(附源码)》在Android应用中,定时任务(ScheduledTask)的需求几乎无处不在:从定时刷新数据、定时备份、定时推送通知,到夜间静默下载、循环执行... 目录一、项目介绍1. 背景与意义二、相关基础知识与系统约束三、方案一:Handler.postDel

C#如何调用C++库

《C#如何调用C++库》:本文主要介绍C#如何调用C++库方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录方法一:使用P/Invoke1. 导出C++函数2. 定义P/Invoke签名3. 调用C++函数方法二:使用C++/CLI作为桥接1. 创建C++/CL

Java 中的 @SneakyThrows 注解使用方法(简化异常处理的利与弊)

《Java中的@SneakyThrows注解使用方法(简化异常处理的利与弊)》为了简化异常处理,Lombok提供了一个强大的注解@SneakyThrows,本文将详细介绍@SneakyThro... 目录1. @SneakyThrows 简介 1.1 什么是 Lombok?2. @SneakyThrows

在 Spring Boot 中实现异常处理最佳实践

《在SpringBoot中实现异常处理最佳实践》本文介绍如何在SpringBoot中实现异常处理,涵盖核心概念、实现方法、与先前查询的集成、性能分析、常见问题和最佳实践,感兴趣的朋友一起看看吧... 目录一、Spring Boot 异常处理的背景与核心概念1.1 为什么需要异常处理?1.2 Spring B