Android中使用Intent.ACTION_SENDTO跳转短信应用后,监听状态失败问题排查
核心问题分析
跳转系统短信应用无法触发自定义PendingIntent广播
Intent.ACTION_SENDTO是启动第三方系统短信应用,第三方应用不会识别你附加的SENT_SMS_ACTION和SMS_DELIVERED_ACTION自定义Extra,自然不会触发对应的BroadcastReceiver回调。只有通过SmsManager直接发送短信时,系统才会根据传入的PendingIntent触发状态广播。onActivityResult中REQUEST_CODE_SENT/DELIVERED分支永远不会执行
你通过startActivityForResult启动的是REQUEST_CODE_SEND_SMS,第三方短信应用只会返回这个请求码的结果,不会返回REQUEST_CODE_SENT或REQUEST_CODE_DELIVERED的结果,这部分代码完全无效。状态计数逻辑错误
sentDeliveredReceiver中用messageDelivered == selectedContacts.size()判断是否全部送达,但selectedContacts集合从未被赋值,实际选中的联系人存在referralCustomers中;此外如果单个联系人有多个手机号,需要统计总短信发送条数而非联系人数量。系统短信应用返回resultCode不可靠
大多数系统短信应用在用户发送短信后,不会将resultCode设置为RESULT_OK,所以依赖REQUEST_CODE_SEND_SMS的resultCode判断发送状态完全不准确。
解决方案
方案一:使用SmsManager直接发送短信(推荐,可准确监听状态)
放弃跳转系统短信应用,直接通过SmsManager发送短信,这样可以正常监听发送和送达状态。
修改sendReferralSMS方法:
private void sendReferralSMS() { if (referralCustomers.isEmpty()) { Toast.makeText(this, "No Referral Contacts to send SMS", Toast.LENGTH_SHORT).show(); return; } // 重置计数 messageSent = 0; messageDelivered = 0; int totalMessages = 0; // 统计总短信条数(单个联系人可能有多个号码) for (Invite contact : referralCustomers) { totalMessages += contact.getPhones().length; } SmsManager smsManager = SmsManager.getDefault(); for (Invite contact : referralCustomers) { for (String phone : contact.getPhones()) { // 为每条短信创建唯一的PendingIntent请求码,避免覆盖 int sentRequestCode = messageSent + 1000; int deliveredRequestCode = messageDelivered + 2000; PendingIntent sentPI = PendingIntent.getBroadcast(this, sentRequestCode, new Intent(SENT_SMS_ACTION), PendingIntent.FLAG_IMMUTABLE); PendingIntent deliveredPI = PendingIntent.getBroadcast(this, deliveredRequestCode, new Intent(SMS_DELIVERED_ACTION), PendingIntent.FLAG_IMMUTABLE); // 发送短信 smsManager.sendTextMessage(phone, null, message, sentPI, deliveredPI); } } }
修改BroadcastReceiver的计数逻辑:
private final BroadcastReceiver sentDeliveredReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { switch (getResultCode()) { case RESULT_OK: messageDelivered++; // 计算总短信条数 int totalMessages = 0; for (Invite contact : referralCustomers) { totalMessages += contact.getPhones().length; } if(messageDelivered == totalMessages){ executeReferralAPI(); Toast.makeText(context, "All SMS delivered", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(context, "SMS delivered: " + messageDelivered + "/" + totalMessages, Toast.LENGTH_SHORT).show(); } break; case RESULT_CANCELED: Toast.makeText(context, "SMS not delivered", Toast.LENGTH_SHORT).show(); // 可在这里触发全局错误提示 break; } } };
方案二:必须跳转系统短信应用(无法准确监听送达状态)
如果业务要求必须让用户手动在系统短信应用中发送,那么无法监听送达状态,只能通过ContentObserver监听短信内容变化,判断是否发送成功(仅能判断是否已发送,无法确认送达)。
示例ContentObserver实现:
private class SmsContentObserver extends ContentObserver { public SmsContentObserver(Handler handler) { super(handler); } @Override public void onChange(boolean selfChange) { super.onChange(selfChange); // 查询已发送的短信,判断是否包含你的推荐内容 Cursor cursor = getContentResolver().query(Uri.parse("content://sms/sent"), new String[]{"body"}, null, null, "date DESC limit 1"); if (cursor != null && cursor.moveToFirst()) { String body = cursor.getString(cursor.getColumnIndex("body")); if (body.contains(message)) { Toast.makeText(NewReferralActivity.this, "SMS sent via system app", Toast.LENGTH_SHORT).show(); // 这里无法确认送达,只能提示发送成功 } cursor.close(); } } } // 在onCreate中注册,onDestroy中注销 private SmsContentObserver smsObserver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_new_referral); // ...其他初始化 smsObserver = new SmsContentObserver(new Handler()); getContentResolver().registerContentObserver(Uri.parse("content://sms"), true, smsObserver); } @Override protected void onDestroy() { super.onDestroy(); unregisterReceivers(); getContentResolver().unregisterContentObserver(smsObserver); }
额外注意事项
- 确保已申请
SEND_SMS和READ_SMS(方案二需要)权限,且在Android 13+动态申请。 - 多手机号发送时,务必为每个PendingIntent设置唯一的请求码,避免广播被覆盖。
- 送达状态的监听依赖运营商支持,部分地区或运营商可能无法返回送达通知。
内容的提问来源于stack exchange,提问作者Sairam balu

