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

相关文章

Python调用Orator ORM进行数据库操作

《Python调用OratorORM进行数据库操作》OratorORM是一个功能丰富且灵活的PythonORM库,旨在简化数据库操作,它支持多种数据库并提供了简洁且直观的API,下面我们就... 目录Orator ORM 主要特点安装使用示例总结Orator ORM 是一个功能丰富且灵活的 python O

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

Deepseek R1模型本地化部署+API接口调用详细教程(释放AI生产力)

《DeepseekR1模型本地化部署+API接口调用详细教程(释放AI生产力)》本文介绍了本地部署DeepSeekR1模型和通过API调用将其集成到VSCode中的过程,作者详细步骤展示了如何下载和... 目录前言一、deepseek R1模型与chatGPT o1系列模型对比二、本地部署步骤1.安装oll

Android里面的Service种类以及启动方式

《Android里面的Service种类以及启动方式》Android中的Service分为前台服务和后台服务,前台服务需要亮身份牌并显示通知,后台服务则有启动方式选择,包括startService和b... 目录一句话总结:一、Service 的两种类型:1. 前台服务(必须亮身份牌)2. 后台服务(偷偷干

一分钟带你上手Python调用DeepSeek的API

《一分钟带你上手Python调用DeepSeek的API》最近DeepSeek非常火,作为一枚对前言技术非常关注的程序员来说,自然都想对接DeepSeek的API来体验一把,下面小编就来为大家介绍一下... 目录前言免费体验API-Key申请首次调用API基本概念最小单元推理模型智能体自定义界面总结前言最

JAVA调用Deepseek的api完成基本对话简单代码示例

《JAVA调用Deepseek的api完成基本对话简单代码示例》:本文主要介绍JAVA调用Deepseek的api完成基本对话的相关资料,文中详细讲解了如何获取DeepSeekAPI密钥、添加H... 获取API密钥首先,从DeepSeek平台获取API密钥,用于身份验证。添加HTTP客户端依赖使用Jav

Python利用自带模块实现屏幕像素高效操作

《Python利用自带模块实现屏幕像素高效操作》这篇文章主要为大家详细介绍了Python如何利用自带模块实现屏幕像素高效操作,文中的示例代码讲解详,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1、获取屏幕放缩比例2、获取屏幕指定坐标处像素颜色3、一个简单的使用案例4、总结1、获取屏幕放缩比例from

redis防止短信恶意调用的实现

《redis防止短信恶意调用的实现》本文主要介绍了在场景登录或注册接口中使用短信验证码时遇到的恶意调用问题,并通过使用Redis分布式锁来解决,具有一定的参考价值,感兴趣的可以了解一下... 目录1.场景2.排查3.解决方案3.1 Redis锁实现3.2 方法调用1.场景登录或注册接口中,使用短信验证码场

使用C/C++调用libcurl调试消息的方式

《使用C/C++调用libcurl调试消息的方式》在使用C/C++调用libcurl进行HTTP请求时,有时我们需要查看请求的/应答消息的内容(包括请求头和请求体)以方便调试,libcurl提供了多种... 目录1. libcurl 调试工具简介2. 输出请求消息使用 CURLOPT_VERBOSE使用 C