You need to enable JavaScript to run this app. 如何使用MediaStore读取或打开已下载的.apk文件?
优惠活动
大模型
产品
解决方案
定价
更多

如何使用MediaStore读取或打开已下载的.apk文件?

MediaStore实现下载目录APK读取及MD5计算的适配方案

Android 10强制启用分区存储后,直接通过文件路径操作公共下载目录的方式会被系统拦截,也就是你遇到的权限拒绝异常。核心适配思路是完全替换原来的File路径访问逻辑,通过MediaStore的下载集合接口查询目标APK,直接通过Uri拿到文件输入流完成MD5计算,全程不需要接触真实文件路径,就能完全对齐你原来的业务逻辑。

版本分支适配

按照系统版本做兼容拆分,避免低版本走冗余的MediaStore查询逻辑:

  • Android 10(API 29)及以上:走MediaStore.Downloads集合查询流程,绕过分区存储限制
  • Android 9(API 28)及以下:保留原有File读取逻辑即可,这类版本没有强制分区存储,原代码不会触发权限问题

对齐原有逻辑的Kotlin实现

替换原来直接构造File读取的代码块,整体流程和你原有的try-catch容错、按固定路径找指定安装包、计算MD5的逻辑完全一致:

// 保留你项目中原有的安装包文件名常量
private const val INSTALLER_NAME = "目标安装包文件名.apk"

fun getDownloadApkMd5(context: Context): String? {
    // 低版本直接走原有逻辑
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
        return try {
            File(
                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
                INSTALLER_NAME
            ).md5()
        } catch (e: Exception) {
            Timber.e(e)
            null
        }
    }

    // Android 10及以上走MediaStore查询
    val downloadUri = MediaStore.Downloads.EXTERNAL_CONTENT_URI
    // 查询条件:匹配完全一致的显示文件名
    val selection = "${MediaStore.Downloads.DISPLAY_NAME} = ?"
    val selectionArgs = arrayOf(INSTALLER_NAME)

    var targetMd5: String? = null
    try {
        context.contentResolver.query(
            downloadUri,
            arrayOf(MediaStore.Downloads._ID),
            selection,
            selectionArgs,
            null
        )?.use { cursor ->
            if (cursor.moveToFirst()) {
                val fileId = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Downloads._ID))
                val targetFileUri = ContentUris.withAppendedId(downloadUri, fileId)
                // 直接打开输入流计算MD5,不需要转成File对象
                context.contentResolver.openInputStream(targetFileUri)?.use { input ->
                    targetMd5 = input.md5()
                }
            }
        }
    } catch (e: Exception) {
        Timber.e(e)
    }
    return targetMd5
}

关键注意点

  • 不要尝试把MediaStore返回的Uri转成本地File绝对路径:这类转换在分区存储下基本都会触发权限问题,通过Uri打开的输入流已经完全支持文件读取、计算MD5的操作,没有额外的功能损失
  • 如果查询不到匹配的文件:检查文件名匹配条件,部分应用下载文件时会在临时文件阶段加.tmp后缀,完成写入后才会改成正式APK名,可以适当调整查询条件做模糊匹配
  • 权限适配:Android 13及以上读取公共下载目录内容时,只要应用声明了对应版本的基础存储读取权限即可,不需要申请高危的全文件访问权限,就能完成对Downloads集合的常规读取操作

内容的提问来源于stack exchange,提问作者Andreas1234

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.13 13:06:06