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?
- ¿Por qué obtengo NullPointerException al enviar un SMS en un HTC Desire, o lo que es SubmitPdu?
- ¿Cómo enviar sms al apagar el teléfono en android?
- Estado de sms de Android
- Android enviando muchos mensajes SMS
- Cómo enviar caracteres no impresos a través de SMS
- Casting un objeto java a objeto en Scala
- Cómo eliminar un SMS de la bandeja de entrada en Android mediante programación?
- Caracteres especiales en sms de Android
- Android: detecta SMS saliente, cuenta incorrecta
- Cuando envío SMS, a veces código de resultado = 0. ¿Qué significa ese código?
- Puedo enviar "SMS recibido intención"?
- Android: recibe SMS largos (multipart)
- Volver a Actividad después de completar la acción en Android?
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 laActivity
registro, etcSmsReceiver 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, usandoSmsManager#divideMessage()
, y pasando elArrayList
resultante a ese método, en lugar del mensajeString
. Para volver a montar el mensaje completo en el Receptor, tendría que decodificar cadabyte[]
en unSmsMessage
, 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 argumentoshort
adicional para el número de puerto (arbitrario), y el mensaje se pasa como unbyte[]
, en lugar de unaString
. 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 elbyte[]
mensajebyte[]
se recupera congetUserData()
, en lugar degetMessageBody()
. -
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 atributoandroid:priority="999"
se agrega a la etiqueta de apertura<intent-filter>
. De forma dinámica, elIntentFilter#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étodoregisterReceiver()
, pasando ese permisoString
como el tercer argumento ynull
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/
- Cómo implementar un escucha
- ¿Cómo deshabilitar la acción "pull to refresh" y usar sólo el indicador?