Запросить подтверждение по SMS в приложении для Android

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

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

Прежде чем вы начнете

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

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

Убедитесь, что в файле сборки вашего приложения используются следующие значения:

  • MinSdkVersion 19 или выше
  • CompileSdkVersion 28 или выше

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

В файле build.gradle уровне проекта, включают в себя репозиторий Maven от buildscript allprojects Google и Maven центрального хранилища в обоих вашей buildscript и allprojects разделах:

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

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

Добавьте Play сервисы Google зависимость для SMS Retriever API для вашего файла сборки модуля Gradle , который обычно 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. Получите номер телефона пользователя.

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

// 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. Запустите SMS-загрузчик.

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

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

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

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

Ваш сервер генерирует проверочное сообщение и отправляет его по SMS на указанный вами номер телефона. См Выполните SMS Проверка на сервере .

4. Получать проверочные сообщения.

Когда проверочное сообщение получено на устройстве пользователя, Play услуга явно вещает приложение SmsRetriever.SMS_RETRIEVED_ACTION Intent, который содержит текст сообщения. Используйте BroadcastReceiver получить это сообщение проверки.

В BroadcastReceiver «s onReceive обработчика, получить текст сообщения подтверждения от х статистов Намерения:

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

Зарегистрируйте этот 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>

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

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

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

Необязательно: сохраните номер телефона с помощью Smart Lock для паролей.

При желании, после того, как пользователь подтвердил свой номер телефона, вы можете предложить пользователю сохранить этот номер телефона с помощью Smart Lock для паролей, чтобы он был автоматически доступен в других приложениях и на других устройствах без необходимости вводить или выбирать номер телефона повторно. :

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);
                    }
                }
            });

Затем, после того, как пользователь переустанавливает приложение или устанавливает приложение на новом устройстве, вы можете получить сохраненный номер телефона, не спрашивая снова его номер телефона:

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