You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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

火山引擎 最新活动