【问题标题】:How to check for successful Multi-part sms send如何检查成功的多部分短信发送
【发布时间】:2015-08-19 16:10:51
【问题描述】:

我已经阅读了很多关于发送 SMS 和多部分 SMS 消息的帖子,例如:

Sending SMS in Android, Sending and Receiving SMS and MMS in Android (pre Kit Kat Android 4.4), Android PendingIntent extras, not received by BroadcastReceiver

...和其他人,但他们似乎没有检查消息的所有部分是否已成功发送。

据我了解,对于多部分消息,您为每个消息部分添加了 PendingIntent,但我看到的示例似乎并没有检查所有部分是否已成功发送......如果是(我猜第一个)他们似乎认为它是成功的......

所以我想我会发送多部分消息并跟踪各个部分。在所有部分都成功发送之前,我不会说消息发送成功。

我尝试在以下代码中执行此操作... SmsMessageInfo 只是一个简单的类,其中包含电话号码、消息和已处理部件的布尔值列表以及成功发送的部件列表,它还有一个唯一的消息 ID。

我尝试了以下方法:

private void sendLongSmsMessage(Context context, final SmsMessageInfo messageInfo) {

    // Receive when each part of the SMS has been sent (or does it????)
    context.registerReceiver(new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String messageIdAsString = intent.getExtras().getString(INTENT_EXTRA_MESSAGE_ID_KEY);

            Log.i("SMSMessageSender", "Broadcast Intent Recieved, IntentMessageID: " + messageIdAsString + "  messageInfoId: " + messageInfo.messageId);

            if (messageIdAsString != null) {
                if (Long.parseLong(messageIdAsString) == messageInfo.messageId) {
                    String messagePartNrAsString = (String) intent.getExtras().get(INTENT_EXTRA_PART_NR_KEY);
                    int messagePartNr = Integer.parseInt(messagePartNrAsString);

                    Log.i("SMSMessageSender", "Broadcast Intent Recieved Multi Part Message Part No: " + messagePartNrAsString);

                    // We need to make all the parts succeed before we say we have succeeded.
                    switch (getResultCode()) {
                    case Activity.RESULT_OK:
                        messageInfo.partsSent.add(messagePartNr, true);
                        break;
                    case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
                        messageInfo.failMessage = "Error - Generic failure";
                        break;
                    case SmsManager.RESULT_ERROR_NO_SERVICE:
                        messageInfo.failMessage = "Error - No Service";
                        break;
                    case SmsManager.RESULT_ERROR_NULL_PDU:
                        messageInfo.failMessage = "Error - Null PDU";
                        break;
                    case SmsManager.RESULT_ERROR_RADIO_OFF:
                        messageInfo.failMessage = "Error - Radio off";
                        break;
                    }

                    messageInfo.partsProcessed.add(messagePartNr, true);

                    boolean allSent = true;
                    for (Boolean partSent : messageInfo.partsSent) {
                        allSent = allSent && partSent;
                    }
                    messageInfo.sent = allSent;

                    boolean allProcessed = true;
                    for (Boolean partProcessed : messageInfo.partsProcessed) {
                        allProcessed = allProcessed && partProcessed;
                    }

                    if (allProcessed) {
                        // We have our response for all of our message parts, so we can unregister our receiver.
                        Log.i("SMSMessageSender", "All message part resoponses received, unregistering message Id: " + messageIdAsString);
                        context.unregisterReceiver(this);
                    } 
                } else {
                    Log.w("SMSMessageSender", "Received a broadcast message with Id for a different message");
                }
            } else {
                Log.w("SMSMessageSender", "Received a broadcast message but not for message Id");
            }
        }
    }, new IntentFilter(SENT));

    ArrayList<String> messageList = SmsManager.getDefault().divideMessage(messageInfo.message);
    ArrayList<PendingIntent> pendingIntents = new ArrayList<PendingIntent>(messageList.size());

    messageInfo.partsSent.clear();

    for (int i = 0; i < messageList.size(); i++) {
        messageInfo.partsSent.add(i, false);
        messageInfo.partsProcessed.add(i, false);

        Intent sentIntent = new Intent(SENT);
        sentIntent.putExtra(INTENT_EXTRA_MESSAGE_ID_KEY, Long.toString(messageInfo.messageId));
        sentIntent.putExtra(INTENT_EXTRA_PART_NR_KEY, Integer.toString(i));

        Log.i("SMSMessageSender", "Adding part " + i + " tp multi-part message Id: " + messageInfo.messageId);
        pendingIntents.add(PendingIntent.getBroadcast(context, 0, sentIntent,  PendingIntent.FLAG_ONE_SHOT));
    }

    Log.i("SMSMessageSender", "About to send multi-part message Id: " + messageInfo.messageId);
    SmsManager.getDefault().sendMultipartTextMessage(messageInfo.phoneNumber, null, messageList, pendingIntents, null);
}

