طلب موافقة لمرّة واحدة لقراءة رمز إثبات الهوية عبر الرسائل القصيرة SMS

توضّح هذه الصفحة طريقة استخدام واجهة برمجة التطبيقات SMS User Consent API لطلب موافقة المستخدم على قراءة رسالة SMS واحدة لإثبات الهوية. إذا وافق المستخدم، ستعرض واجهة برمجة التطبيقات نص الرسالة الذي يمكنك من خلاله الحصول على رمز التحقق وإكمال عملية التحقق.

تثبيت التبعيات

يمكنك تضمين مكوِّن مصادقة "خدمات Play" في ملف build.gradle لتطبيقك:

implementation 'com.google.android.gms:play-services-auth:17.0.0'
implementation 'com.google.android.gms:play-services-auth-api-phone:17.4.0'

1- الحصول على رقم هاتف المستخدم

وإذا لم يكن لديك رقم هاتف المستخدم، اطلبه قبل بدء خطوات إثبات الملكية عبر الرسائل القصيرة SMS.

يمكنك الحصول على رقم هاتف المستخدم بطريقة تناسب تطبيقك. ننصحك باستخدام أداة اختيار تلميح Smart Lock لكلمات المرور لمساعدة المستخدم في ملء رقم هاتفه إذا لم تكن هذه المعلومات مطلوبة لإنشاء حساب المستخدم. لاستخدام أداة اختيار التلميح:

Kotlin

private val CREDENTIAL_PICKER_REQUEST = 1  // Set to an unused request code

// Construct a request for phone numbers and show the picker
private fun requestHint() {
    val hintRequest = HintRequest.Builder()
        .setPhoneNumberIdentifierSupported(true)
        .build()
    val credentialsClient = Credentials.getClient(this)
    val intent = credentialsClient.getHintPickerIntent(hintRequest)
    startIntentSenderForResult(
        intent.intentSender,
        CREDENTIAL_PICKER_REQUEST,
        null, 0, 0, 0
    )
}

public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    when (requestCode) {
        CREDENTIAL_PICKER_REQUEST ->
            // Obtain the phone number from the result
            if (resultCode == Activity.RESULT_OK && data != null) {
                val credential = data.getParcelableExtra<Credential>(Credential.EXTRA_KEY)
                // credential.getId();  <-- will need to process phone number string
            }
        // ...
    }
}

Java

private static final int CREDENTIAL_PICKER_REQUEST = 1;  // Set to an unused request code

// Construct a request for phone numbers and show the picker
private void requestHint() throws IntentSender.SendIntentException {
    HintRequest hintRequest = new HintRequest.Builder()
            .setPhoneNumberIdentifierSupported(true)
            .build();
    PendingIntent intent = Credentials.getClient(this).getHintPickerIntent(hintRequest);
    startIntentSenderForResult(intent.getIntentSender(),
            RESOLVE_HINT, null, 0, 0, 0);
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    switch (requestCode) {
        case CREDENTIAL_PICKER_REQUEST:
            // Obtain the phone number from the result
            if (resultCode == RESULT_OK) {
                Credential credential = data.getParcelableExtra(Credential.EXTRA_KEY);
                // credential.getId();  <-- will need to process phone number string
            }
            break;
        // ...
    }
}

2. بدء الاستماع إلى الرسائل الواردة

بعد ذلك، يمكنك استدعاء طريقة startSmsUserConsent() في واجهة برمجة التطبيقات SMS User Consent API لبدء الاستماع إلى الرسائل الواردة. إذا كنت تعرف رقم الهاتف الذي ستصدر منه الرسالة القصيرة، حدده (وإلا، مرر null). بهذه الطريقة، لن يتم تشغيل واجهة برمجة تطبيقات موافقة مستخدم تطبيق SMS إلا على الرسائل الواردة من هذا الرقم.

لبدء الاستماع:

Kotlin

// Start listening for SMS User Consent broadcasts from senderPhoneNumber
// The Task<Void> will be successful if SmsRetriever was able to start
// SMS User Consent, and will error if there was an error starting.
val task = SmsRetriever.getClient(context).startSmsUserConsent(senderPhoneNumber /* or null */)

Java

// Start listening for SMS User Consent broadcasts from senderPhoneNumber
// The Task<Void> will be successful if SmsRetriever was able to start
// SMS User Consent, and will error if there was an error starting.
Task<Void> task = SmsRetriever.getClient(context).startSmsUserConsent(senderPhoneNumber /* or null */);

بعد الاستماع إلى الرسائل القصيرة SMS الواردة، يمكنك أن تطلب من نظام التحقق إرسال رمز التحقق إلى رقم هاتف المستخدم، الذي تلقيته في الخطوة الأولى.

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

  • تحتوي الرسالة على سلسلة أبجدية رقمية من 4 إلى 10 أحرف مع رقم واحد على الأقل.
  • إذا حددت رقم هاتف المرسل، فقد تم إرسال الرسالة من خلال ذلك الرقم.

