درخواست تأیید پیامک در یک برنامه Android

برای تأیید خودکار شماره تلفن، باید هر دو بخش سرویس گیرنده و سرور جریان تأیید را پیاده سازی کنید. این سند نحوه پیاده سازی بخش کلاینت را در یک برنامه اندروید توضیح می دهد.

برای شروع جریان تأیید شماره تلفن در یک برنامه Android، شماره تلفن را به سرور تأیید خود ارسال می‌کنید و با SMS Retriever API تماس می‌گیرید تا شروع به گوش دادن به پیام SMS حاوی یک کد یکبار مصرف برای برنامه خود کنید. پس از دریافت پیام، کد یکبار مصرف را برای تکمیل فرآیند تأیید به سرور خود ارسال می کنید.

قبل از اینکه شروع کنی

برای آماده سازی اپلیکیشن خود، مراحل زیر را انجام دهید.

پیش نیازهای اپلیکیشن

مطمئن شوید که فایل ساخت برنامه شما از مقادیر زیر استفاده می کند:

  • نسخه minSdk 19 یا بالاتر
  • کامپایلSdkVersion 28 یا بالاتر

برنامه خود را پیکربندی کنید

در فایل build.gradle در سطح پروژه خود، مخزن Maven Google و مخزن مرکزی Maven را در هر دو بخش buildscript و allprojects قرار دهید:

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

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

وابستگی خدمات Google Play را برای SMS Retriever API به فایل ساخت Gradle ماژول خود اضافه کنید، که معمولا app/build.gradle است:

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

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. بازیابی پیامک را راه اندازی کنید

هنگامی که برای تأیید شماره تلفن کاربر آماده هستید، نمونه ای از شی 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 که حاوی یک رشته منحصر به فرد است که برنامه شما را شناسایی می کند گوش می دهد.

3. شماره تلفن را به سرور خود ارسال کنید

پس از اینکه شماره تلفن کاربر را به دست آوردید و شروع به گوش دادن به پیام های SMS کردید، شماره تلفن کاربر را با هر روشی (معمولاً با درخواست HTTPS POST) به سرور تأیید خود ارسال کنید.

سرور شما یک پیام تأیید تولید می کند و آن را از طریق پیامک به شماره تلفنی که مشخص کرده اید ارسال می کند. به انجام تأیید صحت پیامک در سرور مراجعه کنید.

4. پیام های تأیید را دریافت کنید

هنگامی که یک پیام تأیید در دستگاه کاربر دریافت می‌شود، «خدمات 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.  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 ثبت کنید. 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 for Passwords ذخیره کنید

در صورت تمایل، پس از اینکه کاربر شماره تلفن خود را تأیید کرد، می‌توانید از کاربر بخواهید این حساب شماره تلفن را با Smart Lock for Passwords ذخیره کند تا بدون نیاز به تایپ یا انتخاب مجدد شماره تلفن، به طور خودکار در سایر برنامه‌ها و دستگاه‌های دیگر در دسترس باشد. :

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)