You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 07:06:07