1. शुरू करने से पहले
इस कोडलैब में, Android पर Credential Manager का इस्तेमाल करके, 'Google से साइन इन करें' सुविधा को लागू करने का तरीका बताया गया है.
ज़रूरी शर्तें
- Android डेवलपमेंट के लिए Kotlin का इस्तेमाल करने की बुनियादी जानकारी
- Jetpack Compose की बुनियादी जानकारी (ज़्यादा जानकारी के लिए, यहां जाएं)
आपको क्या सीखने को मिलेगा
- Google Cloud प्रोजेक्ट बनाने का तरीका
- Google Cloud Console में OAuth क्लाइंट बनाने का तरीका
- बॉटम शीट फ़्लो का इस्तेमाल करके, 'Google से साइन इन करें' सुविधा को लागू करने का तरीका
- बटन फ़्लो का इस्तेमाल करके, 'Google से साइन इन करें' सुविधा को लागू करने का तरीका
आपको इन चीज़ों की ज़रूरत पड़ेगी
- Android Studio (इसे यहां से डाउनलोड करें)
- ऐसा कंप्यूटर जो Android Studio की सिस्टम से जुड़ी ज़रूरी शर्तें पूरी करता हो
- ऐसा कंप्यूटर जो Android Emulator की सिस्टम से जुड़ी ज़रूरी शर्तें पूरी करता हो
- Java और Java डेवलपमेंट किट (JDK) इंस्टॉल करना
2. Android Studio प्रोजेक्ट बनाना
अवधि 3:00 - 5:00
शुरू करने के लिए, हमें Android Studio में एक नया प्रोजेक्ट बनाना होगा:
- Android Studio खोलना
- नया प्रोजेक्ट
पर क्लिक करें
- फ़ोन और टैबलेट और बिना ऐक्टिविटी वाला
चुनें
- आगे बढ़ें पर क्लिक करें
- अब प्रोजेक्ट के कुछ हिस्सों को सेट अप करने का समय है:
- नाम: यह आपके प्रोजेक्ट का नाम है
- पैकेज का नाम: यह आपके प्रोजेक्ट के नाम के आधार पर अपने-आप भर जाएगा
- सेव करने की जगह: यह डिफ़ॉल्ट रूप से उस फ़ोल्डर पर सेट होनी चाहिए जिसमें Android Studio आपके प्रोजेक्ट सेव करता है. इसे अपनी पसंद के हिसाब से बदला जा सकता है.
- एसडीके का कम से कम वर्शन: यह Android एसडीके का सबसे पुराना वर्शन है, जिस पर आपका ऐप्लिकेशन काम करता है. इस कोडलैब में, हम API 36 (Baklava) का इस्तेमाल करेंगे
- पूरा करें पर क्लिक करें
- Android Studio, प्रोजेक्ट बनाएगा और बुनियादी ऐप्लिकेशन के लिए ज़रूरी डिपेंडेंसी डाउनलोड करेगा. इसमें कुछ मिनट लग सकते हैं. ऐसा होते हुए देखने के लिए, सिर्फ़ बिल्ड आइकॉन पर क्लिक करें:
- यह प्रोसेस पूरी होने के बाद, Android Studio कुछ ऐसा दिखना चाहिए:
3. Google Cloud प्रोजेक्ट सेट अप करना
Google Cloud प्रोजेक्ट बनाना
- Google Cloud Console पर जाएं
- अपना प्रोजेक्ट खोलें या नया प्रोजेक्ट बनाएं
- एपीआई और सेवाएं
पर क्लिक करें
- OAuth के लिए सहमति वाली स्क्रीन पर जाएं
- जारी रखने के लिए, आपको खाते की खास जानकारी में मौजूद फ़ील्ड भरने होंगे. यह जानकारी भरने के लिए, शुरू करें पर क्लिक करें:
- ऐप्लिकेशन का नाम: इस ऐप्लिकेशन का नाम. यह वही नाम होना चाहिए जिसका इस्तेमाल आपने Android Studio में प्रोजेक्ट बनाते समय किया था
- उपयोगकर्ता सहायता ईमेल: इससे आपको उस Google खाते के बारे में पता चलेगा जिससे आपने लॉगिन किया है. साथ ही, आपको उन Google ग्रुप के बारे में भी पता चलेगा जिन्हें मैनेज किया जाता है
- दर्शक:
- इंटरनल ऐप्लिकेशन, सिर्फ़ आपके संगठन में इस्तेमाल किया जाता है. अगर आपके पास Google Cloud प्रोजेक्ट से जुड़ा कोई संगठन नहीं है, तो आपके पास इसे चुनने का विकल्प नहीं होगा.
- हम बाहरी कुकी का इस्तेमाल करेंगे.
- संपर्क जानकारी: इसमें वह ईमेल पता शामिल किया जा सकता है जिसका इस्तेमाल ऐप्लिकेशन से जुड़ी जानकारी पाने के लिए किया जाएगा
- Google API सेवाएं: उपयोगकर्ता के डेटा की नीति पढ़ें.
- उपयोगकर्ता के डेटा से जुड़ी नीति को पढ़ने और उससे सहमत होने के बाद, बनाएं
OAuth क्लाइंट सेट अप करना
अब हमने Google Cloud प्रोजेक्ट सेट अप कर लिया है. इसलिए, हमें एक वेब क्लाइंट और Android क्लाइंट जोड़ना होगा, ताकि हम उनके क्लाइंट आईडी की मदद से OAuth बैकएंड सर्वर को एपीआई कॉल कर सकें.
Android वेब क्लाइंट के लिए, आपको इनकी ज़रूरत होगी:
- आपके ऐप्लिकेशन के पैकेज का नाम (जैसे, com.example.example)
- आपके ऐप्लिकेशन का SHA-1 हस्ताक्षर
- SHA-1 सिग्नेचर क्या होता है?
- SHA-1 फ़िंगरप्रिंट एक क्रिप्टोग्राफ़िक हैश होता है. इसे आपके ऐप्लिकेशन की साइनिंग की से जनरेट किया जाता है. यह आपके ऐप्लिकेशन के हस्ताक्षर करने वाले सर्टिफ़िकेट के लिए यूनीक आइडेंटिफ़ायर के तौर पर काम करता है. इसे अपने ऐप्लिकेशन के लिए डिजिटल "हस्ताक्षर" के तौर पर समझें.
- हमें SHA-1 हस्ताक्षर की ज़रूरत क्यों होती है?
- SHA-1 फ़िंगरप्रिंट से यह पक्का होता है कि सिर्फ़ आपका ऐप्लिकेशन, आपके OAuth 2.0 क्लाइंट आईडी का इस्तेमाल करके ऐक्सेस टोकन का अनुरोध कर सकता है. साथ ही, यह भी पक्का होता है कि आपके ऐप्लिकेशन को आपकी खास साइनिंग कुंजी से साइन किया गया हो. इससे, दूसरे ऐप्लिकेशन (यहां तक कि एक ही पैकेज के नाम वाले ऐप्लिकेशन) को आपके प्रोजेक्ट के संसाधनों और उपयोगकर्ता के डेटा को ऐक्सेस करने से रोका जा सकता है.
- इसे इस तरह समझें:
- आपके ऐप्लिकेशन की साइनिंग की, आपके ऐप्लिकेशन के "दरवाज़े" की असली चाबी की तरह होती है. इससे ऐप्लिकेशन के अंदरूनी कामकाज को ऐक्सेस किया जा सकता है.
- SHA-1 फ़िंगरप्रिंट, यूनीक कीकार्ड आईडी की तरह होता है. यह आपकी फ़िज़िकल चाबी से लिंक होता है. यह एक खास कोड होता है, जो उस कुंजी की पहचान करता है.
- OAuth 2.0 क्लाइंट आईडी, Google के किसी संसाधन या सेवा (जैसे, Google साइन-इन) के लिए एंट्री कोड की तरह होता है.
- OAuth क्लाइंट सेटअप के दौरान SHA-1 फ़िंगरप्रिंट देने का मतलब है कि आपने Google को यह बताया है: "सिर्फ़ इस खास आईडी (SHA-1) वाला कीकार्ड, इस ऐक्सेस कोड (क्लाइंट आईडी) को खोल सकता है." इससे यह पक्का होता है कि सिर्फ़ आपका ऐप्लिकेशन, उस एंट्री कोड से लिंक की गई Google सेवाओं को ऐक्सेस कर सकता है."
- SHA-1 सिग्नेचर क्या होता है?
वेब क्लाइंट के लिए, हमें सिर्फ़ वह नाम चाहिए जिसका इस्तेमाल आपको कंसोल में क्लाइंट की पहचान करने के लिए करना है.
Android OAuth 2.0 क्लाइंट बनाना
- क्लाइंट पेज पर जाएं
- क्लाइंट बनाएं
पर क्लिक करें
- ऐप्लिकेशन टाइप के लिए, Android चुनें
- आपको अपने ऐप्लिकेशन का पैकेज नाम
- Android Studio से हमें अपने ऐप्लिकेशन का SHA-1 सिग्नेचर पाना होगा. इसके बाद, उसे यहां कॉपी/चिपकाना होगा:
- Android Studio पर जाएं और टर्मिनल खोलें
- यह कमांड चलाएं: Mac/Linux:
Windows पर:keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android
इस कमांड को, कीस्टोर में मौजूद किसी खास एंट्री (उर्फ़) की जानकारी दिखाने के लिए डिज़ाइन किया गया है.keytool -list -v -keystore "C:\Users\USERNAME\.android\debug.keystore" -alias androiddebugkey -storepass android -keypass android
-list
: इस विकल्प से keytool को कीस्टोर का कॉन्टेंट दिखाने का निर्देश मिलता है.-v
: इस विकल्प से वर्बोस आउटपुट चालू होता है. इससे एंट्री के बारे में ज़्यादा जानकारी मिलती है.-keystore ~/.android/debug.keystore
: इससे कीस्टोर फ़ाइल का पाथ तय होता है.-alias androiddebugkey
: इससे उस कुंजी का उपनाम (एंट्री का नाम) पता चलता है जिसकी आपको जांच करनी है.-storepass android
: इससे कीस्टोर फ़ाइल का पासवर्ड मिलता है.-keypass android
: इससे, तय किए गए एलियास की निजी कुंजी का पासवर्ड मिलता है.
- SHA-1 हस्ताक्षर की वैल्यू कॉपी करें:
- Google Cloud विंडो पर वापस जाएं और SHA-1 हस्ताक्षर की वैल्यू चिपकाएं:
- अब आपकी स्क्रीन ऐसी दिखनी चाहिए. इसके बाद, बनाएं पर क्लिक करें:
वेब OAuth 2.0 क्लाइंट बनाना
- वेब ऐप्लिकेशन क्लाइंट आईडी बनाने के लिए, Android क्लाइंट बनाएं सेक्शन में दिए गए पहले दो चरणों को दोहराएं. इसके बाद, ऐप्लिकेशन टाइप के लिए वेब ऐप्लिकेशन चुनें
- क्लाइंट को एक नाम दें (यह OAuth क्लाइंट होगा):
- बनाएं
पर क्लिक करें
- पॉप-अप विंडो से क्लाइंट आईडी कॉपी करें. आपको इसकी ज़रूरत बाद में पड़ेगी
अब हमारे OAuth क्लाइंट सेट अप हो गए हैं. इसलिए, हम Android Studio पर वापस जाकर, 'Google से साइन इन करें' सुविधा वाला Android ऐप्लिकेशन बना सकते हैं!
4. Android वर्चुअल डिवाइस सेट अप करना
अगर आपको किसी फ़िज़िकल Android डिवाइस के बिना अपने ऐप्लिकेशन की तुरंत जांच करनी है, तो आपको एक Android वर्चुअल डिवाइस बनाना होगा. इस डिवाइस पर, Android Studio से ऐप्लिकेशन बनाया जा सकता है और उसे तुरंत चलाया जा सकता है. अगर आपको किसी Android डिवाइस पर टेस्ट करना है, तो Android डेवलपर दस्तावेज़ में दिए गए निर्देशों का पालन करें
Android वर्चुअल डिवाइस बनाना
- Android Studio में, डिवाइस मैनेजर
खोलें
- प्लस बटन > वर्चुअल डिवाइस बनाएं पर क्लिक करें
- यहाँ से, अपने प्रोजेक्ट के लिए ज़रूरी कोई भी डिवाइस जोड़ा जा सकता है. इस कोडलैब के लिए, मीडियम फ़ोन चुनें. इसके बाद, आगे बढ़ें पर क्लिक करें
- अब अपने प्रोजेक्ट के लिए डिवाइस को कॉन्फ़िगर किया जा सकता है. इसके लिए, डिवाइस को कोई यूनीक नाम दें और Android का वह वर्शन चुनें जिस पर डिवाइस चलेगा. इसके अलावा, और भी काम किए जा सकते हैं. पक्का करें कि एपीआई को एपीआई 36 "बक्लावा"; Android 16 पर सेट किया गया हो. इसके बाद, पूरा करें पर क्लिक करें
- आपको डिवाइस मैनेजर में नया डिवाइस दिखना चाहिए. यह पुष्टि करने के लिए कि डिवाइस काम कर रहा है,
उस डिवाइस के बगल में मौजूद
पर क्लिक करें जिसे आपने अभी बनाया है
- अब डिवाइस चालू हो जाना चाहिए!
Android Virtual Device में साइन इन करना
आपने अभी जो डिवाइस बनाया है वह काम करता है. अब 'Google से साइन इन करें' सुविधा की जांच करते समय गड़बड़ियों को रोकने के लिए, हमें डिवाइस में Google खाते से साइन इन करना होगा.
- सेटिंग पर जाएं:
- वर्चुअल डिवाइस की स्क्रीन के बीच में क्लिक करें और ऊपर की ओर स्वाइप करें
- Settings ऐप्लिकेशन ढूंढें और उस पर क्लिक करें
- सेटिंग
में जाकर, Google पर क्लिक करें
- साइन इन करें पर क्लिक करें और अपने Google खाते में साइन इन करने के लिए, दिए गए निर्देशों का पालन करें
- अब आपको डिवाइस
पर साइन इन करना चाहिए
आपका वर्चुअल Android डिवाइस अब टेस्टिंग के लिए तैयार है!
5. डिपेंडेंसी जोड़ें
अवधि 5:00
OAuth API कॉल करने के लिए, हमें पहले ज़रूरी लाइब्रेरी को इंटिग्रेट करना होगा. इससे हमें पुष्टि करने के अनुरोध करने और उन अनुरोधों को करने के लिए Google आईडी का इस्तेमाल करने की अनुमति मिलती है:
- libs.googleid
- libs.play.services.auth
- फ़ाइल > प्रोजेक्ट स्ट्रक्चर:
पर जाएं
- इसके बाद, Dependencies > app > '+' > Library Dependency
पर जाएं
- अब हमें अपनी लाइब्रेरी जोड़नी होंगी:
- खोज डायलॉग में, googleid टाइप करें और खोजें पर क्लिक करें
- सिर्फ़ एक एंट्री होनी चाहिए. इसे चुनें और उपलब्ध सबसे नया वर्शन चुनें. (इस Codelab के समय, यह 1.1.1 है)
- ठीक है
पर क्लिक करें
- पहले से तीसरे चरण को दोहराएं. हालांकि, इस बार "play-services-auth" खोजें. इसके बाद, "com.google.android.gms" वाले ग्रुप आईडी और "play-services-auth" वाले आर्टफ़ैक्ट के नाम वाली लाइन चुनें
- ठीक है
पर क्लिक करें
6. बॉटम शीट फ़्लो
बॉटम शीट फ़्लो, Credential Manager API का इस्तेमाल करता है. इससे लोग, Android डिवाइस पर अपने Google खातों से आपके ऐप्लिकेशन में आसानी से साइन इन कर पाते हैं. इसे खास तौर पर, लौटने वाले उपयोगकर्ताओं के लिए, जल्दी और आसानी से इस्तेमाल करने के लिए डिज़ाइन किया गया है. यह फ़्लो, ऐप्लिकेशन लॉन्च होने पर ट्रिगर होना चाहिए.
साइन-इन करने का अनुरोध बनाना
- शुरू करने के लिए,
MainActivity.kt
सेGreeting()
औरGreetingPreview()
फ़ंक्शन हटा दें. हमें इनकी ज़रूरत नहीं होगी. - अब हमें यह पक्का करना होगा कि इस प्रोजेक्ट के लिए ज़रूरी पैकेज इंपोर्ट किए गए हों. यहां दिए गए
import
स्टेटमेंट को, लाइन 3 से शुरू होने वाले मौजूदा स्टेटमेंट के बाद जोड़ें::import android.content.ContentValues.TAG import android.content.Context import android.credentials.GetCredentialException import android.os.Build import android.util.Log import android.widget.Toast import androidx.annotation.RequiresApi import androidx.compose.foundation.clickable import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.credentials.CredentialManager import androidx.credentials.exceptions.GetCredentialCancellationException import androidx.credentials.exceptions.GetCredentialCustomException import androidx.credentials.exceptions.NoCredentialException import androidx.credentials.GetCredentialRequest import com.google.android.libraries.identity.googleid.GetGoogleIdOption import com.google.android.libraries.identity.googleid.GetSignInWithGoogleOption import com.google.android.libraries.identity.googleid.GoogleIdTokenParsingException import java.security.SecureRandom import java.util.Base64 import kotlinx.coroutines.CoroutineScope import androidx.compose.runtime.LaunchedEffect import kotlinx.coroutines.delay import kotlinx.coroutines.launch
- इसके बाद, हमें बॉटम शीट के अनुरोध को बनाने के लिए अपना फ़ंक्शन बनाना होगा. इस कोड को MainActivity क्लास के नीचे चिपकाएं
//This line is not needed for the project to build, but you will see errors if it is not present.
//This code will not work on Android versions < UpsideDownCake
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
@Composable
fun BottomSheet(webClientId: String) {
val context = LocalContext.current
// LaunchedEffect is used to run a suspend function when the composable is first launched.
LaunchedEffect(Unit) {
// Create a Google ID option with filtering by authorized accounts enabled.
val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
.setFilterByAuthorizedAccounts(true)
.setServerClientId(webClientId)
.setNonce(generateSecureRandomNonce())
.build()
// Create a credential request with the Google ID option.
val request: GetCredentialRequest = GetCredentialRequest.Builder()
.addCredentialOption(googleIdOption)
.build()
// Attempt to sign in with the created request using an authorized account
val e = signIn(request, context)
// If the sign-in fails with NoCredentialException, there are no authorized accounts.
// In this case, we attempt to sign in again with filtering disabled.
if (e is NoCredentialException) {
val googleIdOptionFalse: GetGoogleIdOption = GetGoogleIdOption.Builder()
.setFilterByAuthorizedAccounts(false)
.setServerClientId(webClientId)
.setNonce(generateSecureRandomNonce())
.build()
val requestFalse: GetCredentialRequest = GetCredentialRequest.Builder()
.addCredentialOption(googleIdOptionFalse)
.build()
//We will build out this function in a moment
signIn(requestFalse, context)
}
}
}
//This function is used to generate a secure nonce to pass in with our request
fun generateSecureRandomNonce(byteLength: Int = 32): String {
val randomBytes = ByteArray(byteLength)
SecureRandom.getInstanceStrong().nextBytes(randomBytes)
return Base64.getUrlEncoder().withoutPadding().encodeToString(randomBytes)
}
आइए, जानते हैं कि यह कोड क्या कर रहा है:
fun BottomSheet(webClientId: String) {...}
: BottomSheet नाम का एक फ़ंक्शन बनाता है, जो webClientId नाम का एक स्ट्रिंग आर्ग्युमेंट लेता है
val context = LocalContext.current
: यह मौजूदा Android कॉन्टेक्स्ट को वापस लाता है. इसकी ज़रूरत कई कार्रवाइयों के लिए होती है. जैसे, यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट लॉन्च करना.LaunchedEffect(Unit) { ... }
:LaunchedEffect
एक Jetpack Compose कंपोज़ेबल है. इसकी मदद से, कंपोज़ेबल के लाइफ़साइकल में सस्पेंड फ़ंक्शन (ऐसा फ़ंक्शन जो कुछ समय के लिए रुक सकता है और फिर से शुरू हो सकता है) चलाया जा सकता है. यूनिट को कुंजी के तौर पर इस्तेमाल करने का मतलब है कि कंपोज़ेबल के पहली बार लॉन्च होने पर, यह इफ़ेक्ट सिर्फ़ एक बार चलेगा.val googleIdOption: GetGoogleIdOption = ...
:GetGoogleIdOption
ऑब्जेक्ट बनाता है. यह ऑब्जेक्ट, Google से अनुरोध किए जा रहे क्रेडेंशियल के टाइप को कॉन्फ़िगर करता है..Builder()
: विकल्पों को कॉन्फ़िगर करने के लिए, बिल्डर पैटर्न का इस्तेमाल किया जाता है..setFilterByAuthorizedAccounts(true)
: इससे यह तय होता है कि उपयोगकर्ता को सभी Google खातों में से कोई खाता चुनने की अनुमति देनी है या सिर्फ़ उन खातों में से कोई खाता चुनने की अनुमति देनी है जिन्होंने पहले ही ऐप्लिकेशन को अनुमति दी है. इस मामले में, इसे 'सही है' पर सेट किया गया है. इसका मतलब है कि अनुरोध उन क्रेडेंशियल का इस्तेमाल करके किया जाएगा जिन्हें उपयोगकर्ता ने पहले इस ऐप्लिकेशन के साथ इस्तेमाल करने की अनुमति दी थी. हालांकि, ऐसा सिर्फ़ तब होगा, जब कोई क्रेडेंशियल उपलब्ध हो..setServerClientId(webClientId)
: यह सर्वर क्लाइंट आईडी सेट करता है. यह आपके ऐप्लिकेशन के बैकएंड के लिए यूनीक आइडेंटिफ़ायर होता है. आईडी टोकन पाने के लिए, यह ज़रूरी है..setNonce(generateSecureRandomNonce())
: यह एक नॉनस सेट करता है. यह एक रैंडम वैल्यू होती है. इसका इस्तेमाल रीप्ले अटैक को रोकने के लिए किया जाता है. साथ ही, यह पक्का करने के लिए किया जाता है कि आईडी टोकन, किसी खास अनुरोध से जुड़ा हो..build()
: यहGetGoogleIdOption
ऑब्जेक्ट बनाता है. इसमें बताई गई कॉन्फ़िगरेशन का इस्तेमाल किया जाता है.
val request: GetCredentialRequest = ...
:GetCredentialRequest
ऑब्जेक्ट बनाता है. इस ऑब्जेक्ट में, क्रेडेंशियल का पूरा अनुरोध शामिल होता है..Builder()
: यह अनुरोध को कॉन्फ़िगर करने के लिए, बिल्डर पैटर्न शुरू करता है..addCredentialOption(googleIdOption)
: यह अनुरोध में googleIdOption जोड़ता है. इससे यह पता चलता है कि हमें Google आईडी टोकन का अनुरोध करना है..build()
:GetCredentialRequest
ऑब्जेक्ट बनाता है.
val e = signIn(request, context)
: इससे, बनाए गए अनुरोध और मौजूदा कॉन्टेक्स्ट के साथ उपयोगकर्ता को साइन इन करने की कोशिश की जाती है. signIn फ़ंक्शन का नतीजा, e में सेव किया जाता है. इस वैरिएबल में, या तो अनुरोध पूरा होने का नतीजा होगा या कोई अपवाद होगा.if (e is NoCredentialException) { ... }
: यह एक शर्त के साथ किया जाने वाला चेक है. अगर signIn फ़ंक्शन, NoCredentialException के साथ काम नहीं करता है, तो इसका मतलब है कि पहले से अनुमति पाए हुए कोई भी खाते उपलब्ध नहीं हैं.val googleIdOptionFalse: GetGoogleIdOption = ...
: अगर पिछलाsignIn
पूरा नहीं होता है, तो यह हिस्सा एक नयाGetGoogleIdOption
बनाता है..setFilterByAuthorizedAccounts(false)
: यह पहले विकल्प से काफ़ी अलग है. इससे, आधिकारिक खातों को फ़िल्टर करने की सुविधा बंद हो जाती है. इसका मतलब है कि डिवाइस पर मौजूद किसी भी Google खाते का इस्तेमाल करके साइन इन किया जा सकता है.val requestFalse: GetCredentialRequest = ...
:googleIdOptionFalse
का इस्तेमाल करके, एक नयाGetCredentialRequest
बनाया जाता है.signIn(requestFalse, context)
: इससे उपयोगकर्ता को नए अनुरोध के साथ साइन इन करने की कोशिश की जाती है. इससे किसी भी खाते का इस्तेमाल किया जा सकता है.
असल में, यह कोड Credential Manager API को अनुरोध भेजने के लिए तैयार करता है. इससे उपयोगकर्ता के लिए Google आईडी टोकन वापस पाया जा सकता है. इसके लिए, दिए गए कॉन्फ़िगरेशन का इस्तेमाल किया जाता है. इसके बाद, GetCredentialRequest का इस्तेमाल क्रेडेंशियल मैनेजर यूज़र इंटरफ़ेस (यूआई) लॉन्च करने के लिए किया जा सकता है. यहां उपयोगकर्ता अपना Google खाता चुन सकता है और ज़रूरी अनुमतियां दे सकता है.
fun generateSecureRandomNonce(byteLength: Int = 32): String
: इससे generateSecureRandomNonce
नाम का फ़ंक्शन तय होता है. यह byteLength नाम का पूर्णांक आर्ग्युमेंट स्वीकार करता है. इसकी डिफ़ॉल्ट वैल्यू 32 होती है. यह बाइट में, नॉनस की लंबाई तय करता है. यह एक स्ट्रिंग दिखाता है. यह स्ट्रिंग, रैंडम बाइट का Base64-encoded वर्शन होता है.
val randomBytes = ByteArray(byteLength)
: यह फ़ंक्शन, byteLength के हिसाब से बाइट का एक ऐसा कलेक्शन बनाता है जिसमें रैंडम बाइट सेव किए जा सकते हैं.SecureRandom.getInstanceStrong().nextBytes(randomBytes)
:SecureRandom.getInstanceStrong()
: इससे क्रिप्टोग्राफ़िक तौर पर मज़बूत रैंडम नंबर जनरेटर मिलता है. सुरक्षा के लिए यह ज़रूरी है, क्योंकि इससे यह पक्का होता है कि जनरेट किए गए नंबर वाकई में रैंडम हैं और उनका अनुमान नहीं लगाया जा सकता. यह सिस्टम पर उपलब्ध एंट्रॉपी के सबसे मज़बूत सोर्स का इस्तेमाल करता है..nextBytes(randomBytes)
: इससे randomBytes ऐरे में, SecureRandom इंस्टेंस से जनरेट किए गए रैंडम बाइट भर जाते हैं.
return Base64.getUrlEncoder().withoutPadding().encodeToString(randomBytes)
:Base64.getUrlEncoder()
: इससे एक Base64 एनकोडर मिलता है, जो यूआरएल के लिए सुरक्षित वर्णमाला का इस्तेमाल करता है. इसमें + और / के बजाय - और _ का इस्तेमाल किया जाता है. यह ज़रूरी है, क्योंकि इससे यह पक्का होता है कि नतीजे के तौर पर मिली स्ट्रिंग को यूआरएल में सुरक्षित तरीके से इस्तेमाल किया जा सकता है. इसके लिए, इसे फिर से कोड में बदलने की ज़रूरत नहीं होती..withoutPadding()
: इससे Base64 एन्कोड की गई स्ट्रिंग से पैडिंग वर्ण हट जाते हैं. ऐसा इसलिए किया जाता है, ताकि नॉनस को थोड़ा छोटा और ज़्यादा कॉम्पैक्ट बनाया जा सके..encodeToString(randomBytes)
: यह फ़ंक्शन, randomBytes को Base64 स्ट्रिंग में बदलता है और उसे दिखाता है.
संक्षेप में, यह फ़ंक्शन तय की गई लंबाई का क्रिप्टोग्राफ़िक तरीके से मज़बूत रैंडम नॉन्स जनरेट करता है. इसके बाद, इसे यूआरएल के लिए सुरक्षित Base64 का इस्तेमाल करके कोड में बदलता है और नतीजे के तौर पर स्ट्रिंग दिखाता है. यह नॉनस जनरेट करने का एक स्टैंडर्ड तरीका है. इनका इस्तेमाल सुरक्षा से जुड़े मामलों में किया जा सकता है.
साइन इन करने का अनुरोध करना
अब जब हम साइन-इन करने का अनुरोध बना सकते हैं, तो हम Credential Manager का इस्तेमाल करके, साइन-इन करने के लिए इसका इस्तेमाल कर सकते हैं. इसके लिए, हमें एक ऐसा फ़ंक्शन बनाना होगा जो क्रेडेंशियल मैनेजर का इस्तेमाल करके, साइन-इन के अनुरोधों को पास करने की प्रोसेस को मैनेज करे. साथ ही, हमें सामान्य अपवादों को भी मैनेज करना होगा.
इसके लिए, इस फ़ंक्शन को BottomSheet()
फ़ंक्शन के नीचे चिपकाया जा सकता है.
//This code will not work on Android versions < UPSIDE_DOWN_CAKE when GetCredentialException is
//is thrown.
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
suspend fun signIn(request: GetCredentialRequest, context: Context): Exception? {
val credentialManager = CredentialManager.create(context)
val failureMessage = "Sign in failed!"
var e: Exception? = null
//using delay() here helps prevent NoCredentialException when the BottomSheet Flow is triggered
//on the initial running of our app
delay(250)
try {
// The getCredential is called to request a credential from Credential Manager.
val result = credentialManager.getCredential(
request = request,
context = context,
)
Log.i(TAG, result.toString())
Toast.makeText(context, "Sign in successful!", Toast.LENGTH_SHORT).show()
Log.i(TAG, "(☞゚ヮ゚)☞ Sign in Successful! ☜(゚ヮ゚☜)")
} catch (e: GetCredentialException) {
Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
Log.e(TAG, failureMessage + ": Failure getting credentials", e)
} catch (e: GoogleIdTokenParsingException) {
Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
Log.e(TAG, failureMessage + ": Issue with parsing received GoogleIdToken", e)
} catch (e: NoCredentialException) {
Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
Log.e(TAG, failureMessage + ": No credentials found", e)
return e
} catch (e: GetCredentialCustomException) {
Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
Log.e(TAG, failureMessage + ": Issue with custom credential request", e)
} catch (e: GetCredentialCancellationException) {
Toast.makeText(context, ": Sign-in cancelled", Toast.LENGTH_SHORT).show()
Log.e(TAG, failureMessage + ": Sign-in was cancelled", e)
}
return e
}
अब इस कोड के बारे में ज़्यादा जानकारी:
suspend fun signIn(request: GetCredentialRequest, context: Context): Exception?
: इससे signIn नाम का एक सस्पेंड फ़ंक्शन तय होता है. इसका मतलब है कि इसे मुख्य थ्रेड को ब्लॉक किए बिना रोका और फिर से शुरू किया जा सकता है. यह एक Exception?
दिखाता है. अगर साइन इन हो जाता है, तो यह शून्य होगा. अगर साइन इन नहीं होता है, तो यह खास अपवाद होगा.
इसमें दो पैरामीटर होते हैं:
request
: यह एकGetCredentialRequest
ऑब्जेक्ट है.इसमें उस क्रेडेंशियल के टाइप का कॉन्फ़िगरेशन होता है जिसे वापस पाना है. उदाहरण के लिए, Google आईडी).context
: सिस्टम के साथ इंटरैक्ट करने के लिए, Android Context की ज़रूरत होती है.
फ़ंक्शन के मुख्य हिस्से के लिए:
val credentialManager = CredentialManager.create(context)
: CredentialManager का एक इंस्टेंस बनाता है. यह Credential Manager API के साथ इंटरैक्ट करने के लिए मुख्य इंटरफ़ेस है. ऐप्लिकेशन, साइन इन करने की प्रोसेस इस तरह शुरू करेगा.val failureMessage = "Sign in failed!"
: यह एक स्ट्रिंग (failureMessage) तय करता है. साइन इन करने में समस्या आने पर, इस स्ट्रिंग को सूचना के तौर पर दिखाया जाता है.var e: Exception? = null
: इस लाइन में, e वैरिएबल को शुरू किया गया है. इसका इस्तेमाल प्रोसेस के दौरान होने वाली किसी भी गड़बड़ी को सेव करने के लिए किया जाता है. इसकी शुरुआत शून्य से होती है.delay(250)
: इससे 250 मिलीसेकंड की देरी होती है. यह एक संभावित समस्या को हल करने का तरीका है. इस समस्या में, ऐप्लिकेशन शुरू होने पर तुरंत NoCredentialException थ्रो किया जा सकता है. ऐसा खास तौर पर, BottomSheet फ़्लो का इस्तेमाल करते समय होता है. इससे सिस्टम को क्रेडेंशियल मैनेजर शुरू करने का समय मिल जाता है.try { ... } catch (e: Exception) { ... }
:गड़बड़ी को ठीक से हैंडल करने के लिए, try-catch ब्लॉक का इस्तेमाल किया जाता है. इससे यह पक्का होता है कि साइन-इन करने की प्रोसेस के दौरान कोई गड़बड़ी होने पर, ऐप्लिकेशन क्रैश नहीं होगा. साथ ही, वह गड़बड़ी को आसानी से ठीक कर पाएगा.val result = credentialManager.getCredential(request = request, context = context)
: यहां Credential Manager API को कॉल किया जाता है. साथ ही, क्रेडेंशियल वापस पाने की प्रोसेस शुरू की जाती है. यह अनुरोध और कॉन्टेक्स्ट को इनपुट के तौर पर लेता है. साथ ही, उपयोगकर्ता को क्रेडेंशियल चुनने के लिए यूज़र इंटरफ़ेस (यूआई) दिखाता है. अगर यह अनुरोध पूरा हो जाता है, तो आपको चुने गए क्रेडेंशियल वाला नतीजा मिलेगा. इस ऑपरेशन का नतीजा,GetCredentialResponse
,result
वैरिएबल में सेव किया जाता है.Toast.makeText(context, "Sign in successful!", Toast.LENGTH_SHORT).show()
:यह एक छोटा मैसेज दिखाता है, जिसमें बताया जाता है कि साइन इन हो गया है.Log.i(TAG, "Sign in Successful!")
: यह logcat में मज़ेदार और काम का मैसेज लॉग करता है.catch (e: GetCredentialException)
: यहGetCredentialException
टाइप के अपवादों को हैंडल करता है. यह कई खास अपवादों के लिए पैरंट क्लास है. ये अपवाद, क्रेडेंशियल फ़ेच करने की प्रोसेस के दौरान हो सकते हैं.catch (e: GoogleIdTokenParsingException)
: यह उन अपवादों को हैंडल करता है जो Google आईडी टोकन को पार्स करते समय गड़बड़ी होने पर होते हैं.catch (e: NoCredentialException)
: यहNoCredentialException
को मैनेज करता है.यह तब दिखता है, जब उपयोगकर्ता के लिए कोई क्रेडेंशियल उपलब्ध नहीं होता. उदाहरण के लिए, जब उपयोगकर्ता ने कोई क्रेडेंशियल सेव नहीं किया होता या उसके पास Google खाता नहीं होता.- खास तौर पर, यह फ़ंक्शन
e
में सेव किए गए अपवाद को दिखाता है. इससे, क्रेडेंशियल उपलब्ध न होने पर, कॉलर को खास मामले को मैनेज करने की अनुमति मिलती है.NoCredentialException
- खास तौर पर, यह फ़ंक्शन
catch (e: GetCredentialCustomException)
: यह क्रेडेंशियल प्रोवाइडर की ओर से जनरेट की गई कस्टम गड़बड़ियों को मैनेज करता है.catch (e: GetCredentialCancellationException)
: यहGetCredentialCancellationException
को मैनेज करता है. यह तब दिखता है, जब उपयोगकर्ता साइन-इन प्रोसेस को रद्द कर देता है.Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
: यह एक सूचना वाला मैसेज दिखाता है. इससे पता चलता है कि failureMessage का इस्तेमाल करके साइन इन नहीं किया जा सका.Log.e(TAG, "", e)
: यह Log.e का इस्तेमाल करके, Android logcat में अपवाद को लॉग करता है. इसका इस्तेमाल गड़बड़ियों के लिए किया जाता है. इसमें डीबग करने में मदद करने के लिए, अपवाद का स्टैकट्रेस शामिल होगा. इसमें मज़ाकिया तौर पर गुस्से वाला इमोटिकॉन भी शामिल है.
return e
: अगर कोई अपवाद पकड़ा गया है, तो फ़ंक्शन उसे दिखाता है. अगर साइन इन हो गया है, तो फ़ंक्शन शून्य दिखाता है.
संक्षेप में, यह कोड क्रेडेंशियल मैनेजर एपीआई का इस्तेमाल करके, उपयोगकर्ता के साइन-इन को मैनेज करने का तरीका बताता है. यह एसिंक्रोनस ऑपरेशन को मैनेज करता है, संभावित गड़बड़ियों को ठीक करता है, और गड़बड़ी ठीक करने के दौरान, उपयोगकर्ता को सूचनाएं और लॉग दिखाता है. साथ ही, इसमें गड़बड़ी ठीक करने के लिए कुछ मज़ेदार तरीके भी बताए गए हैं.
ऐप्लिकेशन में बॉटम शीट फ़्लो लागू करना
अब हम MainActivity
क्लास में BottomSheet फ़्लो को ट्रिगर करने के लिए, कॉल सेट अप कर सकते हैं. इसके लिए, इस कोड और Google Cloud Console से कॉपी किए गए वेब ऐप्लिकेशन क्लाइंट आईडी का इस्तेमाल करें:
class MainActivity : ComponentActivity() {
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//replace with your own web client ID from Google Cloud Console
val webClientId = "YOUR_CLIENT_ID_HERE"
setContent {
//ExampleTheme - this is derived from the name of the project not any added library
//e.g. if this project was named "Testing" it would be generated as TestingTheme
ExampleTheme {
Surface(
modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background,
) {
//This will trigger on launch
BottomSheet(webClientId)
}
}
}
}
}
अब हम अपने प्रोजेक्ट को सेव कर सकते हैं (File > Save) और उसे चला सकते हैं:
- 'चलाएं' बटन दबाएं:
- जब आपका ऐप्लिकेशन एम्युलेटर पर चलने लगे, तब आपको साइन-इन बॉटमशीट पॉप-अप दिखेगा. साइन इन
की जांच करने के लिए, जारी रखें पर क्लिक करें
- आपको एक सूचना दिखेगी, जिसमें बताया जाएगा कि साइन-इन हो गया है!
7. बटन फ़्लो
'Google से साइन इन करें' सुविधा के बटन फ़्लो की मदद से, लोग अपने मौजूदा Google खाते का इस्तेमाल करके, आपके Android ऐप्लिकेशन में आसानी से साइन अप या लॉग इन कर सकते हैं. अगर उपयोगकर्ता बॉटम शीट को खारिज करता है या साइन-इन या साइन-अप करने के लिए, सिर्फ़ अपने Google खाते का इस्तेमाल करना चाहता है, तो उसे यह बटन दिखेगा. डेवलपर के लिए इसका मतलब है कि वे आसानी से ऑनबोर्ड हो सकते हैं और उन्हें साइन-अप करने में कम परेशानी होगी.
इसे Jetpack Compose के डिफ़ॉल्ट बटन की मदद से किया जा सकता है. हालांकि, हम 'Google से साइन इन करें' सुविधा के ब्रैंडिंग दिशा-निर्देश पेज से, पहले से मंज़ूरी पा चुके ब्रैंड आइकॉन का इस्तेमाल करेंगे.
प्रोजेक्ट में ब्रैंड आइकॉन जोड़ना
- पहले से मंज़ूरी पा चुके ब्रैंड आइकॉन की ZIP फ़ाइल यहां से डाउनलोड करें
- डाउनलोड किए गए फ़ोल्डर में मौजूद signin-assest.zip फ़ाइल को अनकंप्रेस करें. यह आपके कंप्यूटर के ऑपरेटिंग सिस्टम के हिसाब से अलग-अलग हो सकती है. अब आपके पास signin-assets फ़ोल्डर खोलने और उपलब्ध आइकॉन देखने का विकल्प है. इस कोडलैब के लिए, हम
signin-assets/Android/png@2x/neutral/android_neutral_sq_SI@2x.png
का इस्तेमाल करेंगे. - फ़ाइल कॉपी करना
- Android Studio में res > drawable में जाकर, drawable फ़ोल्डर पर राइट क्लिक करें. इसके बाद, चिपकाएं पर क्लिक करके, कॉपी किए गए फ़ोल्डर को चिपकाएं. ऐसा करने के लिए, आपको res फ़ोल्डर को बड़ा करना पड़ सकता है
- आपको एक डायलॉग दिखेगा. इसमें फ़ाइल का नाम बदलने और उस डायरेक्ट्री की पुष्टि करने के लिए कहा जाएगा जिसमें फ़ाइल को जोड़ा जाएगा. ऐसेट का नाम बदलकर siwg_button.png करें. इसके बाद, ठीक है पर क्लिक करें
बटन फ़्लो कोड
यह कोड, उसी signIn()
फ़ंक्शन का इस्तेमाल करेगा जिसका इस्तेमाल BottomSheet()
के लिए किया जाता है. हालांकि, यह GetGoogleIdOption
के बजाय GetSignInWithGoogleOption
का इस्तेमाल करता है, क्योंकि यह फ़्लो साइन इन करने के विकल्प दिखाने के लिए, डिवाइस पर सेव किए गए क्रेडेंशियल और पासकी का इस्तेमाल नहीं करता है. यहां वह कोड दिया गया है जिसे BottomSheet()
फ़ंक्शन के नीचे चिपकाया जा सकता है:
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
@Composable
fun ButtonUI(webClientId: String) {
val context = LocalContext.current
val coroutineScope = rememberCoroutineScope()
val onClick: () -> Unit = {
val signInWithGoogleOption: GetSignInWithGoogleOption = GetSignInWithGoogleOption
.Builder(serverClientId = webClientId)
.setNonce(generateSecureRandomNonce())
.build()
val request: GetCredentialRequest = GetCredentialRequest.Builder()
.addCredentialOption(signInWithGoogleOption)
.build()
coroutineScope.launch {
signIn(request, context)
}
}
Image(
painter = painterResource(id = R.drawable.siwg_button),
contentDescription = "",
modifier = Modifier
.fillMaxSize()
.clickable(enabled = true, onClick = onClick)
)
}
कोड के काम करने के तरीके के बारे में ज़्यादा जानकारी पाने के लिए:
fun ButtonUI(webClientId: String)
: इससे ButtonUI
नाम के फ़ंक्शन का एलान होता है. यह webClientId
(आपके Google Cloud प्रोजेक्ट का क्लाइंट आईडी) को आर्ग्युमेंट के तौर पर स्वीकार करता है.
val context = LocalContext.current
: यह मौजूदा Android कॉन्टेक्स्ट को वापस लाता है. इसकी ज़रूरत कई कार्रवाइयों के लिए होती है. जैसे, यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट लॉन्च करना.
val coroutineScope = rememberCoroutineScope()
: यह एक कोरूटीन स्कोप बनाता है. इसका इस्तेमाल एसिंक्रोनस टास्क को मैनेज करने के लिए किया जाता है. इससे कोड को मुख्य थ्रेड को ब्लॉक किए बिना चलाने की अनुमति मिलती है. rememberCoroutineScope
() Jetpack Compose का एक कंपोज़ेबल फ़ंक्शन है. यह एक ऐसा स्कोप उपलब्ध कराता है जो कंपोज़ेबल के लाइफ़साइकल से जुड़ा होता है.
val onClick: () -> Unit = { ... }
: इससे एक ऐसा लैम्डा फ़ंक्शन बनता है जो बटन पर क्लिक करने पर काम करेगा. लैम्डा फ़ंक्शन ये काम करेगा:
val signInWithGoogleOption: GetSignInWithGoogleOption = GetSignInWithGoogleOption.Builder(serverClientId = webClientId).setNonce(generateSecureRandomNonce()).build()
: यह हिस्सा,GetSignInWithGoogleOption
ऑब्जेक्ट बनाता है. इस ऑब्जेक्ट का इस्तेमाल, "Google से साइन इन करें" प्रोसेस के लिए पैरामीटर तय करने के लिए किया जाता है. इसके लिए,webClientId
और एक नॉनस (सुरक्षा के लिए इस्तेमाल की जाने वाली रैंडम स्ट्रिंग) की ज़रूरत होती है.val request: GetCredentialRequest = GetCredentialRequest.Builder().addCredentialOption(signInWithGoogleOption).build()
: इससे एकGetCredentialRequest
ऑब्जेक्ट बनता है. इस अनुरोध का इस्तेमाल, क्रेडेंशियल मैनेजर की मदद से उपयोगकर्ता के क्रेडेंशियल पाने के लिए किया जाएगा.GetCredentialRequest
, पहले से बनाए गएGetSignInWithGoogleOption
को एक विकल्प के तौर पर जोड़ता है, ताकि "Google से साइन इन करें" क्रेडेंशियल का अनुरोध किया जा सके.
coroutineScope.launch { ... }
: यहCoroutineScope
, एसिंक्रोनस ऑपरेशंस (कोरूटीन का इस्तेमाल करके) को मैनेज करता है.signIn(request, context)
: यह पहले से तय किए गएsignIn
() फ़ंक्शन को कॉल करता है
Image(...)
: यह painterResource
का इस्तेमाल करके इमेज रेंडर करता है. यह इमेज R.drawable.siwg_button
को लोड करता है
Modifier.fillMaxSize().clickable(enabled = true, onClick = onClick)
:fillMaxSize()
: इससे इमेज, उपलब्ध जगह में फ़िट हो जाती है.clickable(enabled = true, onClick = onClick)
: इससे इमेज पर क्लिक किया जा सकता है. क्लिक करने पर, यह पहले से तय किए गए onClick लैम्डा फ़ंक्शन को लागू करता है.
संक्षेप में, यह कोड Jetpack Compose यूज़र इंटरफ़ेस (यूआई) में "Google से साइन इन करें" बटन सेट अप करता है. इस बटन पर क्लिक करने से, क्रेडेंशियल मैनेजर को लॉन्च करने के लिए क्रेडेंशियल का अनुरोध तैयार होता है. इससे उपयोगकर्ता को अपने Google खाते से साइन इन करने की अनुमति मिलती है.
अब हमें MainActivity क्लास को अपडेट करना होगा, ताकि हम ButtonUI()
फ़ंक्शन को चला सकें:
class MainActivity : ComponentActivity() {
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//replace with your own web client ID from Google Cloud Console
val webClientId = "YOUR_CLIENT_ID_HERE"
setContent {
//ExampleTheme - this is derived from the name of the project not any added library
//e.g. if this project was named "Testing" it would be generated as TestingTheme
ExampleTheme {
Surface(
modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background,
) {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
//This will trigger on launch
BottomSheet(webClientId)
//This requires the user to press the button
ButtonUI(webClientId)
}
}
}
}
}
}
अब हम अपने प्रोजेक्ट को सेव कर सकते हैं (File > Save) और उसे चला सकते हैं:
- 'चलाएं' बटन दबाएं:
- इम्यूलेटर पर ऐप्लिकेशन चलने के बाद, BottomSheet दिखना चाहिए. इसे बंद करने के लिए, इसके बाहर क्लिक करें.
- अब आपको ऐप्लिकेशन में, बनाया गया बटन दिखेगा. साइन-इन डायलॉग देखने के लिए, इस पर क्लिक करें
- साइन इन करने के लिए, अपने खाते पर क्लिक करें!
8. नतीजा
आपने यह कोडलैब पूरा कर लिया है! Android पर 'Google से साइन इन करें' सुविधा के बारे में ज़्यादा जानकारी पाने या मदद पाने के लिए, यहां अक्सर पूछे जाने वाले सवाल देखें:
अक्सर पूछे जाने वाले सवाल
- Stackoverflow
- Android क्रेडेंशियल मैनेजर से जुड़ी समस्या हल करने के लिए गाइड
- Android Credential Manager के बारे में अक्सर पूछे जाने वाले सवाल
- OAuth ऐप्लिकेशन की पुष्टि करने से जुड़े सहायता केंद्र पर जाएं
MainActivity.kt का पूरा कोड
रेफ़रंस के लिए, MainActivity.kt का पूरा कोड यहां दिया गया है:
package com.example.example
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.example.example.ui.theme.ExampleTheme
import android.content.ContentValues.TAG
import android.content.Context
import android.credentials.GetCredentialException
import android.os.Build
import android.util.Log
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.compose.foundation.clickable
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.credentials.CredentialManager
import androidx.credentials.exceptions.GetCredentialCancellationException
import androidx.credentials.exceptions.GetCredentialCustomException
import androidx.credentials.exceptions.NoCredentialException
import androidx.credentials.GetCredentialRequest
import com.google.android.libraries.identity.googleid.GetGoogleIdOption
import com.google.android.libraries.identity.googleid.GetSignInWithGoogleOption
import com.google.android.libraries.identity.googleid.GoogleIdTokenParsingException
import java.security.SecureRandom
import java.util.Base64
import kotlinx.coroutines.CoroutineScope
import androidx.compose.runtime.LaunchedEffect
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
class MainActivity : ComponentActivity() {
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//replace with your own web client ID from Google Cloud Console
val webClientId = "YOUR_CLIENT_ID_HERE"
setContent {
//ExampleTheme - this is derived from the name of the project not any added library
//e.g. if this project was named "Testing" it would be generated as TestingTheme
ExampleTheme {
Surface(
modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background,
) {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
//This will trigger on launch
BottomSheet(webClientId)
//This requires the user to press the button
ButtonUI(webClientId)
}
}
}
}
}
}
//This line is not needed for the project to build, but you will see errors if it is not present.
//This code will not work on Android versions < UpsideDownCake
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
@Composable
fun BottomSheet(webClientId: String) {
val context = LocalContext.current
// LaunchedEffect is used to run a suspend function when the composable is first launched.
LaunchedEffect(Unit) {
// Create a Google ID option with filtering by authorized accounts enabled.
val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
.setFilterByAuthorizedAccounts(true)
.setServerClientId(webClientId)
.setNonce(generateSecureRandomNonce())
.build()
// Create a credential request with the Google ID option.
val request: GetCredentialRequest = GetCredentialRequest.Builder()
.addCredentialOption(googleIdOption)
.build()
// Attempt to sign in with the created request using an authorized account
val e = signIn(request, context)
// If the sign-in fails with NoCredentialException, there are no authorized accounts.
// In this case, we attempt to sign in again with filtering disabled.
if (e is NoCredentialException) {
val googleIdOptionFalse: GetGoogleIdOption = GetGoogleIdOption.Builder()
.setFilterByAuthorizedAccounts(false)
.setServerClientId(webClientId)
.setNonce(generateSecureRandomNonce())
.build()
val requestFalse: GetCredentialRequest = GetCredentialRequest.Builder()
.addCredentialOption(googleIdOptionFalse)
.build()
signIn(requestFalse, context)
}
}
}
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
@Composable
fun ButtonUI(webClientId: String) {
val context = LocalContext.current
val coroutineScope = rememberCoroutineScope()
val onClick: () -> Unit = {
val signInWithGoogleOption: GetSignInWithGoogleOption = GetSignInWithGoogleOption
.Builder(serverClientId = webClientId)
.setNonce(generateSecureRandomNonce())
.build()
val request: GetCredentialRequest = GetCredentialRequest.Builder()
.addCredentialOption(signInWithGoogleOption)
.build()
signIn(coroutineScope, request, context)
}
Image(
painter = painterResource(id = R.drawable.siwg_button),
contentDescription = "",
modifier = Modifier
.fillMaxSize()
.clickable(enabled = true, onClick = onClick)
)
}
fun generateSecureRandomNonce(byteLength: Int = 32): String {
val randomBytes = ByteArray(byteLength)
SecureRandom.getInstanceStrong().nextBytes(randomBytes)
return Base64.getUrlEncoder().withoutPadding().encodeToString(randomBytes)
}
//This code will not work on Android versions < UPSIDE_DOWN_CAKE when GetCredentialException is
//is thrown.
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
suspend fun signIn(request: GetCredentialRequest, context: Context): Exception? {
val credentialManager = CredentialManager.create(context)
val failureMessage = "Sign in failed!"
var e: Exception? = null
//using delay() here helps prevent NoCredentialException when the BottomSheet Flow is triggered
//on the initial running of our app
delay(250)
try {
// The getCredential is called to request a credential from Credential Manager.
val result = credentialManager.getCredential(
request = request,
context = context,
)
Log.i(TAG, result.toString())
Toast.makeText(context, "Sign in successful!", Toast.LENGTH_SHORT).show()
Log.i(TAG, "(☞゚ヮ゚)☞ Sign in Successful! ☜(゚ヮ゚☜)")
} catch (e: GetCredentialException) {
Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
Log.e(TAG, failureMessage + ": Failure getting credentials", e)
} catch (e: GoogleIdTokenParsingException) {
Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
Log.e(TAG, failureMessage + ": Issue with parsing received GoogleIdToken", e)
} catch (e: NoCredentialException) {
Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
Log.e(TAG, failureMessage + ": No credentials found", e)
return e
} catch (e: GetCredentialCustomException) {
Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
Log.e(TAG, failureMessage + ": Issue with custom credential request", e)
} catch (e: GetCredentialCancellationException) {
Toast.makeText(context, ": Sign-in cancelled", Toast.LENGTH_SHORT).show()
Log.e(TAG, failureMessage + ": Sign-in was cancelled", e)
}
return e
}