Solicitar verificación por SMS en una aplicación de Android

Para verificar automáticamente los números de teléfono, debe implementar las partes del cliente y del servidor del flujo de verificación. Este documento describe cómo implementar la parte del cliente en una aplicación de Android.

Para iniciar el flujo de verificación del número de teléfono en una aplicación de Android, envíe el número de teléfono a su servidor de verificación y llame a la API de SMS Retriever para comenzar a escuchar un mensaje SMS que contenga un código único para su aplicación. Después de recibir el mensaje, envía el código de un solo uso a su servidor para completar el proceso de verificación.

Antes de que empieces

Para preparar su aplicación, complete los pasos en las siguientes secciones.

Requisitos previos de la aplicación

Asegúrese de que el archivo de compilación de su aplicación utilice los siguientes valores:

  • Una minSdkVersion de 19 o superior
  • Una compileSdkVersion de 28 o superior

Configura tu aplicación

En el archivo de build.gradle a nivel de proyecto, incluir repositorio de Maven de Google y el repositorio central de Maven , tanto en su buildscript y allprojects secciones:

buildscript {
    repositories {
        google()
        mavenCentral()
    }
}

allprojects {
    repositories {
        google()
        mavenCentral()
    }
}

Añadir el servicio Google Play dependencia para el SMS API Retriever para su fichero de construcción Gradle del módulo , que es comúnmente app/build.gradle :

dependencies {
  implementation 'com.google.android.gms:play-services-auth:19.2.0'
  implementation 'com.google.android.gms:play-services-auth-api-phone:17.5.1'
}

1. Obtenga el número de teléfono del usuario

Puede obtener el número de teléfono del usuario de la forma adecuada para su aplicación. A menudo, la mejor experiencia de usuario es utilizar el selector de sugerencias para pedirle al usuario que elija entre los números de teléfono almacenados en el dispositivo y así evitar tener que escribir manualmente un número de teléfono. Para usar el selector de sugerencias:

// Construct a request for phone numbers and show the picker
private void requestHint() {
    HintRequest hintRequest = new HintRequest.Builder()
           .setPhoneNumberIdentifierSupported(true)
           .build();

    PendingIntent intent = Auth.CredentialsApi.getHintPickerIntent(
            apiClient, hintRequest);
    startIntentSenderForResult(intent.getIntentSender(),
            RESOLVE_HINT, null, 0, 0, 0);
}

// Obtain the phone number from the result
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
  super.onActivityResult(requestCode, resultCode, data);
  if (requestCode == RESOLVE_HINT) {
      if (resultCode == RESULT_OK) {
          Credential credential = data.getParcelableExtra(Credential.EXTRA_KEY);
          // credential.getId();  <-- will need to process phone number string
      }
  }
}

2. Inicie el recuperador de SMS

Cuando esté listo para verificar el número de teléfono del usuario, obtener una instancia de la SmsRetrieverClient objeto, llamar startSmsRetriever , y adjuntar éxito y fracaso a los oyentes a la tarea de recuperación de SMS:

// Get an instance of SmsRetrieverClient, used to start listening for a matching
// SMS message.
SmsRetrieverClient client = SmsRetriever.getClient(this /* context */);

// Starts SmsRetriever, which waits for ONE matching SMS message until timeout
// (5 minutes). The matching SMS message will be sent via a Broadcast Intent with
// action SmsRetriever#SMS_RETRIEVED_ACTION.
Task<Void> task = client.startSmsRetriever();

// Listen for success/failure of the start Task. If in a background thread, this
// can be made blocking using Tasks.await(task, [timeout]);
task.addOnSuccessListener(new OnSuccessListener<Void>() {
  @Override
  public void onSuccess(Void aVoid) {
    // Successfully started retriever, expect broadcast intent
    // ...
  }
});

task.addOnFailureListener(new OnFailureListener() {
  @Override
  public void onFailure(@NonNull Exception e) {
    // Failed to start retriever, inspect Exception for more details
    // ...
  }
});

La tarea de recuperación de SMS escuchará durante hasta cinco minutos un mensaje SMS que contenga una cadena única que identifique su aplicación.

3. Envíe el número de teléfono a su servidor

Una vez que haya obtenido el número de teléfono del usuario y haya comenzado a escuchar mensajes SMS, envíe el número de teléfono del usuario a su servidor de verificación utilizando cualquier método (generalmente con una solicitud HTTPS POST).

Su servidor genera un mensaje de verificación y lo envía por SMS al número de teléfono que especificó. Ver Realizar Verificación de SMS en el servidor .

4. Recibir mensajes de verificación

