अपने Android ऐप्लिकेशन पर 'Google से साइन इन करें' सुविधा लागू करने का तरीका जानें

1. शुरू करने से पहले

इस कोडलैब में, Android पर Credential Manager का इस्तेमाल करके, 'Google से साइन इन करें' सुविधा को लागू करने का तरीका बताया गया है.

ज़रूरी शर्तें

  • Android डेवलपमेंट के लिए Kotlin का इस्तेमाल करने की बुनियादी जानकारी
  • Jetpack Compose की बुनियादी जानकारी (ज़्यादा जानकारी के लिए, यहां जाएं)

आपको क्या सीखने को मिलेगा

  • Google Cloud प्रोजेक्ट बनाने का तरीका
  • Google Cloud Console में OAuth क्लाइंट बनाने का तरीका
  • बॉटम शीट फ़्लो का इस्तेमाल करके, 'Google से साइन इन करें' सुविधा को लागू करने का तरीका
  • बटन फ़्लो का इस्तेमाल करके, 'Google से साइन इन करें' सुविधा को लागू करने का तरीका

आपको इन चीज़ों की ज़रूरत पड़ेगी

2. Android Studio प्रोजेक्ट बनाना

अवधि 3:00 - 5:00

शुरू करने के लिए, हमें Android Studio में एक नया प्रोजेक्ट बनाना होगा:

  1. Android Studio खोलना
  2. नया प्रोजेक्टAndroid Studio में आपका स्वागत है पर क्लिक करें
  3. फ़ोन और टैबलेट और बिना ऐक्टिविटी वालाAndroid Studio प्रोजेक्ट चुनें
  4. आगे बढ़ें पर क्लिक करें
  5. अब प्रोजेक्ट के कुछ हिस्सों को सेट अप करने का समय है:
    • नाम: यह आपके प्रोजेक्ट का नाम है
    • पैकेज का नाम: यह आपके प्रोजेक्ट के नाम के आधार पर अपने-आप भर जाएगा
    • सेव करने की जगह: यह डिफ़ॉल्ट रूप से उस फ़ोल्डर पर सेट होनी चाहिए जिसमें Android Studio आपके प्रोजेक्ट सेव करता है. इसे अपनी पसंद के हिसाब से बदला जा सकता है.
    • एसडीके का कम से कम वर्शन: यह Android एसडीके का सबसे पुराना वर्शन है, जिस पर आपका ऐप्लिकेशन काम करता है. इस कोडलैब में, हम API 36 (Baklava) का इस्तेमाल करेंगे
    Android Studio में प्रोजेक्ट सेटअप करना
  6. पूरा करें पर क्लिक करें
  7. Android Studio, प्रोजेक्ट बनाएगा और बुनियादी ऐप्लिकेशन के लिए ज़रूरी डिपेंडेंसी डाउनलोड करेगा. इसमें कुछ मिनट लग सकते हैं. ऐसा होते हुए देखने के लिए, सिर्फ़ बिल्ड आइकॉन पर क्लिक करें:Android Studio में प्रोजेक्ट बनाना
  8. यह प्रोसेस पूरी होने के बाद, Android Studio कुछ ऐसा दिखना चाहिए:Android Studio प्रोजेक्ट बनाया गया

3. Google Cloud प्रोजेक्ट सेट अप करना

Google Cloud प्रोजेक्ट बनाना

  1. Google Cloud Console पर जाएं
  2. अपना प्रोजेक्ट खोलें या नया प्रोजेक्ट बनाएंGCP में नया प्रोजेक्ट बनानाGCP create new project 2GCP create new project 3
  3. एपीआई और सेवाएंGCP के एपीआई और सेवाएं पर क्लिक करें
  4. OAuth के लिए सहमति वाली स्क्रीन पर जाएंGCP में, ऐसी स्क्रीन जहां OAuth के लिए सहमति दी जाती है
  5. जारी रखने के लिए, आपको खाते की खास जानकारी में मौजूद फ़ील्ड भरने होंगे. यह जानकारी भरने के लिए, शुरू करें पर क्लिक करें:GCP का 'शुरू करें' बटन
    • ऐप्लिकेशन का नाम: इस ऐप्लिकेशन का नाम. यह वही नाम होना चाहिए जिसका इस्तेमाल आपने Android Studio में प्रोजेक्ट बनाते समय किया था
    • उपयोगकर्ता सहायता ईमेल: इससे आपको उस Google खाते के बारे में पता चलेगा जिससे आपने लॉगिन किया है. साथ ही, आपको उन Google ग्रुप के बारे में भी पता चलेगा जिन्हें मैनेज किया जाता है
    GCP ऐप्लिकेशन की जानकारी
    • दर्शक:
      • इंटरनल ऐप्लिकेशन, सिर्फ़ आपके संगठन में इस्तेमाल किया जाता है. अगर आपके पास Google Cloud प्रोजेक्ट से जुड़ा कोई संगठन नहीं है, तो आपके पास इसे चुनने का विकल्प नहीं होगा.
      • हम बाहरी कुकी का इस्तेमाल करेंगे.
    GCP ऑडियंस
    • संपर्क जानकारी: इसमें वह ईमेल पता शामिल किया जा सकता है जिसका इस्तेमाल ऐप्लिकेशन से जुड़ी जानकारी पाने के लिए किया जाएगा
    GCP की संपर्क जानकारी
    • Google API सेवाएं: उपयोगकर्ता के डेटा की नीति पढ़ें.
  6. उपयोगकर्ता के डेटा से जुड़ी नीति को पढ़ने और उससे सहमत होने के बाद, बनाएंGCP Create

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 सेवाओं को ऐक्सेस कर सकता है."

