android - 如何为android中的每个联系人/人发送短信确认?

标签 android sms broadcastreceiver android-broadcast

我想向多人发送短信并验证短信是否已发送。我检查了多个链接(此处提到)并想到使用 PendingIntentbroadCast Receiver 进行确认。

Practical way to find out if SMS has been sent
Sending text messages programmatically in android
http://mobiforge.com/design-development/sms-messaging-android

但关键问题是,我在一个 arrayList 中有不同的 50 个联系人号码,在另一个 arrayList 中有不同的消息。

我使用这段代码:

for (Condition) {   
    sms = SmsManager.getDefault();   
    try {   
        . . . sms.sendTextMessage(phoneNumbers[i], null, messages[i], sentPI, deliveredPI);  
    }   
    catch(IllegalArgumentException e) {     }  
}

现在,我无法确定有多少人收到了他们的消息,有多少人没有收到。因为如帖子(上面提到的链接)所示,每次我们只收到一条消息,“短信已送达”。

所以请告诉我,当我发送消息并从 broadcast Receiver 获取额外信息以获取特定细节时,如何将“额外信息”放入 Intent联系人/人。

还有一件事:PendingIntent 中有四种不同的标志值选项 (FLAG_ONE_SHOTFLAG_NO_CREATEFLAG_CANCEL_CURRENTFLAG_UPDATE_CURRENT)。 当我在 for 循环中发送消息以获得正确结果时,我应该使用哪个?

最佳答案

这是一个非常简单的示例,用于演示可用于所有 SmsManager#send*() 方法的发送和传递 PendingIntent 的使用,以及附加数据以便轻松区分接收器中的结果。

附加该数据就像在 Intent 上添加额外内容一样简单,以支持我们传递给 send*() 方法的 PendingIntent .问题是 PendingIntent 的行为可能不像人们预期的那样。为了节约资源,系统只会在必要时创建新资源。如果 Intent 根据 Intent#filterEquals() 不同,get*() 方法将仅返回不同的 PendingIntent方法,请求代码当前未用于相同的 Intent,或者传递了适当的标志。

具有相同请求代码的其他相同 Intent 的不同附加项 不会 导致创建新的 PendingIntent。根据在这种情况下传递的标志,这些额外内容可能会被忽略,或者覆盖当前 Activity 的 PendingIntent 中的那些内容,这可能会导致不正确的结果。

在我们的示例中,我们基本上对每次发送都使用相同的 Intent,因此我们将通过传递唯一的请求代码来确保每次发送都有不同的 PendingIntent。这个简单的示例使用这些代码的收缩列表的大小,这在单次运行的上下文中是唯一的。请求代码最终可以是任意的 int,只要您知道它在请求时未被使用即可。

系统将要缓存这些PendingIntent,以防我们在不久的将来再次需要它们,因此我们还将传递FLAG_ONE_SHOT 来“清除它们”使用后,并确保我们在后续运行中获得正确的、最新的附加功能。

public class SmsActivity extends Activity implements View.OnClickListener {
    private static final String SMS_SENT_ACTION = "com.mycompany.myapp.SMS_SENT";
    private static final String SMS_DELIVERED_ACTION = "com.mycompany.myapp.SMS_DELIVERED";
    private static final String EXTRA_NUMBER = "number";
    private static final String EXTRA_MESSAGE = "message";

    // Initialize our sample numbers list.
    private final List<String> numberList = new ArrayList<String>() {{{
                add("111-111-1111");
                add("222-222-2222");
                add("333-333-3333");
    }}};

    // Initialize our sample message list.
    private final List<String> messageList = new ArrayList<String>() {{{
                add("Hello.");
                add("Howdy.");
                add("Hi.");
    }}};

