طلب إثبات الملكية عبر الرسائل القصيرة SMS في تطبيق Android

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

لبدء عملية تأكيد رقم الهاتف في تطبيق Android، عليك إرسال رقم الهاتف إلى خادم التأكيد واستدعاء واجهة برمجة التطبيقات SMS Retriever API لبدء الاستماع إلى رسالة SMS تحتوي على رمز يُستخدَم لمرة واحدة في تطبيقك. وبعد تلقّي الرسالة، عليك إرسال الرمز الذي يُستخدَم لمرة واحدة إلى الخادم لإكمال عملية التأكيد.

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

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

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

  • الإصدار 19 من minSdkVersion أو إصدار أحدث
  • ‫compileSdkVersion بقيمة 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: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
      }
  }
}

بدء خدمة "استرداد الرسائل القصيرة"

عندما تكون مستعدًا لإثبات ملكية رقم هاتف المستخدم، احصل على مثيل من العنصر 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 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، أرسِل رقم هاتف المستخدم إلى خادم التحقّق من المستخدمين المصابين باستخدام أي طريقة (عادةً باستخدام طلب HTTPS POST).

يُنشئ الخادم رسالة تأكيد ويرسلها عبر رسالة SMS إلى رقم الهاتف الذي حدّدته. اطّلِع على إجراء عملية إثبات الهوية عبر الرسائل القصيرة على الخادم.

تلقّي رسائل التأكيد

عند تلقّي رسالة تأكيد على جهاز المستخدم، تبث &quot;خدمات Play&quot; بشكل صريح SmsRetriever.SMS_RETRIEVED_ACTION Intent إلى تطبيقك، والذي يتضمّن نص الرسالة. استخدِم 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، استخدِم ما يلي:

  • intent filter: 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>

إرسال الرمز الذي يُستخدَم لمرة واحدة من رسالة تأكيد الحساب إلى الخادم

بعد الحصول على نص رسالة التحقّق، استخدِم تعبيرًا عاديًا أو بعض التعليمات البرمجية الأخرى للحصول على الرمز الصالح لمرة واحدة من الرسالة. يعتمد تنسيق الرمز الصالح لمرة واحدة على طريقة تنفيذه في الخادم.

أخيرًا، أرسِل الرمز الصالح لمرة واحدة إلى الخادم عبر اتصال آمن. عندما يتلقّى الخادم الرمز الذي يُستخدم لمرة واحدة، يسجّل أنّه تم تأكيد رقم الهاتف.