वेब क्लाइंट के लिए, हमें सिर्फ़ वह नाम चाहिए जिसका इस्तेमाल आपको कंसोल में क्लाइंट की पहचान करने के लिए करना है.

Android OAuth 2.0 क्लाइंट बनाना

  1. क्लाइंट पेज पर जाएंGCP क्लाइंट
  2. क्लाइंट बनाएंGCP Create Clients पर क्लिक करें
  3. ऐप्लिकेशन टाइप के लिए, Android चुनें
  4. आपको अपने ऐप्लिकेशन का पैकेज नाम
  5. Android Studio से हमें अपने ऐप्लिकेशन का SHA-1 सिग्नेचर पाना होगा. इसके बाद, उसे यहां कॉपी/चिपकाना होगा:
    1. Android Studio पर जाएं और टर्मिनल खोलें
    2. यह कमांड चलाएं: Mac/Linux:
      keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android
      
      Windows पर:
        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: इससे, तय किए गए एलियास की निजी कुंजी का पासवर्ड मिलता है.
    3. SHA-1 हस्ताक्षर की वैल्यू कॉपी करें:
    SHA Signature
    1. Google Cloud विंडो पर वापस जाएं और SHA-1 हस्ताक्षर की वैल्यू चिपकाएं:
  6. अब आपकी स्क्रीन ऐसी दिखनी चाहिए. इसके बाद, बनाएं पर क्लिक करें:Android क्लाइंट की जानकारीAndroid क्लाइंट

वेब OAuth 2.0 क्लाइंट बनाना

  1. वेब ऐप्लिकेशन क्लाइंट आईडी बनाने के लिए, Android क्लाइंट बनाएं सेक्शन में दिए गए पहले दो चरणों को दोहराएं. इसके बाद, ऐप्लिकेशन टाइप के लिए वेब ऐप्लिकेशन चुनें
  2. क्लाइंट को एक नाम दें (यह OAuth क्लाइंट होगा): वेब क्लाइंट की जानकारी
  3. बनाएंवेब क्लाइंट पर क्लिक करें
  4. पॉप-अप विंडो से क्लाइंट आईडी कॉपी करें. आपको इसकी ज़रूरत बाद में पड़ेगीClient ID कॉपी करें

अब हमारे OAuth क्लाइंट सेट अप हो गए हैं. इसलिए, हम Android Studio पर वापस जाकर, 'Google से साइन इन करें' सुविधा वाला Android ऐप्लिकेशन बना सकते हैं!

4. Android वर्चुअल डिवाइस सेट अप करना

अगर आपको किसी फ़िज़िकल Android डिवाइस के बिना अपने ऐप्लिकेशन की तुरंत जांच करनी है, तो आपको एक Android वर्चुअल डिवाइस बनाना होगा. इस डिवाइस पर, Android Studio से ऐप्लिकेशन बनाया जा सकता है और उसे तुरंत चलाया जा सकता है. अगर आपको किसी Android डिवाइस पर टेस्ट करना है, तो Android डेवलपर दस्तावेज़ में दिए गए निर्देशों का पालन करें