    private SmsManager smsManager;
    private IntentFilter intentFilter;
    private BroadcastReceiver resultsReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sms);

        findViewById(R.id.button_send).setOnClickListener(this);

        smsManager = SmsManager.getDefault();
        resultsReceiver = new SmsResultReceiver();

        intentFilter = new IntentFilter(SMS_SENT_ACTION);
        intentFilter.addAction(SMS_DELIVERED_ACTION);
    }

    @Override
    protected void onResume() {
        super.onResume();
        registerReceiver(resultsReceiver, intentFilter);
    }

    @Override
    protected void onPause() {
        super.onPause();
        unregisterReceiver(resultsReceiver);
    }

    public void onClick(View v) {
        v.setEnabled(false);
        sendNextMessage();
    }

    private void sendNextMessage() {
        // We're going to remove numbers and messages from
        // the lists as we send, so if the lists are empty, we're done.
        if (numberList.size() == 0) {
            return;
        }

        // The list size is a sufficiently unique request code,
        // for the PendingIntent since it decrements for each send.
        int requestCode = numberList.size();

        String number = numberList.get(0);
        String message = messageList.get(0);

        // The Intents must be implicit for this example,
        // as we're registering our Receiver dynamically.
        Intent sentIntent = new Intent(SMS_SENT_ACTION);
        Intent deliveredIntent = new Intent(SMS_DELIVERED_ACTION);

        // We attach the recipient's number and message to
        // the Intents for easy retrieval in the Receiver.
        sentIntent.putExtra(EXTRA_NUMBER, number);
        sentIntent.putExtra(EXTRA_MESSAGE, message);
        deliveredIntent.putExtra(EXTRA_NUMBER, number);
        deliveredIntent.putExtra(EXTRA_MESSAGE, message);

        // Construct the PendingIntents for the results.
        // FLAG_ONE_SHOT cancels the PendingIntent after use so we
        // can safely reuse the request codes in subsequent runs.
        PendingIntent sentPI = PendingIntent.getBroadcast(this,
                                                          requestCode,
                                                          sentIntent,
                                                          PendingIntent.FLAG_ONE_SHOT);

        PendingIntent deliveredPI = PendingIntent.getBroadcast(this,
                                                               requestCode,
                                                               deliveredIntent,
                                                               PendingIntent.FLAG_ONE_SHOT);

        // Send our message.
        smsManager.sendTextMessage(number, null, message, sentPI, deliveredPI);

        // Remove the number and message we just sent to from the lists.
        numberList.remove(0);
        messageList.remove(0);
    }

    private class SmsResultReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            // A simple result Toast text.
            String result = null;

            // Get the result action.
            String action = intent.getAction();

            // Retrieve the recipient's number and message.
            String number = intent.getStringExtra(EXTRA_NUMBER);
            String message = intent.getStringExtra(EXTRA_MESSAGE);

            // This is the result for a send.
            if (SMS_SENT_ACTION.equals(action)) {
                int resultCode = getResultCode();
                result = "Send result : " + translateSentResult(resultCode);

                // The current send is complete. Send the next one.
                sendNextMessage();
            }
            // This is the result for a delivery.
            else if (SMS_DELIVERED_ACTION.equals(action)) {
                SmsMessage sms = null;

                // A delivery result comes from the service
                // center as a simple SMS in a single PDU.
                byte[] pdu = intent.getByteArrayExtra("pdu");
                String format = intent.getStringExtra("format");

                // Construct the SmsMessage from the PDU.
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && format != null) {
                    sms = SmsMessage.createFromPdu(pdu, format);
                }
                else {
                    sms = SmsMessage.createFromPdu(pdu);
                }

                // getResultCode() is not reliable for delivery results.
                // We need to get the status from the SmsMessage.
                result = "Delivery result : " + translateDeliveryStatus(sms.getStatus());
            }

            result = number + ", " + message + "\n" + result;
            Toast.makeText(context, result, Toast.LENGTH_SHORT).show();
        }

        String translateSentResult(int resultCode) {
            switch (resultCode) {
                case Activity.RESULT_OK:
                    return "Activity.RESULT_OK";
                case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
                    return "SmsManager.RESULT_ERROR_GENERIC_FAILURE";
                case SmsManager.RESULT_ERROR_RADIO_OFF:
                    return "SmsManager.RESULT_ERROR_RADIO_OFF";
                case SmsManager.RESULT_ERROR_NULL_PDU:
                    return "SmsManager.RESULT_ERROR_NULL_PDU";
                case SmsManager.RESULT_ERROR_NO_SERVICE:
                    return "SmsManager.RESULT_ERROR_NO_SERVICE";
                default:
                    return "Unknown error code";
            }
        }

        String translateDeliveryStatus(int status) {
            switch (status) {
                case Telephony.Sms.STATUS_COMPLETE:
                    return "Sms.STATUS_COMPLETE";
                case Telephony.Sms.STATUS_FAILED:
                    return "Sms.STATUS_FAILED";
                case Telephony.Sms.STATUS_PENDING:
                    return "Sms.STATUS_PENDING";
                case Telephony.Sms.STATUS_NONE:
                    return "Sms.STATUS_NONE";
                default:
                    return "Unknown status code";
            }
        }
    }
}

注意事项:

  • 请记下我们用于获取交付状态的方法。接收器中的结果代码不是可靠的指标。我们必须检查从 Intent 上的 PDU extra 获取的 SmsMessagegetStatus() 返回,以获得实际结果。

  • 另请注意,并非所有承运商都提供交付结果,在这种情况下,交付 PendingIntent 永远不会触发。不要依赖交付结果。

  • 此示例使用“正确”但简单的方法按顺序发送多条消息,因为它会等到当前发送完成后再继续下一个。对于短列表,您可以通过一个在执行时尽快触发所有发送的循环来逃脱,但如果系统跟不上,这可能会导致一般性故障。

  • 如前所述,这是一个非常简单的示例。它不太适合生产,因为动态注册的 Receiver 与 Activity 的生命周期相关联。理想情况下,您希望实现一个在 list 中注册的静态 Receiver 类,并使用显式 Intent 来定位它。还建议使用 Service 来处理结果,这些结果可以通过多种机制传递到 UI;例如,LocalBroadcastManager、另一个事件总线实现、IntentNotification 等。

关于android - 如何为android中的每个联系人/人发送短信确认?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24673595/

相关文章:

android - 无法在我的监听器和广播接收器中涉及接口(interface)方法空对象引用

android - 检查网络连接android

android - Google Plus 登录帐户选择对话框问题

android - 如何使用android exoplayer

android - 动态创建的 BroadcastReceiver 生命周期

android - 如何在 Android 6 (api 23) 的默认短信应用程序中打开特定对话

安卓 : Unable to set action in CONNECTIVITY_CHANGE in my service

android - 如何知道 Android 应用程序是否是混合应用程序?

android - 显示来自 MediaStore.Audio.Albums.ALBUM_ART 的专辑封面

android - Intent 向多个联系人发送短信