BroadcastReceiver + SMS_RECEIVED

Me gustaría que mi aplicación capte los mensajes SMS entrantes. Hay algunos ejemplos de esto alrededor. Parece que solo tenemos que hacer esto:

// AndroidManifest.xml      // SMSReceiver.java public class SMSReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Log.i(TAG, "SMS received."); .... } } 

¿es esto correcto? Estoy enviando algunos mensajes SMS a mi teléfono, pero la statement de registro nunca se imprime. Tengo algunas otras aplicaciones de SMS instaladas en el teléfono, que muestran una ventana emergente cuando se recibe el sms. ¿Están de alguna manera bloqueando el bash de que se transfiera a mi aplicación, solo la están consumiendo por completo?

Gracias

También necesitaría especificar un permiso de uso en su archivo de manifiesto:

  

Los siguientes tutoriales deberían ayudar:

Reaccionar en SMS entrantes
Mensajes SMS en Android

Una cosa más que estas respuestas no han mencionado: debe solicitar el permiso android.permission.BROADCAST_SMS. Si no lo hace, cualquier aplicación puede falsificar mensajes en su aplicación.

      

Hay algunos problemas en el camino. Puede encontrar toda la información necesaria en stackoverflow. He reunido toda la información en esta respuesta, por conveniencia.

Cosas para ser notado

  1. Asumo Kitkat de Android y más.
  2. La intención de los sms entrantes es "android.provider.Telephony.SMS_RECEIVED"
  3. Puede cambiar la prioridad del filtro de intención, pero no es necesario.
  4. Necesita este permiso "android.permission.RECEIVE_SMS" en manifiesto xml, para poder recibir mensajes SMS. En Android 6 y superior, también debe solicitar el permiso en tiempo de ejecución.
  5. No necesita establecer el tipo de datos MIME en el filtro de intención. El filtro de intención debe pasar solo en datos vacíos si no se establece un tipo MIME, pero afortunadamente funcionará sin MIME.
  6. adb shell am broadcast no funcionará. Use la conexión telnet al simulador para probar la recepción de mensajes SMS.
  7. Los mensajes de SMS largos se dividen en pequeños fragmentos de sms. Necesitamos concatenarlos.

Cómo enviar un mensaje de SMS al emulador

Lo más importante es tener la posibilidad de enviar mensajes SMS falsos al dispositivo, para que podamos probar el código.

Para esto, utilizaremos un dispositivo virtual y una conexión Telnet.

  1. Crea un dispositivo virtual en el estudio de Android y ejecuta el simulador
  2. Mira la barra de título en la ventana del simulador. Existe el nombre del dispositivo y un número de puerto . Necesitamos saber este número de puerto en los siguientes pasos.
  3. Ahora conéctese al número de puerto que se muestra en la barra de título del simulador con telnet

      $ telnet localhost 5554 
  4. Si ve esto: Android Console: Authentication required , entonces necesita autenticar la conexión con este comando:

      auth xxxxxx 

    Reemplace el xxxxxx anterior con la lectura del token del archivo ~/.emulator_console_auth_token .

  5. Ahora debería poder ejecutar todos los comandos. Para enviar un mensaje SMS, escriba este comando:

      sms send 555 "This is a message" 

    Donde puede reemplazar 555 con el número de teléfono del remitente y un mensaje propio.

Cómo escuchar transmisiones SMS_RECEIVED

Para obtener las transmisiones, debe registrar un objeto BroadcastReceiver . Puede hacer esto en manifest.xml O simplemente llamar a la función registerReceiver . Te mostraré lo último, ya que es más fácil razonar y aún más flexible.

Conectar el receptor de difusión con la actividad principal

El flujo de datos es de una sola manera. Del receptor de difusión a la actividad principal. Entonces, la forma más sencilla de lograr que hablen es usar una interfaz de función. La actividad implementará tal función y el receptor de difusión tendrá la instancia de actividad pasada como un parámetro en el constructor.

Archivo SmsHandler.java:

 package ... interface SmsHandler { void handleSms(String sender, String message); } 

Implementando el receptor de difusión