Android वर्चुअल डिवाइस बनाना

  1. Android Studio में, डिवाइस मैनेजरडिवाइस मैनेजर खोलें
  2. प्लस बटन > वर्चुअल डिवाइस बनाएं पर क्लिक करेंवर्चुअल डिवाइस बनाएं
  3. यहाँ से, अपने प्रोजेक्ट के लिए ज़रूरी कोई भी डिवाइस जोड़ा जा सकता है. इस कोडलैब के लिए, मीडियम फ़ोन चुनें. इसके बाद, आगे बढ़ें पर क्लिक करेंमीडियम फ़ोन
  4. अब अपने प्रोजेक्ट के लिए डिवाइस को कॉन्फ़िगर किया जा सकता है. इसके लिए, डिवाइस को कोई यूनीक नाम दें और Android का वह वर्शन चुनें जिस पर डिवाइस चलेगा. इसके अलावा, और भी काम किए जा सकते हैं. पक्का करें कि एपीआई को एपीआई 36 "बक्लावा"; Android 16 पर सेट किया गया हो. इसके बाद, पूरा करें पर क्लिक करेंवर्चुअल डिवाइस कॉन्फ़िगर करना
  5. आपको डिवाइस मैनेजर में नया डिवाइस दिखना चाहिए. यह पुष्टि करने के लिए कि डिवाइस काम कर रहा है, डिवाइस को चलाएं उस डिवाइस के बगल में मौजूद डिवाइस 2 पर चल रहा है पर क्लिक करें जिसे आपने अभी बनाया है
  6. अब डिवाइस चालू हो जाना चाहिए!डिवाइस पर चल रहा है

Android Virtual Device में साइन इन करना

आपने अभी जो डिवाइस बनाया है वह काम करता है. अब 'Google से साइन इन करें' सुविधा की जांच करते समय गड़बड़ियों को रोकने के लिए, हमें डिवाइस में Google खाते से साइन इन करना होगा.

  1. सेटिंग पर जाएं:
    1. वर्चुअल डिवाइस की स्क्रीन के बीच में क्लिक करें और ऊपर की ओर स्वाइप करें
    क्लिक करके स्वाइप करें
    1. Settings ऐप्लिकेशन ढूंढें और उस पर क्लिक करें
    सेटिंग ऐप्लिकेशन
  2. सेटिंगGoogle की सेवाएं और प्राथमिकताएं में जाकर, Google पर क्लिक करें
  3. साइन इन करें पर क्लिक करें और अपने Google खाते में साइन इन करने के लिए, दिए गए निर्देशों का पालन करेंडिवाइस पर साइन इन करना
  1. अब आपको डिवाइसडिवाइस में साइन इन किया गया पर साइन इन करना चाहिए

आपका वर्चुअल Android डिवाइस अब टेस्टिंग के लिए तैयार है!

5. डिपेंडेंसी जोड़ें

अवधि 5:00

OAuth API कॉल करने के लिए, हमें पहले ज़रूरी लाइब्रेरी को इंटिग्रेट करना होगा. इससे हमें पुष्टि करने के अनुरोध करने और उन अनुरोधों को करने के लिए Google आईडी का इस्तेमाल करने की अनुमति मिलती है:

  • libs.googleid
  • libs.play.services.auth
  1. फ़ाइल > प्रोजेक्ट स्ट्रक्चर:प्रोजेक्ट का स्ट्रक्चर पर जाएं
  2. इसके बाद, Dependencies > app > '+' > Library Dependencyडिपेंडेंसी पर जाएं
  3. अब हमें अपनी लाइब्रेरी जोड़नी होंगी:
    1. खोज डायलॉग में, googleid टाइप करें और खोजें पर क्लिक करें
    2. सिर्फ़ एक एंट्री होनी चाहिए. इसे चुनें और उपलब्ध सबसे नया वर्शन चुनें. (इस Codelab के समय, यह 1.1.1 है)
    3. ठीक हैGoogle ID Package पर क्लिक करें
    4. पहले से तीसरे चरण को दोहराएं. हालांकि, इस बार "play-services-auth" खोजें. इसके बाद, "com.google.android.gms" वाले ग्रुप आईडी और "play-services-auth" वाले आर्टफ़ैक्ट के नाम वाली लाइन चुनेंPlay Services Auth
  4. ठीक हैडिपेंडेंसी पूरी हो गई पर क्लिक करें

6. बॉटम शीट फ़्लो

बॉटम शीट फ़्लो

बॉटम शीट फ़्लो, Credential Manager API का इस्तेमाल करता है. इससे लोग, Android डिवाइस पर अपने Google खातों से आपके ऐप्लिकेशन में आसानी से साइन इन कर पाते हैं. इसे खास तौर पर, लौटने वाले उपयोगकर्ताओं के लिए, जल्दी और आसानी से इस्तेमाल करने के लिए डिज़ाइन किया गया है. यह फ़्लो, ऐप्लिकेशन लॉन्च होने पर ट्रिगर होना चाहिए.

