¿Cómo enviar sms confirmación de cada contacto / persona en Android?

Deseo enviar sms a varias personas y verificar si enviaron sms o no. Revisé varios enlaces (mencionados aquí) y tuve la idea de usar PendingIntent y broadCast Receiver para su confirmación.

Manera práctica de saber si se han enviado SMS
Envío de mensajes de texto de forma programática en Android
http://mobiforge.com/design-development/sms-messaging-android

Pero el problema clave es que tengo un número diferente de 50 contactos en un arrayList y sus diferentes mensajes en otro arrayList .

Yo uso este código:

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

Ahora, no puedo identificar cuántas personas obtienen su mensaje y cuántas no. Porque como se muestra en la publicación (enlace mencionado anteriormente), cada vez que recibimos un mensaje, “SMS entregado”.

Así que, por favor, avíseme, ¿cómo puedo poner “extras” en Intent , cuando envío msg y obtengo los extras del broadcast Receiver para obtener los detalles del contacto / persona específico.

Una cosa más : hay cuatro opciones diferentes para el valor del indicador en PendingIntent ( FLAG_ONE_SHOT , FLAG_NO_CREATE , FLAG_CANCEL_CURRENT , FLAG_UPDATE_CURRENT ). ¿Cuál debería usar cuando envío mensajes en bucle para obtener el resultado correcto?

Este es un ejemplo muy simple para demostrar el uso del envío y entrega de PendingIntent s disponible para todos los SmsManager#send*() , y adjuntar datos a aquellos para diferenciar fácilmente los resultados en el receptor.

Adjuntar esa información es tan simple como poner extras en el Intent respalda el PendingIntent s que pasamos a los métodos send*() . El problema es que PendingIntent s no se comporta como uno espera. Para conservar recursos, el sistema solo creará nuevos cuando sea necesario. Los métodos get*() solo devolverán un PendingIntent distinto si el Intent es diferente según el método Intent#filterEquals() , el código de solicitud no está actualmente en uso para un Intent igual, o se pasa un indicador apropiado.

Diferentes extras en una Intent contrario igual con el mismo código de solicitud no PendingIntent que se cree un nuevo PendingIntent . Dependiendo de la bandera pasada en ese caso, esos extras pueden ignorarse, o sobrescribir aquellos en un PendingIntent actualmente activo, lo que puede llevar a resultados incorrectos.

En nuestro ejemplo, básicamente estamos usando el mismo Intent para cada envío, por lo que aseguraremos un PendingIntent distinto para cada uno al pasar códigos de solicitud únicos. Este sencillo ejemplo usa el tamaño de una lista de contracción para esos códigos, que serán únicos en el contexto de una sola ejecución. En última instancia, el código de solicitud puede ser cualquier int arbitrario, siempre que sepa que no se utiliza en el momento de la solicitud.

El sistema querrá almacenar estos PendingIntent en caché, en caso de que los necesitemos nuevamente en el futuro cercano, por lo que también pasaremos FLAG_ONE_SHOT para “borrarlos” después de su uso, y nos aseguraremos de obtener los extras actuales correctos en las ejecuciones posteriores.

 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 numberList = new ArrayList() {{{ add("111-111-1111"); add("222-222-2222"); add("333-333-3333"); }}}; // Initialize our sample message list. private final List messageList = new ArrayList() {{{ 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"; } } } } 

Notas:

  • Tome nota del método que estamos usando para obtener el estado de entrega. El código de resultado en el Receptor no es un indicador confiable. Debemos verificar el retorno de getStatus() del SmsMessage obtenido de la PDU extra en la Intent para obtener el resultado real.

  • También tenga en cuenta que no todos los operadores brindan resultados de entrega, en cuyo caso la entrega de PendingIntent nunca se activará. No confíe en un resultado de entrega.

  • Este ejemplo utiliza un método “correcto”, aunque simple, para enviar secuencialmente múltiples mensajes, ya que espera hasta que el envío actual compita antes de pasar al siguiente. Para listas cortas, es posible que pueda salirse con la suya disparando todos los envíos tan rápido como se ejecuta, pero esto puede provocar un error genérico si el sistema no puede mantener el ritmo.

  • Como se señaló, este es un ejemplo muy simple. No es realmente adecuado para producción, ya que el Receptor registrado dinámicamente está vinculado al ciclo de vida de la Activity . Lo ideal sería implementar una clase Receptor estática, registrada en el manifiesto, y usar Intent explícitas para apuntarla. También se recomienda usar un Service para procesar los resultados, y esos resultados podrían entregarse a la UI a través de cualquier cantidad de mecanismos; por ejemplo, LocalBroadcastManager , otra implementación de bus de evento, Intent s, Notification s, etc.