يمكنك معالجة عمليات البث هذه من خلال جهاز استقبال بث يملك إذن SEND_PERMISSION ويستجيب لأهداف SMS_RETRIEVED_ACTION. لإنشاء جهاز استقبال البث وتسجيله:

Kotlin

private val SMS_CONSENT_REQUEST = 2  // Set to an unused request code
private val smsVerificationReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        if (SmsRetriever.SMS_RETRIEVED_ACTION == intent.action) {
            val extras = intent.extras
            val smsRetrieverStatus = extras?.get(SmsRetriever.EXTRA_STATUS) as Status

            when (smsRetrieverStatus.statusCode) {
                CommonStatusCodes.SUCCESS -> {
                    // Get consent intent
                    val consentIntent = extras.getParcelable<Intent>(SmsRetriever.EXTRA_CONSENT_INTENT)
                    try {
                        // Start activity to show consent dialog to user, activity must be started in
                        // 5 minutes, otherwise you'll receive another TIMEOUT intent
                        startActivityForResult(consentIntent, SMS_CONSENT_REQUEST)
                    } catch (e: ActivityNotFoundException) {
                        // Handle the exception ...
                    }
                }
                CommonStatusCodes.TIMEOUT -> {
                    // Time out occurred, handle the error.
                }
            }
        }
    }
}

override fun onCreate(savedInstanceState: Bundle?) {
    // ...

    val intentFilter = IntentFilter(SmsRetriever.SMS_RETRIEVED_ACTION)
    registerReceiver(smsVerificationReceiver, SmsRetriever.SEND_PERMISSION, intentFilter)
}

Java

private static final int SMS_CONSENT_REQUEST = 2;  // Set to an unused request code
private final BroadcastReceiver smsVerificationReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (SmsRetriever.SMS_RETRIEVED_ACTION.equals(intent.getAction())) {
            Bundle extras = intent.getExtras();
            Status smsRetrieverStatus = (Status) extras.get(SmsRetriever.EXTRA_STATUS);

            switch (smsRetrieverStatus.getStatusCode()) {
                case CommonStatusCodes.SUCCESS:
                    // Get consent intent
                    Intent consentIntent = extras.getParcelable(SmsRetriever.EXTRA_CONSENT_INTENT);
                    try {
                        // Start activity to show consent dialog to user, activity must be started in
                        // 5 minutes, otherwise you'll receive another TIMEOUT intent
                        startActivityForResult(consentIntent, SMS_CONSENT_REQUEST);
                    } catch (ActivityNotFoundException e) {
                        // Handle the exception ...
                    }
                    break;
                case CommonStatusCodes.TIMEOUT:
                    // Time out occurred, handle the error.
                    break;
            }
        }
    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // ...

    IntentFilter intentFilter = new IntentFilter(SmsRetriever.SMS_RETRIEVED_ACTION);
    registerReceiver(smsVerificationReceiver, SmsRetriever.SEND_PERMISSION, intentFilter);
}

من خلال بدء نشاط لـ EXTRA_CONSENT_INTENT، تطلب من المستخدم الحصول على إذن لمرة واحدة لقراءة محتوى الرسالة.

3. الحصول على رمز إثبات الهوية من رسالة

في طريقة onActivityResult()، يمكنك التعامل مع ردّ المستخدم على طلبك للحصول على الإذن. إذا تلقّيت رمز نتيجة RESULT_OK، يعني هذا أنّ المستخدم يمنح الإذن بقراءة محتوى الرسالة، ويمكنك الحصول على نص الرسالة من الغرض.

Kotlin

public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    when (requestCode) {
        // ...
        SMS_CONSENT_REQUEST ->
            // Obtain the phone number from the result
            if (resultCode == Activity.RESULT_OK && data != null) {
                // Get SMS message content
                val message = data.getStringExtra(SmsRetriever.EXTRA_SMS_MESSAGE)
                // Extract one-time code from the message and complete verification
                // `message` contains the entire text of the SMS message, so you will need
                // to parse the string.
                val oneTimeCode = parseOneTimeCode(message) // define this function

                // send one time code to the server
            } else {
                // Consent denied. User can type OTC manually.
            }
    }
}

Java

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    switch (requestCode) {
        // ...
        case SMS_CONSENT_REQUEST:
            if (resultCode == RESULT_OK) {
                // Get SMS message content
                String message = data.getStringExtra(SmsRetriever.EXTRA_SMS_MESSAGE);
                // Extract one-time code from the message and complete verification
                // `sms` contains the entire text of the SMS message, so you will need
                // to parse the string.
                String oneTimeCode = parseOneTimeCode(message); // define this function

                // send one time code to the server
            } else {
                // Consent canceled, handle the error ...
            }
            break;
    }
}

بعد تلقّي نص الرسالة، يمكنك تحليل رمز التحقّق وملء النموذج تلقائيًا أو إكمال عملية إثبات الملكية.