साइन-इन करने का अनुरोध बनाना

  1. शुरू करने के लिए, MainActivity.kt से Greeting() और GreetingPreview() फ़ंक्शन हटा दें. हमें इनकी ज़रूरत नहीं होगी.
  2. अब हमें यह पक्का करना होगा कि इस प्रोजेक्ट के लिए ज़रूरी पैकेज इंपोर्ट किए गए हों. यहां दिए गए 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
    
  3. इसके बाद, हमें बॉटम शीट के अनुरोध को बनाने के लिए अपना फ़ंक्शन बनाना होगा. इस कोड को 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) और उसे चला सकते हैं:

  1. 'चलाएं' बटन दबाएं:प्रोजेक्ट चलाना
  2. जब आपका ऐप्लिकेशन एम्युलेटर पर चलने लगे, तब आपको साइन-इन बॉटमशीट पॉप-अप दिखेगा. साइन इनबॉटम शीट की जांच करने के लिए, जारी रखें पर क्लिक करें
  3. आपको एक सूचना दिखेगी, जिसमें बताया जाएगा कि साइन-इन हो गया है!बॉटम शीट में कार्रवाई पूरी होने पर दिखने वाला मैसेज

7. बटन फ़्लो

बटन फ़्लो का GIF

'Google से साइन इन करें' सुविधा के बटन फ़्लो की मदद से, लोग अपने मौजूदा Google खाते का इस्तेमाल करके, आपके Android ऐप्लिकेशन में आसानी से साइन अप या लॉग इन कर सकते हैं. अगर उपयोगकर्ता बॉटम शीट को खारिज करता है या साइन-इन या साइन-अप करने के लिए, सिर्फ़ अपने Google खाते का इस्तेमाल करना चाहता है, तो उसे यह बटन दिखेगा. डेवलपर के लिए इसका मतलब है कि वे आसानी से ऑनबोर्ड हो सकते हैं और उन्हें साइन-अप करने में कम परेशानी होगी.

इसे Jetpack Compose के डिफ़ॉल्ट बटन की मदद से किया जा सकता है. हालांकि, हम 'Google से साइन इन करें' सुविधा के ब्रैंडिंग दिशा-निर्देश पेज से, पहले से मंज़ूरी पा चुके ब्रैंड आइकॉन का इस्तेमाल करेंगे.

प्रोजेक्ट में ब्रैंड आइकॉन जोड़ना

  1. पहले से मंज़ूरी पा चुके ब्रैंड आइकॉन की ZIP फ़ाइल यहां से डाउनलोड करें
  2. डाउनलोड किए गए फ़ोल्डर में मौजूद signin-assest.zip फ़ाइल को अनकंप्रेस करें. यह आपके कंप्यूटर के ऑपरेटिंग सिस्टम के हिसाब से अलग-अलग हो सकती है. अब आपके पास signin-assets फ़ोल्डर खोलने और उपलब्ध आइकॉन देखने का विकल्प है. इस कोडलैब के लिए, हम signin-assets/Android/png@2x/neutral/android_neutral_sq_SI@2x.png का इस्तेमाल करेंगे.
  3. फ़ाइल कॉपी करना
  4. Android Studio में res > drawable में जाकर, drawable फ़ोल्डर पर राइट क्लिक करें. इसके बाद, चिपकाएं पर क्लिक करके, कॉपी किए गए फ़ोल्डर को चिपकाएं. ऐसा करने के लिए, आपको res फ़ोल्डर को बड़ा करना पड़ सकता हैड्रॉएबल
  5. आपको एक डायलॉग दिखेगा. इसमें फ़ाइल का नाम बदलने और उस डायरेक्ट्री की पुष्टि करने के लिए कहा जाएगा जिसमें फ़ाइल को जोड़ा जाएगा. ऐसेट का नाम बदलकर 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) और उसे चला सकते हैं:

  1. 'चलाएं' बटन दबाएं:प्रोजेक्ट चलाना
  2. इम्यूलेटर पर ऐप्लिकेशन चलने के बाद, BottomSheet दिखना चाहिए. इसे बंद करने के लिए, इसके बाहर क्लिक करें.यहां टैप करें
  3. अब आपको ऐप्लिकेशन में, बनाया गया बटन दिखेगा. साइन-इन डायलॉग देखने के लिए, इस पर क्लिक करेंसाइन इन करने का डायलॉग बॉक्स
  4. साइन इन करने के लिए, अपने खाते पर क्लिक करें!

8. नतीजा

आपने यह कोडलैब पूरा कर लिया है! Android पर 'Google से साइन इन करें' सुविधा के बारे में ज़्यादा जानकारी पाने या मदद पाने के लिए, यहां अक्सर पूछे जाने वाले सवाल देखें:

अक्सर पूछे जाने वाले सवाल

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
}