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

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

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

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

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

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

  • الإصدار 19 من حزمة minSdkVersion أو إصدار أحدث
  • الإصدار 28 أو إصدار أحدث من compileSdkVersion

ضبط إعدادات تطبيقك

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

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

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

أضِف الاعتمادية لخدمات Google Play الخاصة بواجهة برمجة التطبيقات SMS Retriever إلى ملف إنشاء Gradle الخاص بالوحدة، والذي يكون عادةً app/build.gradle:

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

‫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
    // ...
  }
});

ستستمع مهمة استرداد الرسائل القصيرة لمدة تصل إلى خمس دقائق بحثًا عن رسالة قصيرة تحتوي على سلسلة فريدة تحدد تطبيقك.

3- إرسال رقم الهاتف إلى الخادم

بعد الحصول على رقم هاتف المستخدم والبدء في الاستماع إلى رسائل SMS، أرسِل رقم هاتف المستخدم إلى خادم التحقّق باستخدام أي طريقة (عادةً مع طلب HTTPS POST).

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

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

عند تلقّي رسالة تأكيد على جهاز المستخدم، تبث &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.  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:
          // (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>

5. إرسال الرمز الصالح لمرة واحدة من رسالة تأكيد الحساب إلى الخادم

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

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