Android SmsManager.sendTextMessage无报错但短信发送失败问题
解决Android双卡机型短信发送无异常但实际失败的问题
这种代码没抛出异常、日志显示发送成功,但短信应用里标记为"Failed"的情况确实很棘手,结合你的描述和日志信息,我整理了几个关键的排查方向和解决方案:
1. 先监听短信发送状态,获取系统真实的失败原因
你目前调用sendTextMessage时传入的后两个参数是null,这两个参数分别用于监听发送状态和送达状态的PendingIntent。没有监听的话,系统底层的发送失败信息根本无法反馈到你的App,所以你看不到任何异常,但实际发送已经失败了。
给你一个添加状态监听的示例代码:
// 定义发送状态的广播Action private static final String SENT_SMS_ACTION = "com.yourpackage.SENT_SMS_ACTION"; // 在Activity或Fragment中注册广播接收器 private void registerSmsStatusReceiver() { BroadcastReceiver smsSentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { int resultCode = getResultCode(); switch (resultCode) { case Activity.RESULT_OK: System.out.println("✅ 系统确认短信发送成功"); break; case SmsManager.RESULT_ERROR_GENERIC_FAILURE: System.out.println("❌ 发送失败:通用错误(可能是运营商或SIM卡问题)"); break; case SmsManager.RESULT_ERROR_NO_SERVICE: System.out.println("❌ 发送失败:当前无移动信号服务"); break; case SmsManager.RESULT_ERROR_NULL_PDU: System.out.println("❌ 发送失败:PDU数据为空"); break; case SmsManager.RESULT_ERROR_RADIO_OFF: System.out.println("❌ 发送失败:移动数据无线电已关闭"); break; } } }; registerReceiver(smsSentReceiver, new IntentFilter(SENT_SMS_ACTION)); } // 发送短信时传入状态监听的PendingIntent private void sendSmsWithStatus() { // 先确保权限已获取 if (ActivityCompat.checkSelfPermission(this, Manifest.permission.SEND_SMS) != PackageManager.PERMISSION_GRANTED) { return; } // 创建发送状态的PendingIntent PendingIntent sentPI = PendingIntent.getBroadcast(this, 0, new Intent(SENT_SMS_ACTION), PendingIntent.FLAG_UPDATE_CURRENT); SmsManager smgr = SmsManager.getSmsManagerForSubscriptionId(2); smgr.sendTextMessage("+xxxxxxxxx", null, "Test 123", sentPI, null); }
通过这个监听,你就能拿到系统返回的真实失败原因,这是定位问题的核心步骤。
2. 检查对应SIM卡的短信服务中心号码是否正确
虽然你尝试过将服务中心设为null(让系统自动选择),但双卡机型有时会出现系统自动匹配的服务中心与当前SIM卡不兼容的情况。
你可以尝试两种方式排查:
- 手动确认系统设置:打开系统的「短信设置」→ 找到对应SIM卡的短信服务中心,确认号码是否正确(可以咨询运营商获取官方服务中心号码)。
- 代码中手动指定服务中心(注意:Android 10及以上普通App无法直接获取服务中心号码,此方法适用于Android 9及以下):
TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); String scAddress = tm.getSmsCenterForSubscriptionId(2); if (scAddress != null && !scAddress.isEmpty()) { smgr.sendTextMessage("+xxxxxxxxx", scAddress, "Test 123", sentPI, null); } else { System.out.println("⚠️ SIM2的短信服务中心号码为空,请检查系统设置"); }
3. 排查后台发送的系统限制(Android 8.0+)
你提到失败的短信要等5-10分钟才出现在发件箱,这很符合Android 8.0之后的后台任务延迟机制——系统会限制后台应用的高优先级操作,将其放入队列延迟执行。
解决办法:
- 如果是在后台线程发送短信,使用
WorkManager来调度发送任务,它会自动适配系统的后台限制,确保任务在合适的时机执行。 - 或者使用前台服务:发送短信时启动一个前台服务,显示一个通知(比如"正在发送短信..."),这样系统会认为这是用户关注的操作,不会延迟执行。
4. 格式化收件人号码,避免格式问题
虽然你说号码是国际格式(+开头),但有些运营商对号码格式的容错率很低,比如号码中包含空格、括号等符号都会导致发送失败。可以先对号码进行格式化:
// 移除所有非数字和+的字符 String cleanRecipient = recipientNumber.replaceAll("[^+0-9]", ""); smgr.sendTextMessage(cleanRecipient, scAddress, "Test 123", sentPI, null);
5. 尝试使用多部分短信发送API
部分设备的SmsManager在处理单条短信时存在兼容性问题,你可以尝试用sendMultipartTextMessage发送(哪怕内容很短):
ArrayList<String> smsParts = smgr.divideMessage("Test 123"); ArrayList<PendingIntent> sentIntents = new ArrayList<>(); sentIntents.add(sentPI); smgr.sendMultipartTextMessage(cleanRecipient, scAddress, smsParts, sentIntents, null);
内容的提问来源于stack exchange,提问作者Siniša




