Uso de SMS para verificar el número de teléfono de un dispositivo

Estoy tratando de verificar el número de teléfono de un dispositivo Android al hacer que el dispositivo envíe un SMS a sí mismo y compruebe automáticamente si se ha recibido el SMS. ¿Cómo puedo hacer esto?

Para empezar, esto requerirá dos permisos; Uno para enviar mensajes SMS, y otro para recibirlos. Lo siguiente debe estar en tu AndroidManifest.xml, entre las etiquetas <manifest> , pero fuera de las etiquetas <application> .

 <uses-permission android:name="android.permission.SEND_SMS" /> <uses-permission android:name="android.permission.RECEIVE_SMS" /> 

Estos son los dos permisos peligrosos, por lo que tendrá que manejar en consecuencia si su aplicación se ejecuta en Marshmallow (API nivel 23) o superior, y tiene una targetSdkVersion de 23 +. Puede encontrar información sobre cómo solicitar estos permisos en tiempo de ejecución en esta página de desarrollador .


Las clases Java que necesitará están en el paquete android.telephony ; Específicamente android.telephony.SmsManager y android.telephony.SmsMessage . Asegúrese de que tiene las clases correctas importadas para ambos.

Para enviar el SMS saliente, utilizará el SmsManager sendTextMessage() , que tiene la siguiente firma:

 sendTextMessage(String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent) 

Sólo se requieren dos argumentos en esta llamada de método: destinationAddress y text ; Siendo el primero el número de teléfono, el segundo el contenido del mensaje. null se puede pasar para el resto. Por ejemplo:

 String number = "1234567890"; String message = "Verification message."; SmsManager sm = SmsManager.getDefault(); sm.sendTextMessage(number, null, message, null, null); 

Es importante mantener el texto del mensaje relativamente corto, ya que sendTextMessage() suele fallar en silencio si la longitud del texto excede el límite de caracteres para un único mensaje.


Para recibir y leer el mensaje entrante, necesitará registrar un BroadcastReceiver con un IntentFilter para la acción "android.provider.Telephony.SMS_RECEIVED" . Este Receptor puede registrarse de forma estática en el manifiesto, o dinámicamente en un Context en tiempo de ejecución.

  • El registro estático de la clase Receiver en el manifiesto permitirá que tu aplicación reciba el mensaje entrante aunque tu aplicación deba matarse antes de la recepción. Puede, sin embargo, tomar un poco de trabajo extra para obtener los resultados donde desee. Entre las etiquetas <application> :

     <receiver android:name=".SmsReceiver" android:enabled="false"> <intent-filter> <action android:name="android.provider.Telephony.SMS_RECEIVED" /> </intent-filter> </receiver> 

    El método PackageManager#setComponentEnabledSetting() se puede usar para habilitar y deshabilitar este <receiver> según sea necesario.

  • El registro dinámico de una instancia de Receptor en un Context puede ser un poco más fácil de manejar, por código, ya que la clase Receptor podría ser una clase interna en el componente que la registra y, por lo tanto, tener acceso directo a los miembros de ese componente. Sin embargo, este enfoque podría no ser tan fiable como el registro estático, ya que algunas cosas diferentes podrían impedir que el receptor de obtener la emisión; Por ejemplo, el proceso de su aplicación se está matando, el usuario navega fuera de la Activity registro, etc

     SmsReceiver receiver = new SmsReceiver(); IntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED"); registerReceiver(receiver, filter); 

    Recuerde desregistrar al Receptor cuando sea apropiado.


En el método onReceive() del receptor, el mensaje real aparece como una matriz de arrays de byte conectados al Intent como extra. Los detalles de descodificación varían dependiendo de la versión de Android, pero el resultado aquí es un único objeto SmsMessage que tendrá el número de teléfono y el mensaje que SmsMessage .

 class SmsReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { SmsMessage msg; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { SmsMessage[] msgs = Telephony.Sms.Intents.getMessagesFromIntent(intent); msg = msgs[0]; } else { Object pdus[] = (Object[]) intent.getExtras().get("pdus"); msg = SmsMessage.createFromPdu((byte[]) pdus[0]); } String number = msg.getOriginatingAddress(); String message = msg.getMessageBody(); ... } } 

En este punto, simplemente compara el number aquí con el que pasó a la llamada sendTextMessage() . Es aconsejable utilizar PhoneNumberUtils.compare() para esto, ya que el número recuperado en el Receptor puede estar en un formato diferente al que se ha dirigido.


