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

إذا كنت توفّر إمكانية تسجيل الدخول باستخدام حسابات 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() للعميل ذي النقرة الواحدة. لن تحتوي بيانات الاعتماد على سمة 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 لصورة الملف الشخصي. بالنسبة إلى العديد من التطبيقات، تكفي هذه المعلومات لمصادقة المستخدم في الخلفية وإنشاء حساب جديد.

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