android - usar - verificar mi numero en google
Usando SMS para verificar el número de teléfono de un dispositivo (1)
Para empezar, esto requerirá dos permisos; Uno para enviar mensajes SMS, y otro para recibirlos. Lo siguiente debe estar en su 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" />
Ambos son permisos peligrosos, por lo que deberá manejarlos en consecuencia si su aplicación se ejecuta en Marshmallow (nivel de API 23) o superior, y tiene una targetSdkVersion
de 23+. La información sobre cómo solicitar estos permisos en tiempo de ejecución se puede encontrar en esta página para desarrolladores .
Las clases de Java que necesitarás están en el paquete android.telephony
; específicamente android.telephony.SmsManager
y android.telephony.SmsMessage
. Asegúrese de que ha importado las clases correctas 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)
Solo se requieren dos argumentos en este método de llamada: destinationAddress
y text
; el primero es el número de teléfono, el segundo es el contenido del mensaje. Se puede pasar null
por 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()
generalmente fallará en silencio si la longitud del texto excede el límite de caracteres para un solo mensaje.
Para recibir y leer el mensaje entrante, deberá registrar un BroadcastReceiver
con un IntentFilter
para la acción "android.provider.Telephony.SMS_RECEIVED"
. Este receptor se puede registrar estáticamente 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 su aplicación reciba el mensaje entrante, incluso si su aplicación se elimina antes de que se reciba. Sin embargo, puede requerir un poco de trabajo extra para obtener los resultados donde los desea. 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.Registrar dinámicamente una instancia de Receiver en un
Context
puede ser un poco más fácil de administrar, a nivel de código, ya que la clase de Receiver se puede convertir en una clase interna en cualquier componente que la registre, y por lo tanto, tener acceso directo a los miembros de ese componente. Sin embargo, este enfoque podría no ser tan confiable como el registro estático, ya que algunas cosas diferentes podrían evitar que el Receptor obtenga la transmisión; por ejemplo, el proceso de su aplicación se está eliminando, el usuario se está alejando de laActivity
registro, etc.SmsReceiver receiver = new SmsReceiver(); IntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED"); registerReceiver(receiver, filter);
Recuerde anular el registro del Receptor cuando sea apropiado.
En el método onReceive()
del receptor, el mensaje real se presenta como una matriz de matrices de byte
adjuntas a la Intent
como un extra. Los detalles de decodificación varían según la versión de Android, pero el resultado aquí es un único objeto de SmsMessage
que tendrá el número de teléfono y el mensaje que está buscando.
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 compare el number
aquí con el que pasó a la llamada sendTextMessage()
. Es aconsejable usar PhoneNumberUtils.compare()
para esto, ya que el número recuperado en el Receptor puede estar en un formato diferente al que se trata.
Notas:
El ejemplo que se muestra aquí es el uso de un mensaje de una sola parte, por lo que el texto del mensaje debe restringirse a una longitud relativamente corta. Si desea enviar un mensaje más largo, por algún motivo, puede usar el método
sendMultipartTextMessage()
. Necesitaría dividir el texto primero, usandoSmsManager#divideMessage()
, y pasar laArrayList
resultante a ese método, en lugar del mensajeString
. Para volver a ensamblar el mensaje completo en el receptor, tendría que decodificar cadabyte[]
en unSmsMessage
y concatenar los cuerpos del mensaje.Desde KitKat (nivel de API 19), si su aplicación no es la aplicación de mensajería predeterminada, el sistema y la aplicación predeterminada guardarán los mensajes utilizados aquí, y por lo tanto estarán disponibles para cualquier otra aplicación que use el Proveedor. No hay mucho que puedas hacer al respecto, pero si realmente quieres evitarlo, esta misma técnica se puede usar con datos SMS, que no activan la aplicación predeterminada y no se guardarán en el Proveedor.
Para esto, se usa el método
sendDataMessage()
, que necesitará unshort
argumento 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 autorización (host y puerto) establecidos. En el manifiesto, se verí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.Descodificar el
SmsMessage
es el mismo, pero elbyte[]
del 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 ello.
Los mensajes entrantes se pueden interceptar y sus transmisiones se anulan antes de que la aplicación de mensajería principal pueda recibirlos y escribirlos. Para lograr esto, la prioridad del filtro se establece en el máximo, y se llama a
abortBroadcast()
en el Receptor. En la opción estática, el atributoandroid:priority="999"
se agrega a la etiqueta de apertura<intent-filter>
. Dinámicamente, elIntentFilter#setPriority()
puede hacer lo mismo.Esto no es en absoluto confiable, 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 no lo dejaría abierto a ningún tipo de falsificación que pudiera hacer daño. Sin embargo, si desea incluir esto, simplemente 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, use la sobrecarga de cuatro parámetros del métodoregisterReceiver()
, pasando eseString
permiso como tercer argumento ynull
como el cuarto.
Estoy tratando de verificar el número de teléfono de un dispositivo Android haciendo que el dispositivo se envíe un SMS a sí mismo y verifique automáticamente si el SMS ha sido recibido. ¿Cómo puedo hacer esto?