إنشاء حسابات جديدة بنقرة واحدة

إذا كنت تتيح تسجيل الدخول باستخدام حسابات Google، يمكنك استخدام برنامج تسجيل الدخول بنقرة واحدة لمنح المستخدمين أيضًا تجربة إنشاء حسابات سلسة لا تخرجهم مطلقًا من سياق تطبيقك.

واجهة مستخدم للاشتراك بنقرة واحدة

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

يتضمن تنفيذ إنشاء الحساب لميزة "نقرة واحدة" جزأين:

  • دمج برنامج "نقرة واحدة" في تطبيقك، الموضح في هذه الصفحة يشبه ذلك في الغالب استخدام ميزة "تسجيل الدخول بنقرة واحدة"، ولكن مع بعض الاختلافات في عملية الإعداد.
  • يمكن إضافة إمكانية إنشاء حسابات مستخدمين من الرموز المميّزة لمعرّفات Google إلى الخلفية، وهذا ما نناقشه في مقالة استخدام رموز المعرّف المميزة في الخلفية.

أين يجب أن أستخدم خيار الاشتراك من خلال ميزة "نقرة واحدة"؟

المكان الأكثر تأثيرًا لتقديم خيار الاشتراك بميزة "نقرة واحدة" للمستخدمين هو الحالات التي يؤدي فيها تسجيل الدخول إلى تفعيل ميزات جديدة. أولاً، حاول تسجيل دخول المستخدم باستخدام بيانات اعتماد محفوظة. إذا لم يتم العثور على أي بيانات اعتماد محفوظة، يمكنك عرض إنشاء حساب جديد للمستخدم.

قبل البدء

عليك إعداد مشروع وحدة تحكُّم Google APIs ومشروع Android كما هو موضَّح في البدء باستخدام ميزة "تسجيل الدخول بنقرة واحدة".

1- ضبط برنامج "نقرة واحدة"

لإعداد برنامج "نقرة واحدة" لإنشاء الحساب، عليك اتّباع الخطوات التالية:

  • عدم تفعيل طلبات بيانات اعتماد كلمة المرور (لا يمكن الاشتراك بنقرة واحدة إلا باستخدام المصادقة المستندة إلى رمز مميّز)
  • يمكنك تفعيل طلبات الرموز المميّزة لرقم تعريف Google باستخدام setGoogleIdTokenRequestOptions() وهذه الإعدادات:

Java

public class YourActivity extends AppCompatActivity {

  // ...

  private SignInClient oneTapClient;
  private BeginSignInRequest signUpRequest;

  @Override
  public void onCreate(@Nullable Bundle savedInstanceState,
                       @Nullable PersistableBundle persistentState) {
      super.onCreate(savedInstanceState, persistentState);

      oneTapClient = Identity.getSignInClient(this);
      signUpRequest = BeginSignInRequest.builder()
              .setGoogleIdTokenRequestOptions(GoogleIdTokenRequestOptions.builder()
                      .setSupported(true)
                      // Your server's client ID, not your Android client ID.
                      .setServerClientId(getString(R.string.your_web_client_id))
                      // Show all accounts on the device.
                      .setFilterByAuthorizedAccounts(false)
                      .build())
              .build();

      // ...
  }
}

Kotlin

class YourActivity : AppCompatActivity() {
    // ...

    private lateinit var oneTapClient: SignInClient
    private lateinit var signUpRequest: BeginSignInRequest

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        oneTapClient = Identity.getSignInClient(this)
        signUpRequest = BeginSignInRequest.builder()
            .setGoogleIdTokenRequestOptions(
                BeginSignInRequest.GoogleIdTokenRequestOptions.builder()
                    .setSupported(true)
                    // Your server's client ID, not your Android client ID.
                    .setServerClientId(getString(R.string.your_web_client_id))
                    // Show all accounts on the device.
                    .setFilterByAuthorizedAccounts(false)
                    .build())
            .build()
        // ...
    }
    // ...
}

2. تتبُّع عملية إلغاء واجهة المستخدم بنقرة واحدة

عليك تتبُّع ما إذا كان المستخدم قد رفض استخدام خيار الاشتراك بميزة "نقرة واحدة" إما عن طريق إغلاق الإشعار أو النقر خارجه. وقد يكون ذلك في غاية البساطة كسمة منطقية لنشاطك. (راجِع إيقاف عرض واجهة المستخدم بنقرة واحدة أدناه).

