Отправляйте SMS до тех пор,

Я пытаюсь отправить срочное SMS-сообщение из своей заявки. Я должен убедиться, что SMS отправляется успешно.

СМС отправляется после загрузки системы Android и после проверки.

Таким образом, у меня есть класс сервиса, который обрабатывает утилизационный фильтр BOOT_COMPLETED. Этот класс делает проверку, и если что-то истинно, он пытается отправить SMS-сообщение через другой класс, который «расширяет службу»,

После того, как он будет успешно отправлен sms, обе службы (тот, который обрабатывает загрузочный вызов и тот, который отправляет смс) должен выйти.

Вопрос 1 : Как заставить функцию отправки sms вызываться с таймаутом, не получая сообщение о невосприимчивости к приложению? В настоящее время я использую это (я не знаю, правильно ли это сделать, хотя он работает):

Timer mTimer = new Timer(); //wait a small timeout prior to sending the message. mTimer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { this.cancel(); //I don't want to run the timer more than once sms_sender sms = new sms_sender(); sms.sendSMS(phoneNumber, messageText); } }, 30000, 30000); //run sendSMS() after 30 seconds 

Вопрос 2 : Как реализовать функцию sendSMS, чтобы повторять каждые 30 секунд после осознания того, что последняя попытка была неудачной?

Вопрос 3 : Как остановить оба сервиса после того, как я понял, что SMS-сообщение успешно отправлено?