这样做的问题是第二个消息部分永远不会收到。

不得不费力地创建多个 PendingIntent 却不去检查它们是否都有效,这似乎很奇怪。

在我显示 Message Part No 的日志消息中,它始终为 0,我从未得到第二部分,因此此代码永远不会认为它已完成。

我是不是让它太复杂了,我是否应该只采用任何返回的旧 PendingIntent 并假设其余部分同样适用(在这种情况下,为什么 Google 首先让您提供它们的列表)。

我为这个冗长的问题道歉,但我真的不知道如何以更短的方式更清楚地问:-)

问候 科林

【问题讨论】:

    标签: android smsmanager


    【解决方案1】:

    这是我最终使用的代码,它混合了我的原始代码和 Bolton 的代码(感谢 Bolton :-))。

    新代码可能更好地检测到一个部分的失败,有点难以测试,上面的代码将每个消息部分的 anyError 设置为 false,所以如果第 1 部分失败并且第 2 部分成功了可能认为整个事情都成功了......下面的代码调用(我的)messageInfo.fail,如果后续消息部分成功,它将不会被重置......我想这一切都是不必要的,因为你会认为如果一个部分可以,其余的也可以...无论如何,下面是我最终使用的代码。

    Edit > 更新代码以删除 Intent 中的 Extras,因为在重负载下,多个 Intent(我认为)合并为一个(使用不同的 PendingIntent 标志没有帮助)。最后,我为每条消息使用了不同的意图操作(例如 new Intent(SENT + messageInfo.getMessageId())),这样接收者肯定只会获得自己消息的广播。似乎在重负载下工作得更好。

    谢谢。

    private void sendLongSmsMessage4(Context context, final SmsMessageInfo messageInfo) {
    
        // Receive when each part of the SMS has been sent
        BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                // We need to make all the parts succeed before we say we have succeeded.
                switch (getResultCode()) {
                case Activity.RESULT_OK:
                    break;
                case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
                    messageInfo.fail("Error - Generic failure");
                    break;
                case SmsManager.RESULT_ERROR_NO_SERVICE:
                    messageInfo.fail("Error - No Service");
                    break;
                case SmsManager.RESULT_ERROR_NULL_PDU:
                    messageInfo.fail("Error - Null PDU");
                    break;
                case SmsManager.RESULT_ERROR_RADIO_OFF:
                    messageInfo.fail("Error - Radio off");
                    break;
                }
    
                nMsgParts--;
                if (nMsgParts <= 0) {
                    // Stop us from getting any other broadcasts (may be for other messages)
                    Log.i(LOG_TAG, "All message part resoponses received, unregistering message Id: " + messageInfo.getMessageId());
                    context.unregisterReceiver(this);
    
                    if (messageInfo.isFailed()) {
                        Log.d(LOG_TAG, "SMS Failure for message id: " + messageInfo.getMessageId());
                    } else {
                        Log.d(LOG_TAG, "SMS Success for message id: " + messageInfo.getMessageId());
                        messageInfo.setSent(true);
                    }
                }
            }
        };
    
        context.registerReceiver(broadcastReceiver, new IntentFilter(SENT + messageInfo.getMessageId()));
    
        SmsManager smsManager = SmsManager.getDefault();
    
        ArrayList<String> messageParts = smsManager.divideMessage(messageInfo.getMessage());
        ArrayList<PendingIntent> pendingIntents = new ArrayList<PendingIntent>(messageParts.size());
        nMsgParts = messageParts.size();
    
        for (int i = 0; i < messageParts.size(); i++) {
            Intent sentIntent = new Intent(SENT + messageInfo.getMessageId());
            pendingIntents.add(PendingIntent.getBroadcast(context, 0, sentIntent, 0));
        }
    
        Log.i(LOG_TAG, "About to send multi-part message Id: " + messageInfo.getMessageId());
        smsManager.sendMultipartTextMessage(messageInfo.getPhoneNumber(), null, messageParts, pendingIntents, null);
    }
    

    【讨论】:

      【解决方案2】:

      我正在使用下面的代码向多个联系人发送多部分消息,它工作正常:

          // Send the SMS message
          SmsManager sms = SmsManager.getDefault();
          ArrayList<String> parts = sms.divideMessage(content);
              final int numParts = parts.size();
      
          ArrayList<PendingIntent> sentIntents = new ArrayList<PendingIntent>();
          sentReceiver = new BroadcastReceiver() {
              @Override
              public void onReceive(Context context, Intent intent) {
      
                  Log.d(TAG, "SMS onReceive intent received.");
                  boolean anyError = false;
                  switch (getResultCode()) {
                  case Activity.RESULT_OK:
                      break;
                  case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
                  case SmsManager.RESULT_ERROR_NO_SERVICE:
                  case SmsManager.RESULT_ERROR_NULL_PDU:
                  case SmsManager.RESULT_ERROR_RADIO_OFF:
                      anyError = true;
                      break;
                  }
                  msgParts--;
                  if (msgParts == 0) {
                      hideProgressBar();
                      if (anyError) {
                          Toast.makeText(context,
                                  getString(R.string.sms_send_fail),
                                  Toast.LENGTH_SHORT).show();
                      } else {
                          //success
      
                      }
      
                      unregisterReceiver(sentReceiver);
                  }
      
              }
          };
          registerReceiver(sentReceiver, new IntentFilter(SENT_ACTION));
      
          // SMS delivered receiver
          // registerReceiver(new BroadcastReceiver() {
          // @Override
          // public void onReceive(Context context, Intent intent) {
          // Log.d(TAG, "SMS delivered intent received.");
          // }
          // }, new IntentFilter(DELIVERED_ACTION));
      
          for (int i = 0; i < numParts; i++) {
              sentIntents.add(PendingIntent.getBroadcast(this, 0, new Intent(
                      SENT_ACTION), 0));
          }
      
          for (PhoneInfo phone : recipientsList) {
              sms.sendMultipartTextMessage(phone.num, null, parts, sentIntents,
                      null);
          }
          msgParts = numParts * recipientsList.size();
          showProgressBar();
      

      【讨论】:

      • 谢谢你,你的解决方案比我的简单一点。我的应用程序可能同时发送了几条消息,我认为意图可以混合到广播接收器,因此我将消息 id 保存在意图中。但是,调整您的代码 getExtras 返回 null 除非我在添加它们时设置了 PendingIntent 标志。我还注意到我的“额外”并没有像我预期的那样工作,因为我似乎收到了两个意图,但额外的不是我设置的......我想我会尝试在发送消息和删除之间增加时间复杂性。
      • 如果这有帮助(2 年后),我遇到了同样的问题,但您只需要使用不同的 RequestCode (In getBroadcast) 请求 PendingIntent 。这可以防止覆盖已使用但尚未接收 PendingIntent。
      猜你喜欢
      • 1970-01-01
      • 2012-06-18
      • 1970-01-01
      • 2011-10-25
      • 2019-07-14
      • 1970-01-01
      • 1970-01-01
      • 2020-03-01
      • 1970-01-01
      相关资源
      最近更新 更多