3- عرض واجهة المستخدم للاشتراك بنقرة واحدة

إذا لم يرفض المستخدم استخدام ميزة "نقرة واحدة" لإنشاء حساب جديد، عليك طلب الإجراء beginSignIn() لكائن العميل وإرفاق المستمعين إلى Task الذي يعرضه. تُجري التطبيقات هذه الخطوة عادةً عندما لا يعثر طلب تسجيل الدخول بنقرة واحدة على أي بيانات اعتماد محفوظة، أي في أداة معالجة الفشل في طلب تسجيل الدخول.

سيتصل برنامج "نقرة واحدة" بالمستمع الناجح إذا كان لدى المستخدم حساب Google واحد أو أكثر تم إعداده على الجهاز. في أداة معالجة النجاح، يمكنك الحصول على النية المعلّقة من نتيجة Task وإرسالها إلى startIntentSenderForResult() لبدء واجهة المستخدم بنقرة واحدة.

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

Java

oneTapClient.beginSignIn(signUpRequest)
        .addOnSuccessListener(this, new OnSuccessListener<BeginSignInResult>() {
            @Override
            public void onSuccess(BeginSignInResult result) {
                try {
                    startIntentSenderForResult(
                            result.getPendingIntent().getIntentSender(), REQ_ONE_TAP,
                            null, 0, 0, 0);
                } catch (IntentSender.SendIntentException e) {
                    Log.e(TAG, "Couldn't start One Tap UI: " + e.getLocalizedMessage());
                }
            }
        })
        .addOnFailureListener(this, new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                // No Google Accounts found. Just continue presenting the signed-out UI.
                Log.d(TAG, e.getLocalizedMessage());
            }
        });

Kotlin

oneTapClient.beginSignIn(signUpRequest)
    .addOnSuccessListener(this) { result ->
        try {
            startIntentSenderForResult(
                result.pendingIntent.intentSender, REQ_ONE_TAP,
                null, 0, 0, 0)
        } catch (e: IntentSender.SendIntentException) {
            Log.e(TAG, "Couldn't start One Tap UI: ${e.localizedMessage}")
        }
    }
    .addOnFailureListener(this) { e ->
        // No Google Accounts found. Just continue presenting the signed-out UI.
        Log.d(TAG, e.localizedMessage)
    }

4. التعامل مع ردّ المستخدم

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

إنشاء حساب باستخدام رمز مميّز لمعرّف Google

إذا اختار المستخدم الاشتراك باستخدام حساب Google، يمكنك الحصول على رمز مميز للمعرّف من خلال تمرير بيانات الغرض من onActivityResult() إلى طريقة getSignInCredentialFromIntent() لعميل One Tap. ستحتوي بيانات الاعتماد على سمة googleIdToken غير فارغة.

استخدِم الرمز المميّز لرقم التعريف لإنشاء حساب على الخلفية (راجِع المصادقة باستخدام خلفية باستخدام رموز المعرّف المميزة) وسجِّل دخول المستخدم.

تتضمّن بيانات الاعتماد أيضًا أي تفاصيل إضافية طلبتها، مثل رقم الهاتف الذي تم إثبات ملكيته للحساب، إن توفّر.

Java

public class YourActivity extends AppCompatActivity {

  // ...
  private static final int REQ_ONE_TAP = 2;  // Can be any integer unique to the Activity.
  private boolean showOneTapUI = true;
  // ...

  @Override
  protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
      super.onActivityResult(requestCode, resultCode, data);

      switch (requestCode) {
          case REQ_ONE_TAP:
              try {
                  SignInCredential credential = oneTapClient.getSignInCredentialFromIntent(data);
                  String idToken = credential.getGoogleIdToken();
                  if (idToken !=  null) {
                      // Got an ID token from Google. Use it to authenticate
                      // with your backend.
                      Log.d(TAG, "Got ID token.");
                  }
              } catch (ApiException e) {
                  // ...
              }
              break;
      }
  }
}

Kotlin

class YourActivity : AppCompatActivity() {

