Android端接收短信时如何获取对应接收方手机号码
解答
可以获取短信对应的本机接收号码,不存在全版本通用的直接API,需要按Android版本做适配,具体方案如下:
实现原理
SmsMessage类本身没有提供接收方号码的公开字段,核心思路是先从短信广播Intent中拿到当前收件的SIM卡标识,再查询对应SIM卡绑定的本机号码即可。
分版本实现
Android 5.1(API 22)及以上
从API 22开始系统原生支持多SIM卡,短信广播Intent会直接携带当前收件SIM的订阅ID,配合SubscriptionManager就能查询到对应号码。
首先在清单文件声明权限,Android 6.0及以上版本需要动态申请该权限:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
核心取值代码:
// 从短信广播Intent取当前收件SIM的订阅ID val subscriptionId = intent.getIntExtra("subscription", -1) var recipientNumber: String? = null if (subscriptionId != -1 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { val subscriptionManager = getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE) as SubscriptionManager if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) { recipientNumber = runCatching { subscriptionManager.getActiveSubscriptionInfo(subscriptionId)?.number }.getOrNull() } }
注意:如果运营商没有将本机号码写入SIM卡,该字段会返回空,属于硬件/运营商限制,没有通用解决办法。
Android 5.0(API 21)及以下
低版本系统没有开放多SIM卡相关公开API,各厂商实现逻辑不统一:
- 可以先遍历Intent的extras字段,查找常见的SIM标识key,包括
simId、sim_num、slot,拿到卡槽ID - 拿到卡槽ID后需要通过反射调用厂商定制的TelephonyManager内部方法,查询对应卡槽的本机号码,需要针对主流机型单独适配,没有统一代码。
现有代码修正
你贴的原有代码存在递归调用getFullMessage的问题,会触发栈溢出,整合接收方号码逻辑后的完整可运行代码如下:
import android.content.Context import android.content.Intent import android.content.pm.PackageManager import android.os.Build import android.provider.Telephony.Sms.Intents.getMessagesFromIntent import android.telephony.SubscriptionManager import android.telephony.SmsMessage import androidx.core.content.ContextCompat data class CompleteSmsMessage( val originatingAddress: String?, val recipientAddress: String?, val body: String ) fun parseSmsFromIntent(intent: Intent, context: Context): CompleteSmsMessage { val messageParts = getMessagesFromIntent(intent) val fullBody = messageParts.joinToString(separator = "") { it.messageBody ?: "" } val sender = messageParts.lastOrNull()?.originatingAddress var recipient: String? = null val subId = intent.getIntExtra("subscription", -1) if (subId != -1 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { val subManager = context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE) as SubscriptionManager if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) { recipient = runCatching { subManager.getActiveSubscriptionInfo(subId)?.number }.getOrNull() } } return CompleteSmsMessage( originatingAddress = sender, recipientAddress = recipient, body = fullBody ) }
补充说明
- 部分定制ROM会修改SubscriptionManager的返回逻辑,即使权限正常、SIM卡已写入号码也可能返回空,这类情况只能单独针对机型做适配
- 不需要尝试解析短信PDU数据获取接收号码,国内运营商下发的短信PDU中通常不携带本机接收号码字段
内容的提问来源于stack exchange,提问作者Aero Wang
相关产品推荐
相关产品推荐