Это мой код, который не работает:

 public class sms_sender extends Service { @Override public IBinder onBind(Intent arg0) { // TODO Auto-generated method stub return null; } final String SENT = "SMS_SENT"; public void sendSMS(final String phoneNumber, final String message, final boolean check_result) { PendingIntent sentPI = PendingIntent.getBroadcast(this, 0, new Intent(SENT), 0); registerReceiver(new BroadcastReceiver(){ @Override public void onReceive(Context arg0, Intent arg1) { if(!check_result) return; switch (getResultCode()) { case Activity.RESULT_OK: //exit stopSelf(); return; case SmsManager.RESULT_ERROR_GENERIC_FAILURE: case SmsManager.RESULT_ERROR_NO_SERVICE: case SmsManager.RESULT_ERROR_NULL_PDU: case SmsManager.RESULT_ERROR_RADIO_OFF: //try again in 1 minute Timer mTimer = new Timer(); mTimer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { this.cancel(); //no need to run again, if it fails, this exact code will run again sendSMS(phoneNumber, message, true); } }, 60000, 60000); return; } } }, new IntentFilter(SENT)); SmsManager smsManager = SmsManager.getDefault(); smsManager.sendTextMessage(phoneNumber, null, message, sentPI, null); } } 

В настоящее время программа вылетает при вызове PendingIntent. Я попытался реализовать BroadCastReceiver в методе onCreate, используя частные переменные-члены, чтобы снова вызвать функцию sendSMS () с помощью метода onReceive, но onReceive никогда не запускался.

— РЕДАКТИРОВАТЬ —

Итак, это мой последний рабочий код. Я предполагаю, что мой случай особенный, потому что он не работает в потоке пользовательского интерфейса. У меня есть широковещательный приемник, который работает в Boot. Я пытаюсь отправить SMS-сообщение, пока оно не будет успешно отправлено.

Этот загрузочный приемник вещания запускает службу. Это код:

 public class service extends Service{ static public service serv; //member variable. Initializing to null so as to know whether to unregister the service or not private BroadcastReceiver messageSent = null; ... ... @Override public void onStart(Intent intent, int startid) { serv=this; //will use this static variable in order to shutdown the service when the message is successfully sent ... ... if(somethingIsTrue()){ //register receiver messageSent = new sent_message(); registerReceiver(messageSent, new IntentFilter(sms_sender.INTENT_MESSAGE_SENT)); startMessageServiceIntent(messageText, phoneNumber); //function code can be found on accepted answer } } } 

Класс sent_message следующий:

 public class sent_message extends BroadcastReceiver { private Context pubCon; private void startMessageServiceIntent(String message, String receiver) { Intent i = new Intent(pubCon, sms_sender.class); i.putExtra(sms_sender.EXTRA_MESSAGE, message); i.putExtra(sms_sender.EXTRA_RECEIVERS, new String[] { receiver }); pubCon.startService(i); } @Override public void onReceive(Context context, Intent intent) { pubCon=context; switch (getResultCode()) { case Activity.RESULT_OK: //all went OK, stop the service where this is called from service.serv.stopSelf(); 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: //try sending the message again after 30s new Handler().postDelayed(new Runnable(){ @Override public void run(){ startMessageServiceIntent(service.messageText, service.phoneNumber); } }, 30000); break; } } } 

И упрощенная (принимает только один получатель) версию класса sms_sender выглядит следующим образом:

 public class sms_sender extends IntentService { public static final String INTENT_MESSAGE_SENT = "message.sent"; public static final String INTENT_MESSAGE_DELIVERED = "message.delivered"; public static final String EXTRA_MESSAGE = "extra.message"; public static final String EXTRA_RECEIVERS = "extra.receivers"; public sms_sender() { super("sms_sender"); } private static class IDGenerator { private static final AtomicInteger counter = new AtomicInteger(); public static int nextValue() { return counter.getAndIncrement(); } } public void sendSMS(String message, String receiver) { SmsManager sm = SmsManager.getDefault(); PendingIntent sentPI = null; Intent sentIntent = new Intent(INTENT_MESSAGE_SENT); int sentID = IDGenerator.nextValue(); sentPI = PendingIntent.getBroadcast(sms_sender.this, sentID, sentIntent, PendingIntent.FLAG_CANCEL_CURRENT); try { sm.sendTextMessage(receiver, null, message, sentPI, null); } catch (IllegalArgumentException e) { System.out.println("Illegal argument"); } } protected void onHandleIntent(Intent intent) { String message = intent.getStringExtra(EXTRA_MESSAGE); String[] receivers = intent.getStringArrayExtra(EXTRA_RECEIVERS); sendSMS(message, receivers[0]); } } 

Вот что я сделал:

 public class SMSSender extends IntentService { public static final String INTENT_MESSAGE_SENT = "message.sent"; public static final String INTENT_MESSAGE_DELIVERED = "message.delivered"; public static final String EXTRA_MESSAGE = "extra.message"; public static final String EXTRA_RECEIVERS = "extra.receivers"; public SMSSender() { super("SMSSender"); } private final String TAG = "SendSMS"; private static class IDGenerator { private static final AtomicInteger counter = new AtomicInteger(); public static int nextValue() { return counter.getAndIncrement(); } } private void sendSMS(String message, String[] receivers) { SmsManager sm = SmsManager.getDefault(); ArrayList<String> parts = sm.divideMessage(message); PendingIntent sentPI = null; PendingIntent deliveredPI = null; Intent sentIntent = new Intent(INTENT_MESSAGE_SENT); int sentID = IDGenerator.nextValue(); sentPI = PendingIntent.getBroadcast(SMSSender.this, sentID, sentIntent, PendingIntent.FLAG_CANCEL_CURRENT); Intent deliveryIntent = new Intent(INTENT_MESSAGE_DELIVERED); int deliveredID = IDGenerator.nextValue(); deliveredPI = PendingIntent.getBroadcast(SMSSender.this, deliveredID, deliveryIntent, PendingIntent.FLAG_CANCEL_CURRENT); Log.i(TAG, "sending SMS: parts: " + parts.size() + " message: " + message); if (parts.size() > 1) { ArrayList<PendingIntent> sentIntents = null; ArrayList<PendingIntent> deliveredIntents = null; sentIntents = new ArrayList<PendingIntent>(); deliveredIntents = new ArrayList<PendingIntent>(); for (int i = 0; i < parts.size(); i++) { sentIntents.add(sentPI); deliveredIntents.add(deliveredPI); } for (String receiver : receivers) { try { sm.sendMultipartTextMessage(receiver, null, parts, sentIntents, deliveredIntents); } catch (IllegalArgumentException e) { Log.e(TAG, "illegal receiver: " + receiver); } } } else { for (String receiver : receivers) { try { sm.sendTextMessage(receiver, null, parts.get(0), sentPI, deliveredPI); } catch (IllegalArgumentException e) { Log.e(TAG, "illegal receiver: " + receiver); } } } } @Override protected void onHandleIntent(Intent intent) { String message = intent.getStringExtra(EXTRA_MESSAGE); String[] receivers = intent.getStringArrayExtra(EXTRA_RECEIVERS); sendSMS(message, receivers); } 

И использовать его:

  private void startMessageServiceIntent(String message, String receiver) { Intent i = new Intent(context, SMSSender.class); i.putExtra(SMSSender.EXTRA_MESSAGE, message); i.putExtra(SMSSender.EXTRA_RECEIVERS, new String[] { receiver }); startService(i) } 

Обратите внимание, что он поддерживает несколько приемников, которые этот метод не демонстрирует / не использует.

Помните в своем манифесте:

 <uses-permission android:name="android.permission.SEND_SMS" /> <service android:name="your.package.SMSSender" android:enabled="true" /> 

При желании вы можете слушать, когда сообщения отправляются и / или доставляются:

 @Override protected void onCreate() { ... // ---when the SMS has been sent--- private BroadcastReceiver messageSent; // <- stored as a field messageSent = new SentMessage(); registerReceiver(messageSent, new IntentFilter(SMSSender.INTENT_MESSAGE_SENT)); // ---when the SMS has been delivered--- private BroadcastReceiver messageDelivered; // <- stored as a field messageDelivered = new MessageDelivered(); registerReceiver(messageDelivered, new IntentFilter( SMSSender.INTENT_MESSAGE_DELIVERED)); } @Override protected void onDestroy() { // remember to unregister unregisterReceiver(messageSent); unregisterReceiver(messageDelivered ); } 

Я знаю, что это не дает ответов на все ваши вопросы, но я надеюсь, что этого достаточно.

Изменить: добавлены мои реализации messageSent и messageDelivered

Они специфичны для моей реализации, поэтому включает в себя некоторый код, который вы не можете использовать, просто для демонстрации.

Сообщение отправлено:

 public class SentMessage extends BroadcastReceiver { private final String TAG = "SentMessage"; @Override public void onReceive(Context context, Intent intent) { long _id = intent.getLongExtra(EXTRA_ID, -1); long protocol_id = intent.getLongExtra(EXTRA_PROTOCOL, -1); Log.d(TAG, "SentMessage"); switch (getResultCode()) { case Activity.RESULT_OK: Log.d(TAG, "RESULT_OK"); if (MessageData.sentMessage(_id, protocol_id)) { try { Database.messageSent(_id); } catch (DatabaseRowNotFoundException e) { Log.e(TAG, e.toString(), e); } } break; case SmsManager.RESULT_ERROR_GENERIC_FAILURE: Log.d(TAG, "RESULT_ERROR_GENERIC_FAILURE"); MessageData.postponeMessage(_id); ApplicationData.hasSignal(false); break; case SmsManager.RESULT_ERROR_NO_SERVICE: Log.d(TAG, "RESULT_ERROR_NO_SERVICE"); MessageData.postponeMessage(_id); ApplicationData.hasSignal(false); break; case SmsManager.RESULT_ERROR_NULL_PDU: Log.d(TAG, "RESULT_ERROR_NULL_PDU"); break; case SmsManager.RESULT_ERROR_RADIO_OFF: Log.d(TAG, "RESULT_ERROR_RADIO_OFF"); MessageData.postponeMessage(_id); ApplicationData.hasSignal(false); break; } } 

Сообщение доставлено:

 public class DeliveredMessage extends BroadcastReceiver { private final String TAG = "DeliveredMessage "; @Override public void onReceive(Context context, Intent intent) { long _id = intent.getLongExtra(EXTRA_ID, -1); long protocol_id = intent.getLongExtra(EXTRA_PROTOCOL, -1); switch (getResultCode()) { case Activity.RESULT_OK: if (_id != -1 && MessageData.deliveredMessage(_id, protocol_id)) { try { Database.messageDelivered(_id); Cursor messageCursor = Database.getCursorByID(MessageOutboxContentProvider.CONTENT_URI, MessageOutboxContentProvider._ID, _id); messageCursor.close(); } catch (DatabaseRowNotFoundException e) { Log.e(TAG, e.toString(), e); } } break; case Activity.RESULT_CANCELED: break; } } 

}

Я тоже нуждался в надежной отправке, поэтому сохранял ссылки на все ожидающие сообщения в базе данных, которые я часто просматривал для отложенных сообщений. Сообщение будет отложено, если нет радио, или отправка просто по какой-либо причине не выполняется.

Я также использовал GCM вместе с SMS для получения сообщения как можно быстрее, отправляя сообщения, используя оба канала одновременно.

Edit2: О, хорошо, могли бы также ответить на вопросы, мы почти все равно:

Вопрос 1: С помощью IntentService отправка выполняется в фоновом режиме.

Вы только хотите, чтобы отправка произошла один раз после задержки, поэтому вы должны сделать это вместо этого:

  new Handler().postDelayed(new Runnable() { @Override public void run() { // send sms } }, delay); 

Вопрос 2: Легко, когда ваше переданное сообщение отправляет сообщение об ошибке, выполните описанный выше метод. Вы можете добавить дополнительную информацию, помимо получателя и сообщения, подсчитывая количество попыток до сих пор, чтобы у вас была возможность остановить цикл отправки / повтора.

Вопрос 3: Передача останавливается сама по себе, так как это служба намерений. Что касается другой службы, самым простым подходом, я думаю, было бы отправить общую трансляцию, которая подхвачена вашей основной деятельностью. Таким образом, вы можете получить доступ к сервису в нужное место и остановить его.