    // ...
    private val REQ_ONE_TAP = 2  // Can be any integer unique to the Activity
    private var showOneTapUI = true
    // ...

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        when (requestCode) {
             REQ_ONE_TAP -> {
                try {
                    val credential = oneTapClient.getSignInCredentialFromIntent(data)
                    val idToken = credential.googleIdToken
                    when {
                        idToken != null -> {
                            // Got an ID token from Google. Use it to authenticate
                            // with your backend.
                            Log.d(TAG, "Got ID token.")
                        }
                        else -> {
                            // Shouldn't happen.
                            Log.d(TAG, "No ID token!")
                        }
                    }
                } catch (e: ApiException) {
                    // ...
            }
        }
    }
    // ...
}

إيقاف عرض واجهة المستخدم بنقرة واحدة

إذا رفض المستخدم تسجيل الدخول، ستعرض المكالمة getSignInCredentialFromIntent() الخطأ ApiException مع رمز الحالة CommonStatusCodes.CANCELED. وعند حدوث ذلك، يجب أن تتوقف مؤقتًا عن عرض واجهة المستخدم لتسجيل الدخول بنقرة واحدة حتى لا تزعج المستخدمين بالطلبات المتكررة. يحقِّق المثال التالي ذلك من خلال ضبط خاصية في "النشاط" يتم استخدامها لتحديد ما إذا كنت تريد توفير خيار "تسجيل الدخول بنقرة واحدة" للمستخدم. ومع ذلك، يمكنك أيضًا حفظ قيمة في "SharedPreferences" أو استخدام طريقة أخرى.

من المهم تطبيق حدود لمعدل طلبات تسجيل الدخول بنقرة واحدة. إذا لم تفعل ذلك، وألغى المستخدم عدة طلبات على التوالي، لن يطلب برنامج "نقرة واحدة" المستخدم خلال 24 ساعة من الآن.

Java

public class YourActivity extends AppCompatActivity {

  // ...
  private static final int REQ_ONE_TAP = 2;  // Can be any integer unique to the Activity.
  private boolean showOneTapUI = true;
  // ...

  @Override
  protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
      super.onActivityResult(requestCode, resultCode, data);

      switch (requestCode) {
          case REQ_ONE_TAP:
              try {
                  // ...
              } catch (ApiException e) {
                  switch (e.getStatusCode()) {
                      case CommonStatusCodes.CANCELED:
                          Log.d(TAG, "One-tap dialog was closed.");
                          // Don't re-prompt the user.
                          showOneTapUI = false;
                          break;
                      case CommonStatusCodes.NETWORK_ERROR:
                          Log.d(TAG, "One-tap encountered a network error.");
                          // Try again or just ignore.
                          break;
                      default:
                          Log.d(TAG, "Couldn't get credential from result."
                                  + e.getLocalizedMessage());
                          break;
                  }
              }
              break;
      }
  }
}

Kotlin

class YourActivity : AppCompatActivity() {

    // ...
    private val REQ_ONE_TAP = 2  // Can be any integer unique to the Activity
    private var showOneTapUI = true
    // ...

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        when (requestCode) {
            REQ_ONE_TAP -> {
                try {
                    // ...
                } catch (e: ApiException) {
                    when (e.statusCode) {
                        CommonStatusCodes.CANCELED -> {
                            Log.d(TAG, "One-tap dialog was closed.")
                            // Don't re-prompt the user.
                            showOneTapUI = false
                        }
                        CommonStatusCodes.NETWORK_ERROR -> {
                            Log.d(TAG, "One-tap encountered a network error.")
                            // Try again or just ignore.
                        }
                        else -> {
                            Log.d(TAG, "Couldn't get credential from result." +
                                " (${e.localizedMessage})")
                        }
                    }
                }
            }
        }
    }
    // ...
}

الخطوات التالية

عندما يُكمل المستخدم عملية الاشتراك من خلال ميزة "نقرة واحدة"، ستحصل على رمز مميّز لمعرّف Google يتضمّن بعض معلومات الملف الشخصي الأساسية، مثل عنوان البريد الإلكتروني للمستخدم والاسم الكامل وعنوان URL لصورة الملف الشخصي. بالنسبة إلى العديد من التطبيقات، تكفي هذه المعلومات لتتمكّن من مصادقة المستخدم في الخلفية وإنشاء حساب جديد.

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