Android Java如何获取双卡手机号?实现类UPI应用短信登录验证
UPI式登录中SIM卡手机号获取问题
我需要实现类似UPI应用的登录功能:用户从手机中选择SIM卡,应用通过该SIM卡发送短信完成手机号验证,后端需对号码进行比对,因此需要获取两张SIM卡的手机号,或用户选中的SIM卡的手机号(可从短信内容或发送环节获取)。
我编写了SimUtil.java工具类处理SIM卡选择和短信操作,尝试通过SubscriptionInfo获取手机号,但该接口能返回运营商名称等信息,唯独手机号返回空字符串。经调研发现,该字段是否填充由运营商决定,无法保证100%能获取到手机号。
以下是我的SimUtil.java代码:
import android.Manifest; import android.app.Activity; import android.content.Context; import android.content.pm.PackageManager; import android.telephony.SmsManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import java.util.ArrayList; import java.util.List; import java.util.Timer; import java.util.TimerTask; public class SimUtil { List<SimCard> simCards = new ArrayList<>(); Context context; public SimUtil(Context context) { this.context = context; if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) { setupPermissions(); return; } List<SubscriptionInfo> subscriptionInfos = SubscriptionManager.from(context.getApplicationContext()).getActiveSubscriptionInfoList(); for (int i = 0; i < subscriptionInfos.size(); i++) { SubscriptionInfo currentCard = subscriptionInfos.get(i); SimCard simCard = new SimCard(i,currentCard); simCards.add(simCard); } } public int getSimCardCount() { return this.simCards.size(); } public List<SimCard> getSimCardList() { if(simCards.size() > 0) return simCards; else return null; } public SimCard getFirstSimCard() { return simCards.get(0); } public boolean hasDualSim() { return simCards.size() > 1; } public SimCard getSecondSimCard() { if(hasDualSim()) return simCards.get(1); else return null; } public static void sendSMSFromSim1(String message) { SmsManager.getSmsManagerForSubscriptionId(0) .sendTextMessage(AppConstant.LOGIN_MOBILE_NUMBER, null, message, null, null); } public static void sendSMSFromSim2(String message) { SmsManager.getSmsManagerForSubscriptionId(1) .sendTextMessage(AppConstant.LOGIN_MOBILE_NUMBER, null, message, null, null); } private void setupPermissions() { int permission = ContextCompat.checkSelfPermission(context, Manifest.permission.SEND_SMS); if(permission != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions((Activity)context, new String[]{Manifest.permission.SEND_SMS}, 1); } int permission2 = ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE); if(permission2 != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions((Activity)context, new String[]{Manifest.permission.READ_PHONE_STATE}, 1); } } public static class SimCard { int index; String operatorName; String mobileNumber; String countryISO; public SimCard(int index, String operatorName, String countryISO, String mobileNumber) { this.index = index; this.operatorName = operatorName; this.countryISO = countryISO; this.mobileNumber = mobileNumber; } public SimCard(int index,SubscriptionInfo subscriptionInfo) { this.index = index; this.operatorName = subscriptionInfo.getCarrierName().toString(); this.countryISO = subscriptionInfo.getCountryIso(); this.mobileNumber = subscriptionInfo.getNumber(); } public int getIndex() { return index; } public String getOperatorName() { return operatorName; } public String getCountryISO() { return countryISO; } public String getMobileNumber() { return mobileNumber; } } }
解决方案
1. 短信发送反向校验(推荐)
既然SubscriptionInfo无法可靠获取手机号,可通过后端接收短信时提取发送方号码实现验证:
- 在发送的验证短信中加入唯一标识(如设备UUID、临时会话ID),后端收到短信后,提取短信的发送方手机号,再通过标识关联到当前用户会话,验证通过后将结果返回给APP。
- 无需提前获取手机号,完全依赖短信发送环节的真实号码,兼容性100%。
2. 兜底:用户手动输入+验证
当自动获取失败时,引导用户手动输入所选SIM卡的手机号,再通过该SIM卡发送验证码:
- 后端比对用户输入的手机号与短信发送方号码,一致则验证通过,确保号码与所选SIM卡匹配。
3. 优化SIM卡信息获取逻辑
补充其他手机号获取方式,提升自动获取的成功率:
// 修改SimCard构造方法,增加TelephonyManager获取逻辑 import android.telephony.TelephonyManager; import android.text.TextUtils; public SimCard(int index, SubscriptionInfo subscriptionInfo, Context context) { this.index = index; this.operatorName = subscriptionInfo.getCarrierName().toString(); this.countryISO = subscriptionInfo.getCountryIso(); this.mobileNumber = subscriptionInfo.getNumber(); // 兜底:用TelephonyManager尝试获取 if (TextUtils.isEmpty(this.mobileNumber) && ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) { TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); this.mobileNumber = telephonyManager.getLine1Number(subscriptionInfo.getSubscriptionId()); } }
注意:
getLine1Number()同样依赖运营商配置,部分设备仍可能返回空值。
4. 权限补充
若要监听运营商回执短信,需额外申请RECEIVE_SMS权限,并注册广播接收器解析短信内容。
内容的提问来源于stack exchange,提问作者Shubham Vyas
相关产品推荐
相关产品推荐

