如何通过Intent分享应用base.apk 解决FileUriExposedException报错
问题根因
Android 7.0(API 级别24)开始系统强制启用私有文件访问限制,跨应用传递file://格式的文件Uri会直接抛出FileUriExposedException,你前后两次实现报错都是因为用Uri.fromFile()生成了被系统禁止的file类型Uri,没有走官方要求的FileProvider机制。
可行实现步骤
1. 在清单文件声明FileProvider
打开项目的AndroidManifest.xml,在<application>标签内添加FileProvider配置,注意authorities字段值要和后续代码中使用的值完全一致,推荐直接用应用包名拼接后缀的格式避免冲突:
<application <!-- 你原有的application标签属性,比如icon、label、theme等保持不变 --> > <!-- 你原有的activity、service等组件声明保持不变 --> <provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> </application>
2. 配置可分享的文件路径
在项目res目录下新建xml子目录,在该目录下创建file_paths.xml文件,配置允许对外分享的文件路径。你当前逻辑是把apk复制到公共Download目录,配置如下即可:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 允许分享公共Download目录下的文件 --> <external-path name="download_files" path="Download/" /> <!-- 如果后续想跳过复制步骤直接分享原base.apk,新增下面这行配置即可 --> <root-path name="app_source" path="." /> </paths>
3. 修正分享逻辑代码
核心修改点有三个:
- 替换
Uri.fromFile()为FileProvider.getUriForFile(),生成系统允许的content://格式Uri - 给分享Intent添加
FLAG_GRANT_READ_URI_PERMISSION标记,授予接收方临时读取文件的权限 - 增加文件存在判断、流自动关闭逻辑,避免旧文件冲突、资源泄漏问题
修正后的完整可运行代码:
try { val pm = packageManager val ai = pm.getApplicationInfo(packageName, 0) val srcFile = File(ai.publicSourceDir) // 准备目标存储文件 val dstFile = File( Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "LogsCalculator.apk" ) // 已存在同名文件先删除,避免旧文件损坏或权限异常 if (dstFile.exists()) dstFile.delete() dstFile.createNewFile() // 复制apk文件,用Kotlin内置的use扩展自动关闭流,避免异常场景下资源泄漏 srcFile.inputStream().use { input -> dstFile.outputStream().use { output -> input.copyTo(output, bufferSize = 1024) } } // 生成合法的分享Uri val shareFileUri = FileProvider.getUriForFile( this, "${packageName}.fileprovider", // 和清单文件中配置的authorities保持一致 dstFile ) // 构建分享Intent val shareIntent = Intent(Intent.ACTION_SEND).apply { type = "application/vnd.android.package-archive" putExtra(Intent.EXTRA_STREAM, shareFileUri) // 给接收分享的应用授予临时文件读权限 addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) } startActivity(Intent.createChooser(shareIntent, getString(R.string.sharing))) } catch (e: Exception) { UtilityMethods(this).toast("Failed To Share The App", "e") e.printStackTrace() }
注意事项
- 不要试图通过修改
StrictModeVmPolicy的方式绕过系统Uri检查,该方案在高版本Android系统上不生效,还会引发严重的兼容性问题 - 兼容Android 6.0及以下版本时,需要提前动态申请存储读写权限;Android 10及以上版本往公共Download目录写文件不需要申请存储权限
- 如果不需要把apk额外存到Download目录,可以直接对源base.apk文件调用
FileProvider.getUriForFile()生成分享Uri,只要在file_paths.xml里配置了对应路径即可,能省掉文件复制的耗时 authorities字段必须和清单文件中声明的完全一致,多一个字符都会抛出异常
内容的提问来源于stack exchange,提问作者Haris
相关产品推荐
相关产品推荐

