Как запросить подтверждение по SMS в приложении Android

Чтобы автоматически подтверждать номера телефонов, необходимо реализовать как клиентскую, так и серверную части процесса подтверждения. В этом документе описывается, как реализовать клиентскую часть в приложении для Android.

Чтобы начать подтверждение номера телефона в приложении для Android, отправьте номер телефона на сервер подтверждения и вызовите SMS Retriever API. Это позволит начать прослушивание SMS-сообщения, содержащего одноразовый код для вашего приложения. Получив сообщение, отправьте одноразовый код обратно на сервер, чтобы завершить процесс подтверждения.

Чтобы подготовить приложение, выполните нужные действия в разделах, указанных ниже.

Требования к приложению

Убедитесь, что в файле сборки приложения приведены значения, указанные ниже.

  • minSdkVersion: 19 или выше.
  • compileSdkVersion 28 или выше;

Настройка приложения

В файле build.gradle на уровне проекта добавьте репозиторий Maven от Google и центральный репозиторий Maven в разделы buildscript и allprojects:

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

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

Добавьте зависимость сервисов Google Play для SMS Retriever API в файл build.gradle модуля – обычно это app/build.gradle:

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

Получить номер телефона пользователя

Вы можете получить номер телефона пользователя любым способом, подходящим для вашего приложения. Часто лучший пользовательский опыт – использовать средство выбора подсказок, чтобы предложить пользователю выбрать один из номеров телефонов, хранящихся на устройстве, и тем самым избежать необходимости вводить номер телефона вручную. Чтобы использовать подсказки:

// 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
      }
  }
}

Запустите SMS Retriever

Когда вы будете готовы подтвердить номер телефона пользователя, получите экземпляр объекта SmsRetrieverClient, вызовите startSmsRetriever и прикрепите прослушиватели успешного и неудачного выполнения к задаче получения 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 using 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
    // ...
  }
});

Задача получения SMS-сообщений ожидает в течение пяти минут SMS-сообщение, содержащее уникальную строку, которая идентифицирует ваше приложение.

Отправьте номер телефона на свой сервер.

После того как вы получили номер телефона пользователя и начали прослушивать SMS-сообщения, отправьте номер телефона пользователя на сервер проверки любым способом (обычно с помощью запроса HTTPS POST).

Ваш сервер генерирует сообщение для подтверждения и отправляет его в виде SMS на указанный номер телефона. Подробнее о том, как выполнить проверку SMS на сервере…

Получать сообщения для подтверждения

Когда на устройство пользователя приходит сообщение с кодом подтверждения, сервисы Google Play передают вашему приложению намерение SmsRetriever.SMS_RETRIEVED_ACTION, которое содержит текст сообщения. Чтобы получить сообщение с кодом подтверждения, используйте BroadcastReceiver.

В обработчике onReceive BroadcastReceiver получите текст сообщения с кодом подтверждения (и, если нужно, адрес отправителя) из дополнительных данных Intent:

/**
  *   BroadcastReceiver to wait for SMS messages. This can be registered either
  *   in the AndroidManifest or at runtime. Filters 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:
          // (Optional) Get SMS Sender address - only available in
          // GMS version 24.20 onwards, else it will return null
          String senderAddress = extras.getString(SmsRetriever.EXTRA_SMS_ORIGINATING_ADDRESS);
          // Get SMS message contents
          String message = extras.getString(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;
      }
    }
  }
}

Чтобы зарегистрировать этот BroadcastReceiver, используйте следующее:

  • Фильтр интентов: com.google.android.gms.auth.api.phone.SMS_RETRIEVED (значение константы SmsRetriever.SMS_RETRIEVED_ACTION)
  • Разрешение: com.google.android.gms.auth.api.phone.permission.SEND (значение константы SmsRetriever.SEND_PERMISSION).

Вы можете зарегистрировать получатель в файле AndroidManifest.xml приложения, как показано в примере ниже, или динамически с помощью 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>

Отправьте одноразовый код из сообщения с подтверждением на свой сервер.

Теперь, когда у вас есть текст сообщения, используйте регулярное выражение или другую логику, чтобы получить одноразовый код. Формат одноразового кода зависит от того, как вы реализовали его на сервере.

Наконец, отправьте одноразовый код на свой сервер по защищенному соединению. Когда сервер получает одноразовый код, он регистрирует, что номер телефона подтвержден.