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

如何读取双卡双待手机中两张SIM卡的收件箱短信?

解决方案:读取双卡双待手机的所有收件箱短信

你的代码只读取到单卡短信的核心原因是:Android系统中双卡短信通过sub_id字段区分归属的SIM卡,原代码未针对该字段做筛选或遍历,导致仅读取到默认SIM卡的短信。以下是通用解决方案:

步骤1:添加必要权限

在AndroidManifest.xml中声明权限,同时注意动态申请(Android 6.0+要求危险权限动态授权):

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

步骤2:获取所有SIM卡的Sub ID

通过SubscriptionManager获取设备上激活的SIM卡标识(sub_id),用于后续筛选对应SIM卡的短信:

private fun getSimSubIds(context: Context): List<Int> {
    val subIds = mutableListOf<Int>()
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
        val subscriptionManager = context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE) as SubscriptionManager
        if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
            subscriptionManager.activeSubscriptionInfoList?.forEach { subInfo ->
                subIds.add(subInfo.subId)
            }
        }
    }
    return subIds
}

步骤3:遍历Sub ID读取对应SIM卡的短信

修改原短信读取逻辑,加入sub_id字段查询,并遍历每个SIM卡的标识获取对应短信:

fun readAllInboxSms(context: Context): MutableList<JSONObject> {
    val msgs = mutableListOf<JSONObject>()
    val uriSms: Uri = Uri.parse("content://sms/inbox")
    // 新增sub_id字段到查询投影
    val projection = arrayOf("_id", "address", "date", "body", "sub_id")
    val subIds = getSimSubIds(context)

    if (subIds.isNotEmpty()) {
        // 遍历每个SIM卡的sub_id,查询对应短信
        subIds.forEach { subId ->
            context.contentResolver.query(
                uriSms,
                projection,
                "sub_id = ?",
                arrayOf(subId.toString()),
                null
            )?.use { cursor ->
                while (cursor.moveToNext()) {
                    val msgJson = JSONObject()
                    // 使用getColumnIndexOrThrow避免字段索引偏移问题
                    val address = cursor.getString(cursor.getColumnIndexOrThrow("address"))
                    val body = cursor.getString(cursor.getColumnIndexOrThrow("body"))
                    val date = cursor.getString(cursor.getColumnIndexOrThrow("date"))
                    val simSubId = cursor.getInt(cursor.getColumnIndexOrThrow("sub_id"))

                    msgJson.put("mobile_number", address)
                    msgJson.put("body", body)
                    msgJson.put("date", date)
                    msgJson.put("sim_sub_id", simSubId) // 标记短信所属SIM卡
                    msgs.add(msgJson)
                }
            }
        }
    } else {
        // 无法获取sub_id时,降级读取所有短信(不区分SIM)
        context.contentResolver.query(
            uriSms,
            projection,
            null,
            null,
            null
        )?.use { cursor ->
            while (cursor.moveToNext()) {
                val msgJson = JSONObject()
                val address = cursor.getString(cursor.getColumnIndexOrThrow("address"))
                val body = cursor.getString(cursor.getColumnIndexOrThrow("body"))
                val date = cursor.getString(cursor.getColumnIndexOrThrow("date"))

                msgJson.put("mobile_number", address)
                msgJson.put("body", body)
                msgJson.put("date", date)
                msgs.add(msgJson)
            }
        }
    }
    return msgs
}

关键注意事项

  • 权限兼容性:Android 10+对READ_PHONE_STATE权限限制更严格,若无法获取该权限,将无法区分短信所属SIM卡,但仍可读取所有短信。
  • 厂商差异:部分厂商(如小米、华为)可能使用自定义短信URI或字段,若上述方法无效,可尝试替换URI为content://mms-sms/sms/inbox(通用兼容URI)。
  • 内存安全:使用cursor?.use自动关闭游标,避免内存泄漏;优先使用getColumnIndexOrThrow而非固定索引,防止数据库字段顺序变更导致的崩溃。

内容的提问来源于stack exchange,提问作者Aymen Ben Salah

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 17:36:32