يشرح هذا الدليل كيفية تنفيذ ميزة "تسجيل الدخول باستخدام حساب Google" ويتناول الخطوات التالية:
- أضِف التبعيات إلى تطبيقك.
- إنشاء مثيل
CredentialManager - أنشئ سير عمل البطاقة السفلية.
- أنشِئ مسار الزر.
- التعامل مع ردّ تسجيل الدخول
- معالجة الأخطاء
- التعامل مع تسجيل الخروج
إضافة التبعيات إلى تطبيقك
في ملف build.gradle الخاص بالوحدة، حدِّد التبعيات باستخدام أحدث إصدار من Credential Manager وخدمات Play Auth وgoogleid:
Kotlin
dependencies { implementation("androidx.credentials:credentials:1.7.0-alpha02") implementation("androidx.credentials:credentials-play-services-auth:1.7.0-alpha02") implementation("com.google.android.libraries.identity.googleid:googleid:<latest version>") }
Groovy
dependencies { implementation "androidx.credentials:credentials:1.7.0-alpha02" implementation "androidx.credentials:credentials-play-services-auth:1.7.0-alpha02" 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)
إنشاء مسار البطاقة السفلية
البطاقة السفلية هي واجهة المستخدم المضمّنة في Credential Manager. يؤدي استخدام واجهة المستخدم هذه إلى توفير تجربة متّسقة في جميع طرق المصادقة، مثل كلمات المرور ومفاتيح المرور وميزة "تسجيل الدخول باستخدام حساب 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.
ضبط رقم خاص (اختياري): لتفعيل مستوى الأمان المحسّن، اضبط رقمًا خاصًا لعملية التحقّق من جهة الخادم. لمنع هجمات إعادة التشغيل، يمكنك تضمين رقم عشوائي يُستخدم مرة واحدة لإجراء عملية تحقّق من جهة الخادم باستخدام
setNonce(). تأكَّد من أنّ الرمز البرمجي من جهة الخادم يتحقّق من تطابق أرقام الـ 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()
// Use an activity-based context to avoid undefined system UI
// launching behavior.
val mutableContext = MutableContextWrapper(activityContext)
coroutineScope {
try {
val result = credentialManager.getCredential(
request = request,
context = mutableContext // Use MutableContextWrapper to avoid memory leak during configuration changes
)
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() لمحو حالة بيانات اعتماد المستخدم الحالية من جميع مزوّدي بيانات الاعتماد.
سيؤدي ذلك إلى إرسال إشعار إلى جميع مزوّدي بيانات الاعتماد بأنّه يجب محو أي جلسة بيانات اعتماد مخزّنة
للتطبيق المحدّد، ما يوفّر للمستخدمين خيارات تسجيل الدخول الكاملة في
المرة القادمة.