طلب التحقّق من رسائل SMS في تطبيق متوافق مع Android

تنظيم صفحاتك في مجموعات يمكنك حفظ المحتوى وتصنيفه حسب إعداداتك المفضّلة.

لإثبات ملكية أرقام الهواتف تلقائيًا، عليك تنفيذ كل من العميل والخادم أثناء عملية إثبات الملكية. يوضح هذا المستند كيفية تنفيذ جزء العميل في تطبيق Android.

لبدء عملية إثبات ملكية رقم الهاتف في أحد تطبيقات Android، عليك إرسال رقم الهاتف إلى خادم إثبات الملكية والاتصال بواجهة برمجة التطبيقات لاسترداد الرسائل القصيرة SMS لبدء الاستماع إلى رسالة SMS تحتوي على رمز يتم استخدامه مرة واحدة لتطبيقك. وبعد تلقّي الرسالة، عليك إعادة إرسال الرمز مرة واحدة إلى خادمك لإكمال عملية إثبات الملكية.

قبل البدء

لتحضير تطبيقك، أكمِل الخطوات الواردة في الأقسام التالية.

المتطلّبات الأساسية للتطبيق

تأكَّد من أن ملف الإصدار الخاص بتطبيقك يستخدم القيم التالية:

  • minSdkVersion بالإصدار 19 أو إصدار أحدث
  • إصدار AggregateSdkVersion بالإصدار 28 أو إصدار أحدث

إعداد تطبيقك

في ملف build.gradle على مستوى المشروع، يمكنك تضمين مستودع Google Maven ومستودع Maven المركزي في كلٍّ من القسمَين buildscript وallprojects:

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

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

أضِف خدمات Google Play الخاصة بواجهة برمجة التطبيقات لاسترداد الرسائل القصيرة SMS إلى module's Gradle build file، والذي يكون عادةً app/build.gradle:

dependencies {
  implementation 'com.google.android.gms:play-services-auth:20.4.0'
  implementation 'com.google.android.gms:play-services-auth-api-phone:18.0.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. بدء أداة استرداد الرسائل القصيرة

عندما تكون مستعدًّا لإثبات ملكية رقم هاتف المستخدم، حاوِل الحصول على مثال للكائن SmsRetrieverClient ثم اتّصِل بالرقم startSmsRetriever وأرفِق النجاح وتعذّر على المستمعين تنفيذ مهمة استرداد الرسائل القصيرة:

// 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 صراحةً رسالة intent إلى SmsRetriever.SMS_RETRIEVED_ACTION على تطبيقك، وتحتوي على نص الرسالة. يمكنك استخدام BroadcastReceiver لاستلام رسالة إثبات الملكية هذه.

في معالج onReceive'BroadcastReceiver، يمكنك الحصول على نص رسالة التحقق من الإضافات الإضافية:

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