استخدِم عميل تسجيل الدخول باستخدام ميزة "نقرة واحدة" لطلب إذن من المستخدم باسترداد إحدى بيانات الاعتماد التي سبق له استخدامها لتسجيل الدخول إلى تطبيقك. يمكن أن تكون بيانات الاعتماد هذه إما حسابًا على Google أو مجموعة من اسم المستخدم وكلمة المرور التي حفظها المستخدم باستخدام Google من خلال Chrome أو ميزة "الملء التلقائي" على Android أو Smart Lock لكلمات المرور.
عند استرداد بيانات الاعتماد بنجاح، يمكنك استخدامها لتسجيل دخول المستخدم إلى تطبيقك بسلاسة.
إذا لم يحفظ المستخدم أي بيانات اعتماد، لن تظهر أي واجهة مستخدم، ويمكنك تقديم تجربة تسجيل الخروج العادية.
أين يجب استخدام ميزة "تسجيل الدخول بنقرة واحدة"؟
إذا كان تطبيقك يتطلّب من المستخدمين تسجيل الدخول، اعرض واجهة مستخدم "نقرة واحدة" على شاشة تسجيل الدخول. يمكن أن يكون ذلك مفيدًا حتى إذا كان لديك زر "تسجيل الدخول باستخدام حساب Google"، لأنّه يمكن ضبط واجهة مستخدم "نقرة واحدة" لعرض بيانات الاعتماد التي سبق للمستخدم استخدامها لتسجيل الدخول فقط، ما قد يذكّر المستخدمين الذين يسجّلون الدخول بشكل غير منتظم بالطريقة التي سجّلوا بها الدخول في المرة الأخيرة، ويمنعهم من إنشاء حسابات جديدة عن طريق الخطأ باستخدام تطبيقك.
إذا كان تسجيل الدخول اختياريًا في تطبيقك، ننصحك باستخدام ميزة "تسجيل الدخول بنقرة واحدة" على أي شاشة تقدّم تجربة محسّنة عند تسجيل الدخول. على سبيل المثال، إذا كان بإمكان المستخدمين تصفُّح المحتوى باستخدام تطبيقك أثناء تسجيل الخروج، ولكن لا يمكنهم نشر التعليقات أو إضافة عناصر إلى سلّة التسوّق إلا بعد تسجيل الدخول، سيكون هذا سياقًا مناسبًا لميزة "تسجيل الدخول بنقرة واحدة".
يجب أيضًا أن تستخدم التطبيقات التي يكون تسجيل الدخول فيها اختياريًا ميزة "تسجيل الدخول باستخدام نقرة واحدة" على شاشات تسجيل الدخول للأسباب المذكورة أعلاه.
قبل البدء
- يمكنك إعداد مشروعك على Google APIs Console ومشروع Android كما هو موضّح في مقالة البدء في استخدام ميزة "تسجيل الدخول بنقرة واحدة".
- إذا كنت تتيح تسجيل الدخول باستخدام كلمة المرور، عليك تحسين تطبيقك لكي يتوافق مع ميزة "الملء التلقائي" (أو استخدام Smart Lock لكلمات المرور) ليتمكّن المستخدمون من حفظ بيانات اعتماد كلمة المرور بعد تسجيل الدخول.
1. إعداد عميل تسجيل الدخول باستخدام ميزة "نقرة واحدة"
يمكنك إعداد عميل تسجيل الدخول باستخدام ميزة "نقرة واحدة" لتسجيل دخول المستخدمين باستخدام كلمات المرور المحفوظة أو حسابات Google المحفوظة أو كليهما. (ننصحك بإتاحة كليهما، لتفعيل إنشاء الحساب بنقرة واحدة للمستخدمين الجدد وتسجيل الدخول تلقائيًا أو بنقرة واحدة لأكبر عدد ممكن من المستخدمين العائدين.)
إذا كان تطبيقك يتيح تسجيل الدخول باستخدام كلمة المرور، استخدِم setPasswordRequestOptions() لتفعيل طلبات بيانات اعتماد كلمة المرور.
إذا كان تطبيقك يتيح تسجيل الدخول باستخدام حساب Google، استخدِم setGoogleIdTokenRequestOptions() لتفعيل طلبات رموز تعريف Google وضبطها:
اضبط معرّف عميل الخادم على المعرّف الذي أنشأته في Google APIs Console. يُرجى العِلم أنّ هذا هو معرّف عميل الخادم، وليس معرّف عميل Android.
اضبط العميل على الفلترة حسب الحسابات المفوّضة. عند تفعيل هذا الخيار، لا يطلب عميل "نقرة واحدة" من المستخدمين تسجيل الدخول إلى تطبيقك إلا باستخدام حسابات Google التي سبق لهم استخدامها في الماضي. يمكن أن يساعد ذلك المستخدمين في تسجيل الدخول بنجاح عندما لا يكونون متأكدين مما إذا كان لديهم حساب أو أي حساب على Google استخدموه، ويمنعهم من إنشاء حسابات جديدة عن طريق الخطأ باستخدام تطبيقك.
إذا كنت تريد تسجيل دخول المستخدمين تلقائيًا متى أمكن ذلك، فعِّل الميزة باستخدام
setAutoSelectEnabled(). يمكن تسجيل الدخول تلقائيًا عند استيفاء المعايير التالية:- لدى المستخدم بيانات اعتماد واحدة فقط محفوظة لتطبيقك، أي كلمة مرور واحدة محفوظة أو حساب واحد على Google محفوظ.
- لم يسبق للمستخدم إيقاف ميزة "تسجيل الدخول تلقائيًا" في إعدادات حساب Google.
ننصحك بشدة باستخدام رقم خاص لتحسين أمان تسجيل الدخول وتجنُّب هجمات إعادة التشغيل، على الرغم من أنّ ذلك اختياري. استخدِم setNonce لتضمين رقم خاص في كل طلب. راجِع قسم الحصول على رقم خاص في SafetyNet للحصول على اقتراحات وتفاصيل إضافية حول إنشاء رقم خاص.
Java
public class YourActivity extends AppCompatActivity { // ... private SignInClient oneTapClient; private BeginSignInRequest signInRequest; @Override public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) { super.onCreate(savedInstanceState, persistentState); oneTapClient = Identity.getSignInClient(this); signInRequest = BeginSignInRequest.builder() .setPasswordRequestOptions(PasswordRequestOptions.builder() .setSupported(true) .build()) .setGoogleIdTokenRequestOptions(GoogleIdTokenRequestOptions.builder() .setSupported(true) // Your server's client ID, not your Android client ID. .setServerClientId(getString(R.string.default_web_client_id)) // Only show accounts previously used to sign in. .setFilterByAuthorizedAccounts(true) .build()) // Automatically sign in when exactly one credential is retrieved. .setAutoSelectEnabled(true) .build(); // ... } // ... }
Kotlin
class YourActivity : AppCompatActivity() { // ... private lateinit var oneTapClient: SignInClient private lateinit var signInRequest: BeginSignInRequest override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) oneTapClient = Identity.getSignInClient(this) signInRequest = BeginSignInRequest.builder() .setPasswordRequestOptions(BeginSignInRequest.PasswordRequestOptions.builder() .setSupported(true) .build()) .setGoogleIdTokenRequestOptions( BeginSignInRequest.GoogleIdTokenRequestOptions.builder() .setSupported(true) // Your server's client ID, not your Android client ID. .setServerClientId(getString(R.string.your_web_client_id)) // Only show accounts previously used to sign in. .setFilterByAuthorizedAccounts(true) .build()) // Automatically sign in when exactly one credential is retrieved. .setAutoSelectEnabled(true) .build() // ... } // ... }
2. التحقّق من وجود مستخدم مسجّل الدخول
إذا كان بإمكان مستخدم مسجّل الدخول أو مستخدم مسجّل الخروج استخدام نشاطك، تحقَّق من حالة المستخدم قبل عرض واجهة مستخدم "تسجيل الدخول باستخدام ميزة نقرة واحدة".
عليك أيضًا تتبُّع ما إذا كان المستخدم قد رفض استخدام ميزة "تسجيل الدخول باستخدام نقرة واحدة" من خلال إغلاق الطلب أو النقر خارجه. يمكن أن يكون ذلك بسيطًا مثل ضبط قيمة منطقية في النشاط. (راجِع إيقاف عرض واجهة مستخدم "نقرة واحدة" أدناه.)
3. عرض واجهة مستخدم تسجيل الدخول بنقرة واحدة
إذا لم يكن المستخدم مسجّلاً الدخول ولم يسبق له رفض استخدام ميزة "تسجيل الدخول بنقرة واحدة"، عليك استدعاء طريقة beginSignIn() لكائن العميل وإرفاق أدوات الاستماع بـ Task التي تعرضها. عادةً ما تفعل التطبيقات ذلك في طريقة onCreate() للنشاط أو بعد الانتقال بين الشاشات عند استخدام بنية تطبيق واحد.
سيستدعي عميل "نقرة واحدة" متتبِّع النجاح إذا كان لدى المستخدم أي بيانات اعتماد محفوظة لتطبيقك. في متتبِّع النجاح، احصل على الغرض المعلّق من نتيجة Task ومرِّره إلى startIntentSenderForResult() لبدء واجهة مستخدم تسجيل الدخول باستخدام ميزة "نقرة واحدة".
إذا لم يكن لدى المستخدم أي بيانات اعتماد محفوظة، سيستدعي عميل "نقرة واحدة" أداة الاستماع التي تشير إلى حدوث خطأ. في هذه الحالة، ليس عليك اتخاذ أي إجراء، ويمكنك ببساطة مواصلة عرض تجربة تسجيل الخروج في التطبيق. ومع ذلك، إذا كنت تتيح ميزة "الاشتراك باستخدام نقرة واحدة"، يمكنك بدء هذا المسار هنا لتوفير تجربة سلسة لإنشاء الحساب. راجِع مقالة إنشاء حسابات جديدة بنقرة واحدة.
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 saved credentials found. Launch the One Tap sign-up flow, or
// do nothing and continue presenting the signed-out UI.
Log.d(TAG, e.getLocalizedMessage());
}
});
Kotlin
oneTapClient.beginSignIn(signInRequest)
.addOnSuccessListener(this) { result ->
try {
startIntentSenderForResult(
result.pendingIntent.intentSender, REQ_ONE_TAP,
null, 0, 0, 0, null)
} catch (e: IntentSender.SendIntentException) {
Log.e(TAG, "Couldn't start One Tap UI: ${e.localizedMessage}")
}
}
.addOnFailureListener(this) { e ->
// No saved credentials found. Launch the One Tap sign-up flow, or
// do nothing and continue presenting the signed-out UI.
Log.d(TAG, e.localizedMessage)
}
4. التعامل مع استجابة المستخدم
سيتم إبلاغ تطبيقك باستجابة المستخدم لطلب تسجيل الدخول باستخدام ميزة "نقرة واحدة" باستخدام طريقة onActivityResult() في النشاط. إذا اختار المستخدم تسجيل الدخول، ستكون النتيجة بيانات اعتماد محفوظة. إذا رفض المستخدم تسجيل الدخول، إما عن طريق إغلاق واجهة مستخدم "نقرة واحدة" أو النقر خارجها، ستعرض النتيجة الرمز RESULT_CANCELED. يجب أن يتعامل تطبيقك مع كلا الاحتمالَين.
تسجيل الدخول باستخدام بيانات الاعتماد المستردّة
إذا اختار المستخدم مشاركة بيانات الاعتماد مع تطبيقك، يمكنك استردادها عن طريق تمرير بيانات الغرض من onActivityResult() إلى طريقة getSignInCredentialFromIntent() لعميل "نقرة واحدة". ستتضمّن بيانات الاعتماد السمة googleIdToken غير الفارغة إذا شارك المستخدم بيانات اعتماد حساب على Google مع تطبيقك، أو السمة password غير الفارغة إذا شارك المستخدم كلمة مرور محفوظة.
استخدِم بيانات الاعتماد للمصادقة مع خادم الخلفية في تطبيقك.
- إذا تم استرداد اسم مستخدم وكلمة مرور، استخدِمهما لتسجيل الدخول بالطريقة نفسها التي تستخدمها إذا كان المستخدم قد قدّمها يدويًا.
إذا تم استرداد بيانات اعتماد حساب Google، استخدِم رمز تعريف الهوية للمصادقة مع خادم الخلفية. إذا اخترت استخدام رقم خاص للمساعدة في تجنُّب هجمات إعادة التشغيل، تحقَّق من قيمة الاستجابة على خادم الخلفية. راجِع مقالة المصادقة مع خادم الخلفية باستخدام رموز تعريف Google.
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(); String username = credential.getId(); String password = credential.getPassword(); if (idToken != null) { // Got an ID token from Google. Use it to authenticate // with your backend. Log.d(TAG, "Got ID token."); } else if (password != null) { // Got a saved username and password. Use them to authenticate // with your backend. Log.d(TAG, "Got password."); } } 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 val username = credential.id val password = credential.password when { idToken != null -> { // Got an ID token from Google. Use it to authenticate // with your backend. Log.d(TAG, "Got ID token.") } password != null -> { // Got a saved username and password. Use them to authenticate // with your backend. Log.d(TAG, "Got password.") } else -> { // Shouldn't happen. Log.d(TAG, "No ID token or password!") } } } 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})") } } } } } } // ... }
5. التعامل مع تسجيل الخروج
عندما يسجّل المستخدم الخروج من تطبيقك، استدعِ طريقة signOut() لعميل "نقرة واحدة".
يؤدي استدعاء signOut() إلى إيقاف ميزة "تسجيل الدخول تلقائيًا" إلى أن يسجّل المستخدم الدخول مرة أخرى.
حتى إذا كنت لا تستخدم ميزة "تسجيل الدخول تلقائيًا"، فإنّ هذه الخطوة مهمة لأنّها تضمن أنّه عند تسجيل خروج المستخدمين من تطبيقك، تتم أيضًا إعادة ضبط حالة المصادقة لأي واجهات برمجة تطبيقات في "خدمات Play" تستخدمها.
الخطوات التالية
إذا أعددت عميل "نقرة واحدة" لاسترداد بيانات اعتماد Google، يمكن لتطبيقك الآن الحصول على رموز تعريف Google التي تمثّل حسابات المستخدمين على Google. تعلَّم كيف يمكنك استخدام هذه الرموز على خادم الخلفية.