يوضّح هذا الدليل كيفية تنفيذ ميزة "تسجيل الدخول باستخدام حساب Google" ويتناول الخطوات التالية:
- أضِف التبعيات إلى تطبيقك.
- إنشاء مثيل
CredentialManager - أنشئ سير عمل للورقة السفلية.
- أنشئ سير عمل الزر.
- التعامل مع استجابة تسجيل الدخول
- معالجة الأخطاء
- التعامل مع عملية تسجيل الخروج
إضافة التبعيات إلى تطبيقك
في ملف build.gradle الخاص بالوحدة، عرِّف التبعيات باستخدام أحدث إصدار من Credential Manager وخدمات Play Auth وgoogleid:
Kotlin
dependencies { implementation("androidx.credentials:credentials:1.6.0-rc02") implementation("androidx.credentials:credentials-play-services-auth:1.6.0-rc02") implementation("com.google.android.libraries.identity.googleid:googleid:<latest version>") }
Groovy
dependencies { implementation "androidx.credentials:credentials:1.6.0-rc02" implementation "androidx.credentials:credentials-play-services-auth:1.6.0-rc02" implementation "com.google.android.libraries.identity.googleid:googleid:<latest version>" }
إنشاء مثيل لـ Credential Manager
استخدِم سياق تطبيقك أو نشاطك لإنشاء عنصر CredentialManager.
// Use your app or activity context to instantiate a client instance of
// CredentialManager.
private val credentialManager = CredentialManager.create(context)
إنشاء سير عمل البطاقة السفلية
البطاقة السفلية هي واجهة المستخدم المضمّنة في "مدير بيانات الاعتماد". تتيح واجهة المستخدم هذه تجربة متسقة في جميع طرق المصادقة، مثل كلمات المرور ومفاتيح المرور و"تسجيل الدخول باستخدام حساب Google".
ضبط طلب تسجيل الدخول للحسابات التي تمّت الموافقة عليها سابقًا
حاوِل إرسال طلب تسجيل دخول باستخدام Google مع GetGoogleIdOption لاسترداد الرمز المميّز لتعريف المستخدم على Google.
تتحقّق المقتطفات التالية ممّا إذا كان الحساب حسابًا معتمَدًا.
val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
.setFilterByAuthorizedAccounts(true)
.setServerClientId(WEB_CLIENT_ID)
.setAutoSelectEnabled(true)
.setNonce(generateSecureRandomNonce())
.build()
يتم ضبط الكائن googleIdOption الخاص بالطلب على النحو التالي:
فلترة الحسابات التي تم منحها الإذن سابقًا: لاسترداد الحسابات التي تم منحها الإذن والتي تم استخدامها سابقًا لتسجيل الدخول إلى تطبيقك، اضبط قيمة
setFilterByAuthorizedAccountsعلىtrue.يُرجى العِلم أنّ القيمة التلقائية لـ
setFilterByAuthorizedAccountsهيtrue، ما يعني أنّ السلوك التلقائي لواجهة مستخدم ورقة البيانات السفلية هو عرض الحسابات التي تم منحها الإذن سابقًا فقط.ضبط رقم تعريف العميل على الخادم: اضبط المَعلمة
setServerClientId.webClientIdهو معرّف عميل الويب الذي أعددته لبروتوكول OAuth في مشروعك على Google Cloud أثناء إكمال المتطلبات الأساسية.تفعيل ميزة "تسجيل الدخول التلقائي" (اختياري): لتفعيل ميزة تسجيل الدخول التلقائي للمستخدمين المتكرّرين، استخدِم
setAutoSelectEnabled(true)وsetFilterByAuthorizedAccounts(true). بالنسبة إلى مستخدمي تطبيقك، يزيل ذلك أي عوائق غير ضرورية إذا كانوا قد سجّلوا الدخول من قبل.لا يمكن تفعيل ميزة "تسجيل الدخول التلقائي" إلا عند استيفاء المعايير التالية:
- يجب أن يكون هناك حساب واحد معتمَد على الجهاز، وأن يكون هذا الحساب المعتمَد قد تم استخدامه سابقًا لتسجيل الدخول إلى التطبيق على الجهاز. يؤدي وجود حسابات معتمَدة متعددة على الجهاز إلى إيقاف ميزة تسجيل الدخول التلقائي.
- لم يسجّل المستخدم الخروج من التطبيق بشكل صريح خلال جلسته السابقة.
- لم يوقف المستخدم ميزة "تسجيل الدخول تلقائيًا" في إعدادات حساب Google.
ضبط قيمة nonce (اختياري): لتفعيل الأمان المحسّن، اضبط قيمة nonce لعملية تحقّق من جهة الخادم. لمنع هجمات إعادة الإرسال، يمكنك تضمين رقم عشوائي لإجراء عملية التحقّق من جهة الخادم باستخدام
setNonce(). تأكَّد من أنّ الرمز البرمجي من جهة الخادم يتحقّق من تطابق أرقام nonce في الطلب والاستجابة.لإنشاء قيمة nonce، استخدِم دالة مشابهة للدالة التالية التي تنشئ قيمة nonce عشوائية قوية من ناحية التشفير بطول محدّد وتشفّرها باستخدام
Base64:
fun generateSecureRandomNonce(byteLength: Int = 32): String {
val randomBytes = ByteArray(byteLength)
SecureRandom().nextBytes(randomBytes)
return Base64.encodeToString(randomBytes, Base64.NO_WRAP or Base64.URL_SAFE or Base64.NO_PADDING)
}
طلب تسجيل الدخول
تحقَّق مما إذا كان لدى المستخدم حساب معتمَد على الجهاز من خلال استدعاء طريقة
getCredential:
val request: GetCredentialRequest = GetCredentialRequest.Builder()
.addCredentialOption(googleIdOption)
.build()
coroutineScope {
try {
val result = credentialManager.getCredential(
request = request,
context = activityContext,
)
handleSignIn(result)
} catch (e: GetCredentialException) {
// Handle failures
}
}
ضبط طلب تسجيل الدخول في حال عدم توفّر أي حسابات معتمَدة
إذا لم يكن هناك أي مستخدمين معتمَدين لتطبيقك على الجهاز، ستعرض الدالة CredentialManager الرمز NoCredentialException. في هذه الحالة، عليك إيقاف فلتر الحسابات المصرّح بها حتى يتمكّن المستخدم من استخدام حساب آخر للاشتراك.
val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
.setFilterByAuthorizedAccounts(false)
.setServerClientId(WEB_CLIENT_ID)
.setNonce(generateSecureRandomNonce())
.build()
بعد ذلك، اطلب تسجيل الدخول بالطريقة نفسها التي اتّبعتها للحسابات المعتمَدة.
إنشاء مسار الزر
استخدِم زرًا إذا كنت تريد أن يتمكّن المستخدمون من تسجيل الدخول باستخدام حساب Google في الحالات التالية:
- أغلق المستخدم واجهة مستخدم البطاقة السفلية في Credential Manager.
- لا تتوفّر حسابات Google على الجهاز.
- تتطلّب الحسابات الحالية على الجهاز إعادة المصادقة.
إنشاء واجهة مستخدم الزر
على الرغم من إمكانية تنفيذ ذلك باستخدام زر Jetpack Compose، يمكنك استخدام رمز علامة تجارية معتمَد مسبقًا من صفحة إرشادات تصميم العلامة التجارية لميزة "تسجيل الدخول باستخدام حساب Google".
إنشاء مسار تسجيل الدخول
أنشئ طلب تسجيل دخول باستخدام Google مع
GetSignInWithGoogleOption لاسترداد رمز مميّز لتعريف Google.
val signInWithGoogleOption: GetSignInWithGoogleOption = GetSignInWithGoogleOption.Builder(
serverClientId = WEB_CLIENT_ID
).setNonce(generateSecureRandomNonce())
.build()
بعد ذلك، اطلب تسجيل الدخول بالطريقة نفسها التي اتّبعتها مع واجهة المستخدم الخاصة بالورقة السفلية.
إنشاء وظيفة تسجيل الدخول المشترَكة للبطاقة السفلية والزر
للتعامل مع عملية تسجيل الدخول، أكمِل الخطوات التالية:
- استخدِم الدالة
getCredential()في CredentialManager. إذا كانت الاستجابة ناجحة، استخرِجCustomCredentialالذي يجب أن يكون من النوعGoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL. حوِّل العنصر إلى
GoogleIdTokenCredentialباستخدام الطريقةGoogleIdTokenCredential.createFrom().تحقَّق من صحة بيانات الاعتماد على خادم الجهة المعتمِدة.
تأكَّد من التعامل مع الأخطاء بشكل مناسب.
fun handleSign(result: GetCredentialResponse) {
// Handle the successfully returned credential.
val credential = result.credential
when (credential) {
is CustomCredential -> {
if (credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) {
try {
// Use googleIdTokenCredential and extract the ID for server-side validation.
val googleIdTokenCredential = GoogleIdTokenCredential
.createFrom(credential.data)
} catch (e: GoogleIdTokenParsingException) {
Log.e(TAG, "Received an invalid google id token response", e)
}
} else {
// Catch any unrecognized credential type here.
Log.e(TAG, "Unexpected type of credential")
}
}
else -> {
// Catch any unrecognized credential type here.
Log.e(TAG, "Unexpected type of credential")
}
}
}
معالجة الأخطاء
راجِع الأخطاء المُدرَجة في تحديد المشاكل وحلّها للتأكّد من أنّ الرمز البرمجي يعالج جميع سيناريوهات الأخطاء المحتملة.
التعامل مع تسجيل الخروج
من المهم توفير آلية تتيح للمستخدمين تسجيل الخروج من تطبيقك. على سبيل المثال، قد يكون لدى المستخدم حسابات متعددة على Google على الجهاز ويقرّر تسجيل الدخول من حساب مختلف. يمكنك تقديم هذه المعلومات في صفحة الإعدادات مثلاً.
قد يخزِّن موفّر بيانات الاعتماد جلسة بيانات اعتماد نشطة ويستخدمها للحدّ من خيارات تسجيل الدخول لطلبات تسجيل الدخول المستقبلية. على سبيل المثال، يمكنه تحديد أولوية بيانات الاعتماد النشطة على أي بيانات اعتماد أخرى متاحة.
عندما يسجّل المستخدم الخروج من تطبيقك، استدعِ طريقة clearCredentialState() في واجهة برمجة التطبيقات لمحو حالة بيانات اعتماد المستخدم الحالية من جميع مقدّمي بيانات الاعتماد.
سيؤدي ذلك إلى إرسال إشعار إلى جميع مقدّمي بيانات الاعتماد بأنّه يجب محو أي جلسة بيانات اعتماد مخزّنة للتطبيق المحدّد، ما يوفّر للمستخدمين خيارات تسجيل دخول كاملة في المرة التالية.