Notas:

  • El ejemplo demostrado aquí es el uso de un mensaje de una sola pieza, por lo tanto, por qué el texto del mensaje debe limitarse a una longitud relativamente corta. Si desea enviar un mensaje más largo, por alguna razón, se puede usar el método sendMultipartTextMessage() . Usted necesitaría dividir el texto primero, usando SmsManager#divideMessage() , y pasando el ArrayList resultante a ese método, en lugar del mensaje String . Para volver a montar el mensaje completo en el Receptor, tendría que decodificar cada byte[] en un SmsMessage , y concatenar los cuerpos del mensaje.

  • Desde KitKat (API nivel 19), si su aplicación no es la aplicación de mensajería predeterminada, los mensajes utilizados aquí se guardarán en el proveedor de SMS por el sistema y la aplicación predeterminada y, por lo tanto, estarán disponibles para cualquier otra aplicación que utilice la aplicación Proveedor. No hay mucho que puedes hacer al respecto, pero si realmente quieres evitarlo, esta misma técnica puede usarse con los datos SMS, que no activan la aplicación predeterminada, y no se guardarán en el proveedor.

    Para ello, se utiliza el método sendDataMessage() , que necesitará un argumento short adicional para el número de puerto (arbitrario), y el mensaje se pasa como un byte[] , en lugar de una String . La acción para filtrar es "android.intent.action.DATA_SMS_RECEIVED" , y el filtro necesitará un esquema de datos y la autoridad (host y puerto) establecidos. En el manifiesto, sería como:

     <intent-filter> <action android:name="android.intent.action.DATA_SMS_RECEIVED" /> <data android:scheme="sms" android:host="localhost" android:port="1234" /> </intent-filter> 

    Y hay métodos correspondientes en la clase IntentFilter para establecerlos dinámicamente.

    La descodificación de SmsMessage es la misma, pero el byte[] mensaje byte[] se recupera con getUserData() , en lugar de getMessageBody() .

  • Antes de KitKat, las aplicaciones eran responsables de escribir sus propios mensajes salientes, por lo que simplemente no puede hacer eso en esas versiones, si no desea ningún registro de la misma.

    Los mensajes entrantes podrían ser interceptados, y sus transmisiones abortadas antes de que la aplicación de mensajería principal pudiera recibir y escribirlas. Para lograr esto, la prioridad del filtro se establece en el máximo, y abortBroadcast() se llama en el receptor. En la opción estática, el atributo android:priority="999" se agrega a la etiqueta de apertura <intent-filter> . De forma dinámica, el IntentFilter#setPriority() puede hacer lo mismo.

    Esto no es del todo fiable, ya que siempre es posible que otra aplicación tenga una prioridad más alta que la suya.

  • He omitido asegurar el receptor con el permiso de la emisora ​​en estos ejemplos, en parte por simplicidad y claridad, y en parte porque la naturaleza de la cosa realmente no te dejaría abierto a cualquier tipo de suplantación que podría hacer daño. Sin embargo, si desea incluir esto, sólo necesita agregar el atributo android:permission="android.permission.BROADCAST_SMS" a la etiqueta de apertura <receiver> para la opción estática. Para la dinámica, utilice la sobrecarga de cuatro parámetros del método registerReceiver() , pasando ese permiso String como el tercer argumento y null como el cuarto.

Sinch SDK le permite verificar el número de teléfono del usuario mediante la tecnología de llamadas flash. Se basa en la red telefónica normal, por lo que si el número de teléfono del usuario es válido, recibirá una llamada perdida.

 private void startVerification(String phoneNumber) { Config config = SinchVerification.config().applicationKey("your_app_key").context(getApplicationContext()).build(); VerificationListener listener = new MyVerificationListener(); verification = SinchVerification.createFlashCallVerification(config, phoneNumber, listener); verification.initiate(); } 

Para obtener más información, puede consultar este tutorial:

https://www.sinch.com/tutorials/android-flash-call-verification/

  • Android: obtenga la hora de la fecha de la marca de tiempo de SMS en milisegundos
  • Android 1.6 SMS (antiguo código de aplicación)
  • Abrir la conversación de SMS principal en android
  • Android: Leer / Enviar mensajes de texto en Ubuntu?
  • Observe los SMS que envían la aplicación en el emulador
  • Interceptar mensaje SMS entrante y modificarlo
  • Obtener mensajes SMS desde la tarjeta SIM
  • Android receptor SMS no funciona
  • Crear PDU para Android
  • Mantener un registro de los SMS enviados en Android
  • ACTION_SEND utilizado para enviar sms
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.