Cómo asegurarse de que SMS se envía en Android

En mi aplicación habrá una notificación sms enviar una acción. Ahora, ¿cómo puedo asegurarme de que el SMS será enviado?

Por ejemplo, si no hay red o tarjeta SIM eliminada, ¿cómo puedo asegurar que los sms se enviarán una vez que haya una red disponible en un momento posterior? ¿Es posible agregar los sms a la cola?

es posible?

Gracias de antemano, Perumal

Puede capturar el estado de envío / envío de SMS con un receptor de difusión. El BroadcastReceiver debe estar registrado antes de enviar el SMS. Utilizo esta implementación, junto con una clase padre, para obtener el resultado de la operación hasta el estado SENT o DELIVERED (debe escoger uno de los dos)

 package com.mycie.myapp; import java.util.ArrayList; import java.util.logging.Level; import android.app.Activity; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.SystemClock; import android.telephony.SmsManager; import android.widget.Toast; extern class Sequencer; extern class Test; extern class Status; /** * Sends multipart SMS to multiple destinations and verifies the send and * deliver status of each part sent away. The operation is a success if all the * codes of the SMS_SENT of all the messages sent are equal to * {@link Activity#RESULT_OK}. */ public class SendSms extends ModemDependentAtom { private static final String LOG_TAG = "SendSms"; // set this flag to true to print many traces to follow the machine state. // NB: DEBUG level traces are always printed for the SEND and DELIVER status // of the part, so you don't need to activate this flag to get them. private static final boolean DEBUG = false; public static final String SMS_DELIVERY = "com.mycie.myapp.SMS_DELIVERY"; public static final String SMS_SENT = "com.mycie.myapp.SMS_SENT"; // infinite time-out public static final int TIMEOUT_INFINITE = -1; // timeout per part. private static final int DEFAULT_TIMEOUT = 10000; private String mSmsNumber; private String mSmsBody; private int mTimeout; private long mOrgRealtime; private SendSmsReceiver mSendReceiver; private SendSmsReceiver mDeliverReceiver; private int mNbParts; private int mDestIndex; private int mState; private String[] mNumbers; private ArrayList<String> mParts; private Status mStatus; public enum SmsSendNotification { SEND, DELIVER } private final SmsSendNotification mSignificantNotification; private ArrayList<PendingIntent> mSentIntents; private ArrayList<PendingIntent> mDeliveryIntents; public SendSms(SmsSendNotification significant) { mSignificantNotification = significant; mSmsNumber = ""; mSmsBody = ""; mTimeout = DEFAULT_TIMEOUT; mOrgRealtime = 0; mStatus = Status.NotDone; mState = 0; mSentIntents = new ArrayList<PendingIntent>(); mDeliveryIntents = new ArrayList<PendingIntent>(); } private final class SendCallBack implements SendSmsReceiver.Callback { SendCallBack(Sequencer sequencer, Test test) { mSequencer = sequencer; mTest = test; } private Sequencer mSequencer; private Test mTest; @Override public void onPartResult(int part, int code) { Log.d(LOG_TAG, String.format("SEND part %d: %s", part, SendSmsReceiver.getCodeString(code))); Context context = Controller.controller.getApplication().getApplicationContext(); if (mSendReceiver.findCode(SendSmsReceiver.RESULT_UNDEFINED) == -1) { // no more sent notification to receive. int globalCode = mSendReceiver.findNotCode(Activity.RESULT_OK); if (globalCode == -1) { // all part were sent successfully. globalCode = Activity.RESULT_OK; } else { // at least one part failed to be sent. mSequencer.onTestEvent(mTest, Level.SEVERE, Sequencer.TEST_EXCEPTION, "one or more parts failed to be sent"); //$NON-NLS-1$ mTest.setStatus(Status.Error); mStatus = Status.Executed; } Log.d(LOG_TAG, "SMS send result: " + SendSmsReceiver.getCodeString(globalCode)); Toast.makeText(context, "SEND: " + SendSmsReceiver.getCodeString(globalCode), Toast.LENGTH_LONG).show(); } } }; private final class DeliverCallBack implements SendSmsReceiver.Callback { DeliverCallBack(Sequencer sequencer, Test test) { mSequencer = sequencer; mTest = test; } private Sequencer mSequencer; private Test mTest; @Override public void onPartResult(int part, int code) { Log.d(LOG_TAG, String.format("DELIVER part %d: %s", part, SendSmsReceiver.getCodeString(code))); if (mDeliverReceiver.findCode(SendSmsReceiver.RESULT_UNDEFINED) == -1) { // no more delivery notification to receive. int globalCode = mDeliverReceiver.findNotCode(Activity.RESULT_OK); if (globalCode == -1) { // all part were sent successfully. globalCode = Activity.RESULT_OK; } else { // at least one part failed to be sent. mSequencer.onTestEvent(mTest, Level.SEVERE, Sequencer.TEST_EXCEPTION, "one or more parts failed to be delivered"); //$NON-NLS-1$ mTest.setStatus(Status.Error); mStatus = Status.Executed; } Context context = Controller.controller.getApplication().getApplicationContext(); Log.d(LOG_TAG, "SMS deliver result: " + SendSmsReceiver.getCodeString(globalCode)); Toast.makeText(context, "DELIVER: " + SendSmsReceiver.getCodeString(globalCode), Toast.LENGTH_LONG).show(); // we can early examine the send results so do it. examine(mSequencer, mTest); } } }; @Override public Status process(Sequencer sequencer, Test test) { if (mState == 0) { mNumbers = PhoneUtils.splitNumbers(mSmsNumber); PhoneUtils.parsePhoneNumbers(mNumbers, new PhoneUtils.PrivilegiateSms()); AppData data = Controller.controller.getData(); SmsManager smsManager = data.services.getSmsManager(); mParts = smsManager.divideMessage(mSmsBody); mNbParts = mParts.size(); Context context = Controller.controller.getApplication().getApplicationContext(); mSendReceiver = SendSmsReceiver.getInstance(context, sequencer.getPosition(), SMS_SENT, new SendCallBack(sequencer, test)); mDeliverReceiver = SendSmsReceiver.getInstance(context, sequencer.getPosition(), SMS_DELIVERY, new DeliverCallBack(sequencer, test)); if (DEBUG) { Log.d(LOG_TAG, "broadcast receivers created."); } mDestIndex = 0; if (DEBUG) { Log.d(LOG_TAG, "state=1"); } mState = 1; process(sequencer, test); mStatus = Status.Active; } else if (mState == 1) { if (mDestIndex < mNumbers.length) { Log.i(LOG_TAG, "Sending SMS to " + mNumbers[mDestIndex] + "..."); Status result = sendMultipartText(sequencer, test, mNumbers[mDestIndex]); if (result == Status.Error) { // error: fail to send to a receiver. test.setStatus(Status.Error); mStatus = Status.Executed; } else { if (DEBUG) { Log.d(LOG_TAG, "state=2"); } mState = 2; } } else { // no more: completed. if (DEBUG) { Log.d(LOG_TAG, "No more recipient. Test OK."); } mStatus = Status.Executed; } } else if (mState == 2) { if (mModemReset) { sequencer.onTestEvent(test, Level.SEVERE, Sequencer.EXTERNAL_ERROR, "the test probably caused a modem reset"); //$NON-NLS-1$ test.setStatus(Status.Error); mStatus = Status.Error; mModemReset = false; } // wait for status to change. Force examination if timeout expires. else if (isTimerExpired()) { if (DEBUG) { Log.d(LOG_TAG, "timeout"); } examine(sequencer, test); } } else { // what? } if (mStatus != Status.Active) { if (DEBUG) { Log.d(LOG_TAG, "status = " + mStatus); } } else { sequencer.wakeAfter(0); } return mStatus; } @Override public void onFinalRelease(Status unused) { super.onFinalRelease(unused); if (DEBUG) { Log.d(LOG_TAG, "broadcast receivers released."); } cancelPendingIntents(); if (mSendReceiver != null) { mSendReceiver.discard(); mSendReceiver = null; } if (mDeliverReceiver != null) { mDeliverReceiver.discard(); mDeliverReceiver = null; } } @Override public void reset() { super.reset(); mState = 0; if (DEBUG) { Log.d(LOG_TAG, "state=0"); } mStatus = Status.NotDone; } public void examine(Sequencer sequencer, Test test) { // If a SENT result is missing then the test failed due to timeout. The // method should have been called by the timeout handler, if not this is // a programming error. if (mSendReceiver.findCode(SendSmsReceiver.RESULT_UNDEFINED) != -1) { sequencer.onTestEvent(test, Level.SEVERE, Sequencer.TEST_EXCEPTION, "not all send results received before timeout"); //$NON-NLS-1$ test.setStatus(Status.Error); mStatus = Status.Executed; } // If one or more SENT failed then the test failed. else if (mSendReceiver.findNotCode(Activity.RESULT_OK) != -1) { sequencer.onTestEvent(test, Level.SEVERE, Sequencer.TEST_EXCEPTION, "failed to send at least one SMS part."); //$NON-NLS-1$ test.setStatus(Status.Error); mStatus = Status.Executed; } // Otherwise, if DELIVER is the significant notification then the // test fails if there is one or more delivery failed. else if (mSignificantNotification.equals(SmsSendNotification.DELIVER)) { if (mDeliverReceiver.findCode(SendSmsReceiver.RESULT_UNDEFINED) != -1) { // failed due to timeout on DELIVERY sequencer.onTestEvent(test, Level.SEVERE, Sequencer.TEST_EXCEPTION, "not all delivery results received before timeout"); //$NON-NLS-1$ test.setStatus(Status.Error); mStatus = Status.Executed; } else if (mDeliverReceiver.findNotCode(Activity.RESULT_OK) != -1) { // at least on part delivery failed. sequencer.onTestEvent(test, Level.SEVERE, Sequencer.TEST_EXCEPTION, "failed to deliver at least one SMS part."); //$NON-NLS-1$ test.setStatus(Status.Error); mStatus = Status.Executed; } else { // OK, proceed with next number. if (DEBUG) { Log.d(LOG_TAG, "send to next recipient, if any."); } mDestIndex ++; mState = 1; } } else { // SEND is significant and all SENT were OK: proceed with next number. if (DEBUG) { Log.d(LOG_TAG, "send to next receiver, if any."); } mDestIndex ++; mState = 1; } } private Status sendMultipartText(Sequencer sequencer, Test test, String number) { Intent sent; Intent delivery; PendingIntent sentIntent; PendingIntent deliveryIntent; AppData data = Controller.controller.getData(); SmsManager smsManager = data.services.getSmsManager(); Context context = Controller.controller.getApplication().getApplicationContext(); if (mNbParts > 1) { Log.i(LOG_TAG, String.format("SMS is devided in %d parts.", mNbParts)); } cancelPendingIntents(); String serial = getNewSerial(number); int iPart; for (iPart = 0; iPart < mNbParts; iPart++) { Uri uri = new Uri.Builder() .scheme(String.format("pos%d", sequencer.getPosition())) .authority(serial) .appendQueryParameter("part", Integer.toString(iPart)) .build(); sent = new Intent(SMS_SENT, uri); sentIntent = PendingIntent.getBroadcast(context, 0, sent, 0); if (sentIntent == null) { sequencer.onTestEvent(test, Level.SEVERE, Sequencer.PROGRAM_ERROR, "null " + SMS_SENT + " intent"); //$NON-NLS-1$ return Status.Error; } mSentIntents.add(sentIntent); delivery = new Intent(SMS_DELIVERY, uri); deliveryIntent = PendingIntent.getBroadcast(context, 0, delivery, 0); if (deliveryIntent == null) { sequencer.onTestEvent(test, Level.SEVERE, Sequencer.PROGRAM_ERROR, "null " + SMS_DELIVERY + " intent"); return Status.Error; } mDeliveryIntents.add(deliveryIntent); } this.mOrgRealtime = SystemClock.elapsedRealtime(); if (DEBUG) { Log.d(LOG_TAG, "timeout: " + getRealTimeout()); } mSendReceiver.restart(serial, mNbParts); mDeliverReceiver.restart(serial, mNbParts); smsManager.sendMultipartTextMessage(number, null, mParts, mSentIntents, mDeliveryIntents); return Status.Executed; } private static String getNewSerial(String number) { String serial = number + "." + SystemClock.uptimeMillis(); return serial; } private void cancelPendingIntents() { // cancel precedent pending intents. for (PendingIntent pi : mSentIntents) { pi.cancel(); } mSentIntents.clear(); for (PendingIntent pi : mDeliveryIntents) { pi.cancel(); } mDeliveryIntents.clear(); } private boolean isTimerExpired() { boolean expired = false; long timeout = getRealTimeout(); if (timeout > 0) { if (mOrgRealtime <= 0) { mOrgRealtime = SystemClock.elapsedRealtime(); } else { long elapsed = SystemClock.elapsedRealtime() - mOrgRealtime; if (elapsed > timeout) { expired = true; } } } return expired; } private long getRealTimeout() { long timeout; if (mTimeout > 0) { if (mSignificantNotification.equals(SmsSendNotification.SEND)) { timeout = mTimeout * mNbParts; } else { // double the times if DELIVER is the significant status. timeout = 2 * mTimeout * mNbParts; } } else { timeout = TIMEOUT_INFINITE; } return timeout; } public void setTimeout(int timeout) { mTimeout = timeout; } public void setNumber(final String number) { mSmsNumber = PhoneUtils.normalizeList(number); } public String getNumber() { return mSmsNumber; } public void setBody(final String body) { mSmsBody = body; } public String getBody() { return mSmsBody; } /** * Send a text message to one or many receivers and forget about the * notifications. * @param number receiver(s) number(s), separated by a comma if more than one. * @param text to send */ public static void sendMessage(String number, String text) { AppData data = Controller.controller.getData(); SmsManager smsManager = data.services.getSmsManager(); ArrayList<String> parts = smsManager.divideMessage(text); Log.d(LOG_TAG, String.format("sending SMS composed of %d parts.", parts.size())); //$NON-NLS-1$ String[] array = PhoneUtils.splitNumbers(number); for (String n : array) { smsManager.sendMultipartTextMessage(n, null, parts, null, null); } } } 

Mire por favor en la clase del encargado de SMS en androide. El enlace es:

http://developer.android.com/reference/android/telephony/SmsManager.html

Hay una constante "STATUS_ON_ICC_SENT". Compruebe el valor de esta constante para comprobar si se envía el SMS.

Para el problema mencionado, vea Notificar si un mensaje que envió se envió correctamente o no en Android y ver la respuesta de Rupesh Yadav .. Utiliza el pendingIntent y BroadcastReceiver para anotar si un mensaje se envía con éxito o no con una simple condición SWITCH Funcionó para mi

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.