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

API32+中ContentResolver读取MMS附件失效,API33该如何处理?

问题

API 32及以上版本中,使用ContentResolver读取MMS附件的原有逻辑失效。执行以下代码时:

val partURI = Uri.parse("content://mms/part/$partId")
val inputStream = context.contentResolver.openInputStream(partURI)

inputStream?.let { inputStream2 ->
    val file = File(context.getExternalFilesDir(null), fileName)
    FileOutputStream(file).use { outputStream ->
        val buffer = ByteArray(1024)
        var read: Int
        while (inputStream.read(buffer).also { read = it } != -1) {
            outputStream.write(buffer, 0, read)
        }
    outputStream.flush()
    }
}
inputStream?.close()

抛出异常:java.io.FileNotFoundException: Column _data not found。

已在Manifest配置以下权限并完成动态申请:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO"/>
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>

求API 33下读取MMS附件数据的正确方法。

解决方案

API 32+限制了content://mms/part Uri对_data列的访问,导致直接调用openInputStream()失效,可通过以下两种方式解决:

方法1:通过openAssetFileDescriptor获取输入流

改用ContentResolver.openAssetFileDescriptor()获取文件描述符,再从中读取数据,绕过_data列限制:

val partURI = Uri.parse("content://mms/part/$partId")
context.contentResolver.openAssetFileDescriptor(partURI, "r")?.use { descriptor ->
    FileInputStream(descriptor.fileDescriptor).use { inputStream ->
        val file = File(context.getExternalFilesDir(null), fileName)
        FileOutputStream(file).use { outputStream ->
            val buffer = ByteArray(1024)
            var read: Int
            while (inputStream.read(buffer).also { read = it } != -1) {
                outputStream.write(buffer, 0, read)
            }
            outputStream.flush()
        }
    }
}

使用use函数自动管理资源,无需手动关闭流和描述符。

方法2:直接查询MMS附件的二进制数据列

通过查询Mms.Part.DATA列(存储附件二进制数据的Blob字段),直接读取数据:

import android.provider.Telephony.Mms.Part

val partURI = Uri.parse("content://mms/part/$partId")
val projection = arrayOf(Part.DATA)

context.contentResolver.query(partURI, projection, null, null, null)?.use { cursor ->
    if (cursor.moveToFirst()) {
        val blob = cursor.getBlob(cursor.getColumnIndexOrThrow(Part.DATA))
        val file = File(context.getExternalFilesDir(null), fileName)
        FileOutputStream(file).use { outputStream ->
            outputStream.write(blob)
            outputStream.flush()
        }
    }
}

关键权限补充

你当前的权限列表缺少短信读取权限,需添加:

<uses-permission android:name="android.permission.READ_SMS" />

并完成动态申请,否则无法访问MMS相关内容。此外,API 33+无需再申请READ_EXTERNAL_STORAGE,READ_MEDIA_*权限已覆盖媒体文件访问需求。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 06:40:27