El receptor de la transmisión obtendrá la intención en una callback. Usaremos la función Telephony.Sms.Intents.getMessagesFromIntent(intent) para obtener los mensajes sms. Observe el parámetro SmsHandler en el constructor. Será la actividad a la que enviaremos los sms recibidos.

Archivo SmsInterceptor.java:

 package ... import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.provider.Telephony; import android.telephony.SmsMessage; public class SmsInterceptor extends BroadcastReceiver { private SmsHandler handler; /* Constructor. Handler is the activity * * which will show the messages to user. */ public SmsInterceptor(SmsHandler handler) { this.handler = handler; } @Override public void onReceive(Context context, Intent intent) { /* Retrieve the sms message chunks from the intent */ SmsMessage[] rawSmsChunks; try { rawSmsChunks = Telephony.Sms.Intents.getMessagesFromIntent(intent); } catch (NullPointerException ignored) { return; } /* Gather all sms chunks for each sender separately */ Map sendersMap = new HashMap<>(); for (SmsMessage rawSmsChunk : rawSmsChunks) { if (rawSmsChunk != null) { String sender = rawSmsChunk.getDisplayOriginatingAddress(); String smsChunk = rawSmsChunk.getDisplayMessageBody(); StringBuilder smsBuilder; if ( ! sendersMap.containsKey(sender) ) { /* For each new sender create a separate StringBuilder */ smsBuilder = new StringBuilder(); sendersMap.put(sender, smsBuilder); } else { /* Sender already in map. Retrieve the StringBuilder */ smsBuilder = sendersMap.get(sender); } /* Add the sms chunk to the string builder */ smsBuilder.append(smsChunk); } } /* Loop over every sms thread and concatenate the sms chunks to one piece */ for ( Map.Entry smsThread : sendersMap.entrySet() ) { String sender = smsThread.getKey(); StringBuilder smsBuilder = smsThread.getValue(); String message = smsBuilder.toString(); handler.handleSms(sender, message); } } } 

La actividad principal

Finalmente, debemos implementar la interfaz SmsHandler en la actividad principal y agregar el registro del receptor de difusión y la verificación de permisos a la función onCreate .

Archivo MainActivity.java:

 package ... import ... public class MainActivity extends AppCompatActivity implements SmsHandler { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); /* Register the broadcast receiver */ registerSmsListener(); /* Make sure, we have the permissions */ requestSmsPermission(); } /* This function will be called by the broadcast receiver */ @Override public void handleSms(String sender, String message) { /* Here you can display the message to the user */ } private void registerSmsListener() { IntentFilter filter = new IntentFilter(); filter.addAction("android.provider.Telephony.SMS_RECEIVED"); /* filter.setPriority(999); This is optional. */ SmsInterceptor receiver = new SmsInterceptor(this); registerReceiver(receiver, filter); } private void requestSmsPermission() { String permission = Manifest.permission.RECEIVE_SMS; int grant = ContextCompat.checkSelfPermission(this, permission); if ( grant != PackageManager.PERMISSION_GRANTED) { String[] permission_list = new String[1]; permission_list[0] = permission; ActivityCompat.requestPermissions(this, permission_list, 1); } } } 

Por último, recuerde agregar el permiso RECEIVE_SMS a su manifest xml

     ...   

También tenga en cuenta que la aplicación Hangouts bloqueará actualmente que BroadcastReceiver no reciba mensajes SMS. Tuve que deshabilitar la funcionalidad de SMS en la aplicación de Hangouts (Configuración-> SMS-> Activar SMS), antes de que mi SMS BroadcastReceived comenzara a ser despedido.

Editar: parece que algunas aplicaciones abortaránBroadcast () con la intención de evitar que otras aplicaciones reciban el bash. La solución es boost el atributo android:priority en la etiqueta de intent-filter :

       

Ver más detalles aquí: Habilitar el soporte de SMS en Hangouts 2.0 rompe el BroadcastReceiver de SMS_RECEIVED en mi aplicación

¿Lo intentaste con el emulador ?

Después de implementar su aplicación en el emulador, puede enviar eventos como SMS a través del DDMS o a través de la línea de comando al conectarse con telnet:

 telnet localhost  send sms   

port_emulator es generalmente 5554

Debería leer esta acción sobre enviar y recibir sms programáticamente. http://mobiforge.com/developing/story/sms-messaging-android