详细介绍:FileProvider 配置必须针对 Android 7.0+(API 24+)做兼容

news/2025/10/4 12:41:47/文章来源:https://www.cnblogs.com/wzzkaifa/p/19125489

这个 FileProvider 配置必须针对 Android 7.0+(API 24+)做兼容,否则在 Android 7.0 及以上版本中,通过 file:// 路径访问文件会触发 FileUriExposedException 异常。结合你当前的项目(已适配 Android 10+),需要进一步完善 FileProvider 的配置,确保文件访问在全版本兼容。

一、为什么需要兼容?

Android 7.0 开始引入 StrictMode 安全策略,禁止应用通过 file:// 格式的 Uri 向其他应用暴露文件(如调用系统相机拍照、分享文件等场景),必须使用 content:// 格式的 Uri 替代,而 FileProvider 就是系统提供的用于生成 content:// Uri 的工具类。

你的现有配置已经有了 FileProvider 基础,但还需要补充两点:

  1. 完善 provider_paths.xml 配置(指定可共享的文件路径,适配 Android 10+ 分区存储);
  2. 在代码中通过 FileProvider 生成 Uri(替代直接使用 new File(...) 生成 file:// Uri)。

二、第一步:完善 provider_paths.xml 配置

首先在 res/xml/ 目录下创建 / 修改 provider_paths.xml必须包含 Android 10+ 分区存储下的共享路径(如应用私有目录、媒体库目录),否则高版本系统会提示 “无法访问文件”。

xml



配置说明:

路径标签对应实际路径用途
cache-path应用私有缓存目录临时文件(如缓存图片),无需权限
files-path应用私有文件目录持久化文件,无需权限
external-files-path应用外部私有目录(如 Download)Android 10+ 推荐,无需权限
external-path外部存储公共目录旧版本(Android 9-)访问公共文件
external-media-path媒体库目录Android 10+ 访问图片 / 视频 / 音频

三、第二步:修复 AndroidManifest.xml 中的 FileProvider 配置

你的现有配置中 android:authorities 建议补充包名后缀(避免与其他应用冲突),同时确保 meta-data 的 name 正确(兼容 AndroidX):

xml

android:authorities="com.nyw.anmoapp.fileprovider"android:exported="false"android:grantUriPermissions="true">android:resource="@xml/provider_paths" />

关键修改:

  • android:authorities:从 com.nyw.anmoapp 改为 com.nyw.anmoapp.fileprovider(更规范,避免冲突);
  • 确保 android:exported="false"(禁止外部应用直接访问,必须通过权限授予);
  • android:grantUriPermissions="true"(允许临时授予其他应用访问文件的权限)。

四、第三步:在代码中使用 FileProvider 生成 Uri(核心兼容逻辑)

在需要向其他应用暴露文件的场景(如调用系统相机拍照、打开本地文件、分享文件),必须通过 FileProvider.getUriForFile() 生成 content:// Uri,替代旧的 file:// Uri。

以下是 3 个常见场景的兼容代码示例:

场景 1:调用系统相机拍照(保存到应用私有目录)

java

运行

/*** 调用系统相机拍照(适配 Android 7.0+)*/
private void takePhotoWithCamera() {// 1. 创建保存照片的文件(存到应用私有缓存目录,无需权限)File photoFile = new File(getCacheDir(), "temp_photo.jpg");try {if (photoFile.exists()) {photoFile.delete();}photoFile.createNewFile();} catch (IOException e) {e.printStackTrace();return;}// 2. 生成 Uri(Android 7.0+ 用 FileProvider,低版本直接用 file://)Uri photoUri;if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {// 注意:authorities 必须和 Manifest 中配置的一致photoUri = FileProvider.getUriForFile(this,"com.nyw.anmoapp.fileprovider", // 与 Manifest 中的 android:authorities 对应photoFile);// 授予临时权限(允许相机应用访问该 Uri)grantUriPermission("com.android.camera", // 目标应用包名(相机)photoUri,Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);} else {// Android 7.0 以下直接用 file:// UriphotoUri = Uri.fromFile(photoFile);}// 3. 启动相机Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);startActivityForResult(intent, 1001); // 1001 为拍照请求码
}

场景 2:打开本地文件(如 PDF、TXT)

java

运行

/*** 打开本地文件(适配 Android 7.0+)* @param file 要打开的文件*/
private void openLocalFile(File file) {if (!file.exists()) {Toast.makeText(this, "文件不存在", Toast.LENGTH_SHORT).show();return;}// 1. 生成 UriUri fileUri;if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {fileUri = FileProvider.getUriForFile(this,"com.nyw.anmoapp.fileprovider",file);} else {fileUri = Uri.fromFile(file);}// 2. 配置文件打开意图Intent intent = new Intent(Intent.ACTION_VIEW);intent.setDataAndType(fileUri, getMimeType(file.getAbsolutePath())); // 获取文件 MIME 类型intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);// 授予临时权限(允许目标应用访问该 Uri)intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);// 3. 启动应用打开文件try {startActivity(intent);} catch (ActivityNotFoundException e) {Toast.makeText(this, "没有找到可打开该文件的应用", Toast.LENGTH_SHORT).show();}
}
/*** 获取文件 MIME 类型*/
private String getMimeType(String filePath) {String type = null;String extension = MimeTypeMap.getFileExtensionFromUrl(filePath);if (extension != null) {type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase());}return type;
}

