如何通过SMS listener判定双卡手机短信的接收SIM卡?开发求助
Hey there! I’ve tackled this exact issue while building a dual-SMS management app, so let’s break down the practical solutions based on your target Android version—since the approach varies a lot between older and newer OS releases.
Android 11+(API 30及以上):官方API支持
Starting with Android 11, Google finally added official support to identify which SIM received a text. Here’s how to implement it smoothly:
- Register your SMS Broadcast Receiver (or use a foreground service with
SMS_RECEIVED_ACTIONif targeting Android 12+—background receivers are restricted now). - Extract the Subscription ID directly from the broadcast intent. The system passes this via
Telephony.Sms.Intents.EXTRA_SUBSCRIPTION_ID. - Map Subscription ID to SIM Slot Index using
TelephonyManager.getSimSlotIndexFromSubscriptionId().
Here’s a Kotlin code snippet to put this into action:
class DualSmsReceiver : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { if (intent?.action == Telephony.Sms.Intents.SMS_RECEIVED_ACTION) { val subscriptionId = intent.getIntExtra(Telephony.Sms.Intents.EXTRA_SUBSCRIPTION_ID, -1) if (subscriptionId != -1) { val telephonyManager = context?.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager val simSlotIndex = telephonyManager.getSimSlotIndexFromSubscriptionId(subscriptionId) // simSlotIndex will typically be 0 or 1 for dual-SIM devices Log.d("DualSmsReceiver", "SMS received on SIM slot: $simSlotIndex") } } } }
Android 10及以下:兼容方案
Before Android 11, there’s no official API, but two reliable workarounds get the job done:
Option 1: Query the SMS Content Provider
When a SMS arrives, you can query the content://sms/inbox URI and check the hidden but widely supported subscription_id column:
fun getSmsSubscriptionId(context: Context, latestSmsId: Long): Int? { val cursor = context.contentResolver.query( Uri.parse("content://sms/inbox"), arrayOf("subscription_id"), "_id = ?", arrayOf(latestSmsId.toString()), null ) cursor?.use { if (it.moveToFirst()) { return it.getInt(it.getColumnIndexOrThrow("subscription_id")) } } return null }
Note: You’ll need to listen for the SMS broadcast, then fetch the ID of the most recent incoming SMS to pass into this method.
Option 2: Reflect Hidden TelephonyManager Methods
Many devices expose hidden methods like getSimSlotId(int subscriptionId) that let you map subscription IDs to slot indices. Here’s a quick Java example:
private int getSimSlotFromSubscriptionId(Context context, int subscriptionId) { TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); try { Method method = tm.getClass().getMethod("getSimSlotId", int.class); return (int) method.invoke(tm, subscriptionId); } catch (Exception e) { e.printStackTrace(); return -1; // Fallback if reflection fails } }
⚠️ Heads up: Reflection can break across different device manufacturers or Android versions, so always add fallback logic for edge cases.
关键注意事项
- Permissions: You’ll need
READ_SMSandRECEIVE_SMSpermissions. For Android 13+, addPOST_NOTIFICATIONSif you plan to show alerts for incoming SMS. - Background Restrictions: On Android 12+, broadcast receivers can’t catch
SMS_RECEIVED_ACTIONwhile in the background. Switch to a foreground service or useSmsManagercallbacks instead. - Device Compatibility: Test across multiple dual-SIM devices (especially Samsung, Xiaomi, Huawei) since some manufacturers tweak telephony APIs under the hood.
内容的提问来源于stack exchange,提问作者Splect




