简介:本文详细解析Android双卡手机开发中短信发送与双卡判断的核心技术,涵盖TelephonyManager API调用、卡槽信息解析、权限管理及多卡环境下的业务适配策略。
Android系统通过TelephonyManager服务提供双卡设备识别能力,自Android 5.1(API 22)起引入了SubscriptionManager类作为双卡管理的核心接口。开发者可通过以下关键步骤实现双卡判断:
// 获取TelephonyManager实例TelephonyManager telephonyManager =(TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);// 检查设备是否支持多卡(API 22+)if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {SubscriptionManager subscriptionManager =(SubscriptionManager) context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);List<SubscriptionInfo> subscriptionInfos = subscriptionManager.getActiveSubscriptionInfoList();boolean isDualSim = subscriptionInfos.size() > 1;}
该方法通过查询激活的订阅信息列表(SubscriptionInfo)判断设备是否为双卡,相比传统通过SIM卡数量判断的方式(getSimCount()),能更准确反映实际可用卡槽状态。
每个SubscriptionInfo对象包含以下关键属性:
getSubscriptionId(): 唯一订阅ID(用于短信发送)getSimSlotIndex(): 物理卡槽索引(0或1)getCarrierName(): 运营商名称getDisplayNumber(): 显示号码(可能为空)getIconTint(): 运营商图标色调开发者可通过遍历SubscriptionInfo列表构建完整的双卡信息模型:
Map<Integer, SimCardInfo> simCardMap = new HashMap<>();for (SubscriptionInfo info : subscriptionInfos) {SimCardInfo cardInfo = new SimCardInfo(info.getSubscriptionId(),info.getSimSlotIndex(),info.getCarrierName().toString(),info.getDisplayNumber());simCardMap.put(info.getSimSlotIndex(), cardInfo);}
针对不同Android版本需采用差异化实现:
// 反射获取SubscriptionManager(高风险)try {Class<?> telephonyClass = Class.forName("android.telephony.TelephonyManager");Method getMultiSimConfigurationMethod = telephonyClass.getMethod("getMultiSimConfiguration");Object config = getMultiSimConfigurationMethod.invoke(telephonyManager);// 解析配置对象...} catch (Exception e) {// 降级处理}
使用SmsManager发送短信的标准流程:
// 获取默认SMS管理器SmsManager smsManager = SmsManager.getDefault();// 分割长短信(超过160字符)ArrayList<String> parts = smsManager.divideMessage(message);// 发送多部分短信smsManager.sendMultipartTextMessage(destinationAddress,null, // 服务中心地址(通常为null)parts,sentIntents, // 发送状态PendingIntent数组deliveryIntents // 送达状态PendingIntent数组);
Android 5.1+通过SubscriptionManager实现卡槽指定:
public void sendSimSpecificSms(Context context, String message, String phoneNumber, int simSlot) {SubscriptionManager sm = (SubscriptionManager) context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);List<SubscriptionInfo> activeSubs = sm.getActiveSubscriptionInfoList();int targetSubId = -1;for (SubscriptionInfo info : activeSubs) {if (info.getSimSlotIndex() == simSlot) {targetSubId = info.getSubscriptionId();break;}}if (targetSubId != -1) {SmsManager smsManager = SmsManager.getSmsManagerForSubscriptionId(targetSubId);smsManager.sendTextMessage(phoneNumber, null, message, null, null);} else {Log.e("SMS", "No SIM found in slot " + simSlot);}}
必须声明以下权限:
<uses-permission android:name="android.permission.SEND_SMS" /><uses-permission android:name="android.permission.READ_PHONE_STATE" /><!-- Android 10+需要动态请求 --><uses-permission android:name="android.permission.SMS_SEND_ACTION" />
动态权限请求示例:
if (ContextCompat.checkSelfPermission(this, Manifest.permission.SEND_SMS)!= PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.SEND_SMS},REQUEST_SMS_PERMISSION);}
实现智能卡槽选择的伪代码:
public int selectOptimalSimSlot(Context context, String destination) {// 1. 检查号码归属地(需集成号码库)String operator = NumberAnalyzer.getOperator(destination);// 2. 匹配卡槽运营商Map<Integer, String> simOperators = getSimOperators(context);for (Map.Entry<Integer, String> entry : simOperators.entrySet()) {if (entry.getValue().equals(operator)) {return entry.getKey();}}// 3. 默认选择策略(流量卡优先)return getDefaultDataSimSlot(context);}
实现短信发送状态监听:
// 发送状态监听PendingIntent sentPI = PendingIntent.getBroadcast(context,0,new Intent("SMS_SENT"),PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);// 注册广播接收器context.registerReceiver(new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {switch (getResultCode()) {case Activity.RESULT_OK:Log.i("SMS", "Sent successfully");break;case SmsManager.RESULT_ERROR_GENERIC_FAILURE:Log.e("SMS", "Generic failure");break;case SmsManager.RESULT_ERROR_NO_SERVICE:Log.e("SMS", "No service");break;}}}, new IntentFilter("SMS_SENT"));
主要厂商的双卡实现差异:
| 厂商 | 特殊实现 | 解决方案 |
|————|—————————————————-|———————————————|
| 华为 | 使用HwTelephonyManager | 通过反射调用隐藏方法 |
| 小米 | 自定义SubscriptionManager | 检测MIUI版本后适配 |
| 三星 | 多卡信息存储在Secure Settings | 使用Settings.Global获取 |
建议采用分层架构设计,将厂商适配层与核心逻辑分离,通过接口抽象实现解耦。
实际开发中,推荐使用开源库如TelephonyManagerCompat(需自行实现)来封装各版本差异,或参考AOSP中的Telephony组件实现原理。对于商业项目,建议建立完整的双卡功能测试用例库,覆盖卡槽热插拔、运营商切换等边界场景。