Cuando se recibe un mensaje de verificación en el dispositivo del usuario, servicios de reproducir emisiones de forma explícita a la aplicación de un SmsRetriever.SMS_RETRIEVED_ACTION Intención, que contiene el texto del mensaje. Use un BroadcastReceiver recibir este mensaje de verificación.

En el BroadcastReceiver 's onReceive manipulador, obtener el texto del mensaje de verificación de los extras de Intención:

/**
 * BroadcastReceiver to wait for SMS messages. This can be registered either
 * in the AndroidManifest or at runtime.  Should filter Intents on
 * SmsRetriever.SMS_RETRIEVED_ACTION.
 */
public class MySMSBroadcastReceiver extends BroadcastReceiver {

  @Override
  public void onReceive(Context context, Intent intent) {
    if (SmsRetriever.SMS_RETRIEVED_ACTION.equals(intent.getAction())) {
      Bundle extras = intent.getExtras();
      Status status = (Status) extras.get(SmsRetriever.EXTRA_STATUS);

      switch(status.getStatusCode()) {
        case CommonStatusCodes.SUCCESS:
          // Get SMS message contents
          String message = (String) extras.get(SmsRetriever.EXTRA_SMS_MESSAGE);
          // Extract one-time code from the message and complete verification
          // by sending the code back to your server.
          break;
        case CommonStatusCodes.TIMEOUT:
          // Waiting for SMS timed out (5 minutes)
          // Handle the error ...
          break;
      }
    }
  }
}

Registre esta BroadcastReceiver con el filtro intención com.google.android.gms.auth.api.phone.SMS_RETRIEVED (el valor de la SmsRetriever.SMS_RETRIEVED_ACTION constante) y el permiso com.google.android.gms.auth.api.phone.permission.SEND (el valor de la SmsRetriever.SEND_PERMISSION constante) en su aplicación de AndroidManifest.xml archivo, como en el siguiente ejemplo, o dinámicamente usando Context.registerReceiver .

<receiver android:name=".MySMSBroadcastReceiver" android:exported="true"
          android:permission="com.google.android.gms.auth.api.phone.permission.SEND">
    <intent-filter>
        <action android:name="com.google.android.gms.auth.api.phone.SMS_RETRIEVED"/>
    </intent-filter>
</receiver>

5. Envíe el código de un solo uso del mensaje de verificación a su servidor

Ahora que tiene el texto del mensaje de verificación, use una expresión regular o alguna otra lógica para obtener el código de un solo uso del mensaje. El formato del código de un solo uso depende de cómo lo implementó en su servidor.

Finalmente, envíe el código de un solo uso a su servidor a través de una conexión segura. Cuando su servidor recibe el código de un solo uso, registra que el número de teléfono ha sido verificado.

Opcional: guarde el número de teléfono con Smart Lock para contraseñas

Opcionalmente, después de que el usuario haya verificado su número de teléfono, puede solicitar al usuario que guarde esta cuenta de número de teléfono con Smart Lock para contraseñas para que esté disponible automáticamente en otras aplicaciones y en otros dispositivos sin tener que escribir o seleccionar el número de teléfono nuevamente. :

Credential credential = new Credential.Builder(phoneNumberString)
        .setAccountType("https://signin.example.com")  // a URL specific to the app
        .setName(displayName)  // optional: a display name if available
        .build();
Auth.CredentialsApi.save(apiClient, credential).setResultCallback(
            new ResultCallback() {
                public void onResult(Result result) {
                    Status status = result.getStatus();
                    if (status.isSuccess()) {
                        Log.d(TAG, "SAVE: OK");  // already saved
                    } else if (status.hasResolution()) {
                        // Prompt the user to save
                        status.startResolutionForResult(this, RC_SAVE);
                    }
                }
            });

Luego, después de que el usuario reinstale la aplicación o la instale en un nuevo dispositivo, puede recuperar el número de teléfono guardado sin tener que volver a pedirle al usuario su número de teléfono:

// On the next install, retrieve the phone number
mCredentialRequest = new CredentialRequest.Builder()
    .setAccountTypes("https://signin.example.com")  // the URL specific to the developer
    .build();
Auth.CredentialsApi.request(apiClient, mCredentialRequest).setResultCallback(
    new ResultCallback<CredentialRequestResult>() {
        public void onResult(CredentialRequestResult credentialRequestResult) {
            if (credentialRequestResult.getStatus().isSuccess()) {
                credentialRequestResult.getCredential().getId();  // this is the phone number
            }
        }
    });

// Then, initiate verification and sign the user in (same as original verification logic)