如何读取双卡双待手机中两张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
相关产品推荐
相关产品推荐