场景 3:配合 HttpUtils 下载文件后打开

在 HttpUtils 的 DownloadProgressListener 中,通过 FileProvider 打开下载的文件:

java

运行

HttpUtils.getInstance().download("https://example.com/test.pdf","Download","test.pdf",new HttpUtils.DownloadProgressListener() {@Overridepublic void onProgress(int progress) {// 进度更新}@Overridepublic void onSuccess(String filePath) {// 下载完成,打开文件File downloadFile = new File(filePath);openLocalFile(downloadFile); // 调用上面的 openLocalFile 方法}@Overridepublic void onFail(String errorMsg) {Toast.makeText(MainActivity.this, errorMsg, Toast.LENGTH_SHORT).show();}}
);

五、第四步:Android 10+ 特殊兼容(分区存储)

如果你的文件需要保存到外部存储公共目录(如 /storage/emulated/0/Download/),在 Android 10+ 中还需要注意:

  1. 若使用 MediaStore 保存媒体文件(图片 / 视频 / 音频),无需 WRITE_EXTERNAL_STORAGE 权限,直接通过 ContentResolver 插入即可;
  2. 若保存非媒体文件(如 PDF、TXT),在 Android 10+ 中需通过 SAF(存储访问框架) 让用户选择保存位置,或使用应用私有目录(推荐)。

总结:必须兼容的核心点

  1. provider_paths.xml 必须包含全版本路径:覆盖应用私有目录、外部存储目录、媒体库目录;
  2. Manifest 中 authorities 必须唯一:建议用 “包名 + .fileprovider” 格式;
  3. 代码中必须区分版本生成 Uri:Android 7.0+ 用 FileProvider,低版本用 Uri.fromFile
  4. 必须授予临时权限:通过 grantUriPermission 或 Intent.FLAG_GRANT_READ_URI_PERMISSION 允许其他应用访问文件。

这样配置后,你的 FileProvider 就能在 Android 7.0 到 Android 14+ 全版本中正常工作,避免 FileUriExposedException 等兼容性问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/927139.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

题解:P14124 [SCCPC 2021] Nihongo wa Muzukashii Desu

P14124 题解 题目传送门 题意简化 给你 \(n\) 个字符串,根据字符串的后缀按要求更改字符串。 题目分析 一般的转换规则可以分为 5 种,如下表。后缀类型 更改后chimasu tterimasu ^mimasu ndebimasu ^nimasu ^kimasu …

网站上传在空间哪里女孩子奖励自己的资料

🐌博主主页:🐌​倔强的大蜗牛🐌​ 📚专栏分类:C❤️感谢大家点赞👍收藏⭐评论✍️ 目录 一、Static成员 1、概念 2、特性 二、友元 1、友元函数 2、友元类 一、Static成员 1、概念 声…

怎么查看网站是用什么编程语言开发的gta5买房网站建设中

央视网(www.cctv.com)视频下载往往是花屏的,如何处理呢? 如果您是IT技术开发者,那么您可以通过下面步骤自己实现。 用chrome浏览器,F2打开开发者工具,找到当前页面的network 然后找一个接口:https://vdn.a…

上位机知识篇---服务器脚本一直运行方法 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

个人网站域名取名chenqinghua wordpress

题目描述: 小红拿到了一个数组,初始数组为空,她希望你实现以下两种操作: 1. 输入x,y,将x插入在元素y的右边。保证此时数组中没有元素等于x,且数组中存在一个y。特殊的,如果将x插入在数组的最左边&#xff0…

python+vue在线视频课程学习系统设计(源码+文档+调试+基础修改+答疑) - 详解

python+vue在线视频课程学习系统设计(源码+文档+调试+基础修改+答疑) - 详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-fa…

DeepSeek V3.1-Terminus、阿里 Qwen3-Max、ChatGPT Pulse 同周登场!| AI Weekly 9.22-9.28 - 实践

DeepSeek V3.1-Terminus、阿里 Qwen3-Max、ChatGPT Pulse 同周登场!| AI Weekly 9.22-9.28 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block …

wejianzhan是什么网站企业解决方案参考网站

背景:写的算法合并到项目组代码,编译发现一些以前没积累过的错误,这里记录下,也供大家参考。 一、问题1 // 每个类都有单独的.h .cpp class A; class B : public A {// ... }; class C : public A {// ... };若在B.h中引用了一个…

网站建设修饰商品wordpress批量导入页面

文章目录 🍋引言🍋队列的定义🍋队列的实现🍋队列的应用🍋练习题🍋结语 🍋引言 队列(Queue)是计算机科学中一种重要的数据结构,它常用于各种应用程序中&#x…

公司做了网站怎么做推广本地做织梦网站

原文来自http://note.youdao.com/share/web/file.html?id236896997b6ffbaa8e0d92eacd13abbf&typenote 我怕链接会失效,故转载此篇文章。通过这篇文章,我对之前疑惑的地方有了直观的理解,很多地方并没有自己动手实践,所以这篇…

【做题记录】CF2600左右有趣的思维题1

A. Latin Square 考虑维护三元组 \((i,j,a_{i,j})\)。例如:R 操作就是变成了 \((i,j+1,a_{i,j})\);I 操作就是变成了 \((i,a_{i,j},j)\)。时间复杂度 \(O(m+n^2)\)。Code #include<bits/stdc++.h> #define ll …

pdf翻译

pdf翻译 https://github.com/Byaidu/PDFMathTranslate?tab=readme-ov-file

OpenEuler 25.03 installed UKUI but cant run msedge and chrome

[root@OpenEulerWD Desktop]# pwd /root/Desktop[root@OpenEulerWD Desktop]# cat google-chrome.desktop microsoft-edge.desktop | grep stable Exec=/usr/bin/google-chrome-stable %U Exec=/usr/bin/google-chrom…

网站为什么被百度k了关于wordpress更新时无法创建目录

Spring Boot 注解 PostConstruct 介绍 文章目录 Spring Boot 注解 PostConstruct 介绍一、基本介绍二、PostConstruct 的执行时机Spring Bean 的生命周期PostConstruct 的确切执行时机执行顺序示例重要注意事项 三、使用场景及代码示例1. 初始化资源&#xff1a;比如打开数据库…

实用指南:iPhone美区账号登录指南:轻松下载ChatGPT应用

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

德国诺莫斯手表网站电子商务网站建设与管理习题答案

http://www.imooc.com/article/285246?block_idtuijian_wz 最近在设计一款进销存系统的时候&#xff0c;遇到一个分类的设计问题&#xff0c;就是如何将分类设计成数据库里的表&#xff0c;怎么样设计才比较灵活&#xff1f; 举个例子&#xff0c;一级分类&#xff1a;生鲜类&…

推广方案怎么写模板网站内容seo

汇川Easy系列以太网通讯中(MODBUSTCP,plc做主站),终于可以不用使用指令就可以完成了,全程通过简单的配置就可通讯。本文将通过EASY系列PLC与调试助手之间完成此操作。具体演示如下; 关于主站和从站的介绍 A/请求:即主动方 向被动方发送的一个要求的信息。 B/主站:发…

网络调整config.xml的android.mk解析

网络调整config.xml的android.mk解析pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monac…