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

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

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

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

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

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

  • Google Cloud प्रोजेक्ट और OAuth क्लाइंट बनाएं.
  • साइन इन करने के लिए, खातों की सूची वाला फ़्लो लागू करें.
  • बटन के ज़रिए साइन इन करने की सुविधा लागू करें.

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

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

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

  1. Android Studio खोलें और नया प्रोजेक्ट पर क्लिक करें. Android Studio में आपका स्वागत है
  2. फ़ोन और टैबलेट > Empty Activity चुनें. इसके बाद, आगे बढ़ें पर क्लिक करें. Android Studio प्रोजेक्ट
  3. प्रोजेक्ट सेटिंग कॉन्फ़िगर करें:
    • नाम: प्रोजेक्ट का नाम चुनें.
    • पैकेज का नाम: डिफ़ॉल्ट नाम का इस्तेमाल करें या अपना नाम चुनें.
    • SDK टूल का कम से कम वर्शन: सबसे नया स्टेबल वर्शन या > Android 14 चुनें.

Android Studio में प्रोजेक्ट सेटअप करना

  1. हो गया पर क्लिक करें और प्रोजेक्ट के शुरुआती बिल्ड के पूरा होने का इंतज़ार करें. Android Studio प्रोजेक्ट बनाया गया

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

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

  1. Google Cloud Console पर जाएं और कोई प्रोजेक्ट चुनें या बनाएं. GCP में नया प्रोजेक्ट बनाना
  2. एपीआई और सेवाएं > OAuth के लिए सहमति वाली स्क्रीन पर जाएं. GCP OAuth के लिए सहमति वाली स्क्रीन
  3. शुरू करें पर क्लिक करें और ज़रूरी फ़ील्ड में जानकारी भरें:
    • ऐप्लिकेशन का नाम: अपने Android ऐप्लिकेशन का नाम इस्तेमाल करें.
    • उपयोगकर्ता सहायता ईमेल: अपना Google खाता चुनें.
    • दर्शक: बाहरी चुनें.
    • संपर्क जानकारी: अपना ईमेल पता डालें. GCP ऐप्लिकेशन की जानकारी
  4. Google API सेवाएं: उपयोगकर्ता के डेटा से जुड़ी नीति पढ़ें और बनाएं पर क्लिक करें. GCP Create

OAuth क्लाइंट सेट अप करना

पुष्टि के लिए क्लाइंट आईडी पाने के लिए, आपको Google Cloud Console में वेब क्लाइंट और Android क्लाइंट, दोनों बनाने होंगे.

  • Android क्लाइंट: यह आपके ऐप्लिकेशन के पैकेज के नाम और SHA-1 हस्ताक्षर की पुष्टि करके अनुरोधों को सुरक्षित करता है.
  • वेब क्लाइंट: यह Google Sign-in सेवा के लिए बैकएंड क्लाइंट के तौर पर काम करता है.

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

  1. क्लाइंट पेज पर, क्लाइंट बनाएं पर क्लिक करें. इसके बाद, ऐप्लिकेशन टाइप के तौर पर Android चुनें. GCP Create Clients
  2. अपने ऐप्लिकेशन के पैकेज का नाम डालें. यह नाम, MainActivity.kt की पहली लाइन से मेल खाना चाहिए.
  3. अपना SHA-1 हस्ताक्षर जनरेट करें. Android Studio टर्मिनल खोलें और यह कमांड चलाएं:macOS/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
    
  4. कमांड के आउटपुट से SHA-1 फ़िंगरप्रिंट कॉपी करें. इसके बाद, उसे कंसोल में SHA-1 फ़िंगरप्रिंट फ़ील्ड में चिपकाएं और बनाएं पर क्लिक करें. Android क्लाइंट की जानकारी

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

  1. क्लाइंट बनाएं पर फिर से क्लिक करें. इसके बाद, ऐप्लिकेशन टाइप के तौर पर वेब ऐप्लिकेशन चुनें.
  2. अपने वेब क्लाइंट का नाम डालें. यूआरएल/ओरिजन फ़ील्ड को खाली छोड़ दें. इसके बाद, बनाएं पर क्लिक करें. वेब क्लाइंट की जानकारी
  3. पुष्टि करने वाले डायलॉग बॉक्स से, जनरेट किया गया Client-ID कॉपी करें. इसका इस्तेमाल अपने Kotlin कोड में करें. Client ID कॉपी करें

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

ऐप्लिकेशन की जांच करने के लिए, किसी फ़िज़िकल Android डिवाइस या Android वर्चुअल डिवाइस (AVD) का इस्तेमाल किया जा सकता है.

AVD बनाना और उसे चलाना

  1. Android Studio में, डिवाइस मैनेजर खोलें. इसके बाद, वर्चुअल डिवाइस बनाएं या + आइकॉन पर क्लिक करें. इसके बाद, मीडियम फ़ोन चुनें.
  2. सिस्टम इमेज के तौर पर सबसे नया स्टेबल वर्शन चुनें. इसके बाद, हो गया पर क्लिक करें.
  3. डिवाइस के बगल में मौजूद, चलाएं/रन करें आइकॉन पर क्लिक करके, एम्युलेटर लॉन्च करें. डिवाइस चल रहा है

डिवाइस पर किसी Google खाते में साइन इन करना

  1. एम्युलेटर पर, सेटिंग ऐप्लिकेशन खोलें और Google पर जाएं.
  2. अपने Google खाते में साइन इन करें पर क्लिक करें और निर्देशों का पालन करें. डिवाइस में साइन इन किया गया

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

अपने प्रोजेक्ट में, पुष्टि करने और Google आईडी इंटिग्रेशन के लिए ज़रूरी लाइब्रेरी जोड़ें:

  1. फ़ाइल > प्रोजेक्ट स्ट्रक्चर > डिपेंडेंसी > ऐप्लिकेशन पर जाएं.
  2. + > लाइब्रेरी डिपेंडेंसी पर क्लिक करें. इसके बाद, com.google.android.libraries.identity.googleid:googleid खोजें और नया वर्शन (जैसे, 1.1.1) चुनें.
  3. + > लाइब्रेरी डिपेंडेंसी पर फिर से क्लिक करें. इसके बाद, play-services-auth खोजें और ग्रुप आईडी com.google.android.gms वाली लाइब्रेरी चुनें.
  4. बदलाव लागू करने और अपने प्रोजेक्ट को सिंक करने के लिए, ठीक है पर क्लिक करें. डिपेंडेंसी पूरी हो गई

6. बॉटम शीट फ़्लो लागू करना

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

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

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

  1. शुरू करने के लिए, MainActivity.kt खोलें और डिफ़ॉल्ट Greeting() और GreetingPreview() फ़ंक्शन हटाएं.
  2. लाइन 3 से शुरू होने वाले मौजूदा इंपोर्ट स्टेटमेंट के बाद, ये इंपोर्ट स्टेटमेंट जोड़ें:
    import android.content.Context
    import android.os.Build
    import android.util.Log
    import android.widget.Toast
    import androidx.annotation.RequiresApi
    import androidx.compose.foundation.Image
    import androidx.compose.foundation.clickable
    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.Composable
    import androidx.compose.runtime.LaunchedEffect
    import androidx.compose.runtime.rememberCoroutineScope
    import androidx.compose.ui.Alignment
    import androidx.compose.ui.Modifier
    import androidx.compose.ui.platform.LocalContext
    import androidx.compose.ui.res.painterResource
    import androidx.credentials.CredentialManager
    import androidx.credentials.CustomCredential
    import androidx.credentials.GetCredentialRequest
    import androidx.credentials.exceptions.GetCredentialCancellationException
    import androidx.credentials.exceptions.GetCredentialCustomException
    import androidx.credentials.exceptions.GetCredentialException
    import androidx.credentials.exceptions.NoCredentialException
    import com.google.android.libraries.identity.googleid.GetGoogleIdOption
    import com.google.android.libraries.identity.googleid.GetSignInWithGoogleOption
    import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential
    import com.google.android.libraries.identity.googleid.GoogleIdTokenParsingException
    import java.security.SecureRandom
    import java.util.Base64
    import kotlinx.coroutines.delay
    import kotlinx.coroutines.launch
    
    const val TAG = "MainActivity"
    
  3. अपनी MainActivity.kt फ़ाइल में, MainActivity क्लास के नीचे यह कंपोज़ेबल फ़ंक्शन जोड़ें:
     @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)
     }
    

कोड ब्रेकडाउन

  • LaunchedEffect(Unit): इस विकल्प को चुनने पर, कंपोज़ेबल पहली बार दिखने पर ही साइन-इन करने की प्रोसेस शुरू हो जाती है.
  • GetGoogleIdOption.Builder(): यह Google आईडी टोकन के अनुरोध को कॉन्फ़िगर करता है.
    • setFilterByAuthorizedAccounts(true): यह सबसे पहले साइलेंट साइन-इन की कोशिश करता है. इसके लिए, यह उन खातों को फ़िल्टर करता है जिनके लिए उपयोगकर्ता ने पहले ही इस ऐप्लिकेशन को अनुमति दी है. इससे, बार-बार आने वाले उपयोगकर्ताओं को कम परेशानी होती है.
    • setNonce(...): यह कुकी, generateSecureRandomNonce() के हर अनुरोध के लिए जनरेट किया गया एक सुरक्षित रैंडम नॉनस पास करती है, ताकि रीप्ले अटैक को रोका जा सके.
  • signIn(request, context): अनुरोध को पूरा करता है. अगर यह NoCredentialException के साथ काम नहीं करता है, तो इसका मतलब है कि पहले से कोई भी खाता अधिकृत नहीं है. ऐसे में, फ़्लो setFilterByAuthorizedAccounts(false) पर वापस चला जाता है, ताकि उपयोगकर्ता डिवाइस पर साइन इन किए गए किसी भी Google खाते को चुन सके.

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

साइन-इन करने का अनुरोध तैयार होने के बाद, साइन-इन करने की प्रोसेस पूरी करने के लिए, Credential Manager का इस्तेमाल किया जा सकता है. signIn नाम का एक फ़ंक्शन बनाएं. यह फ़ंक्शन अनुरोध को पूरा करता है और आम तौर पर होने वाली गड़बड़ियों को ठीक करता है.

अपनी MainActivity.kt फ़ाइल में, BottomSheet फ़ंक्शन के नीचे यह फ़ंक्शन जोड़ें:

@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!"
    //using delay() here helps prevent NoCredentialException when the BottomSheet Flow is triggered
    //on the initial running of our app
    delay(250)
    return 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())

        val credential = result.credential
        if (credential is CustomCredential &&
            credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) {
            val googleIdTokenCredential = GoogleIdTokenCredential.createFrom(credential.data)
            Log.i(TAG, "Signed in as: ${googleIdTokenCredential.id}")
        }

        Toast.makeText(context, "Sign in successful!", Toast.LENGTH_SHORT).show()
        Log.i(TAG, "(☞゚ヮ゚)☞  Sign in Successful!  ☜(゚ヮ゚☜)")
        null
    } catch (e: GoogleIdTokenParsingException) {
        Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
        Log.e(TAG, failureMessage + ": Issue with parsing received GoogleIdToken", e)
        e
    } catch (e: NoCredentialException) {
        Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
        Log.e(TAG, failureMessage + ": No credentials found", e)
        e
    } catch (e: GetCredentialCancellationException) {
        Toast.makeText(context, "Sign-in cancelled", Toast.LENGTH_SHORT).show()
        Log.e(TAG, failureMessage + ": Sign-in was cancelled", e)
        e
    } catch (e: GetCredentialCustomException) {
        Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
        Log.e(TAG, failureMessage + ": Issue with custom credential request", e)
        e
    } catch (e: GetCredentialException) {
        Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
        Log.e(TAG, failureMessage + ": Failure getting credentials", e)
        e
    }
}

कोड ब्रेकडाउन

  • credentialManager.getCredential(...): यह Credential Manager API को कॉल करता है, ताकि सिस्टम खाता चुनने वाले बॉटम शीट या डायलॉग को दिखाया जा सके.
  • delay(250): यह कुछ समय के लिए रुक जाता है, ताकि क्रेडेंशियल मैनेजर सेवा के शुरू होने से पहले ही ऐप्लिकेशन के शुरू होने पर बॉटम शीट ट्रिगर होने की स्थिति को रोका जा सके.
  • अपवाद हैंडलिंग: यह सामान्य क्रेडेंशियल से जुड़ी गड़बड़ियों (जैसे, रद्द करना, क्रेडेंशियल मौजूद न होना या टोकन पार्स करने से जुड़ी समस्याएं) का पता लगाता है और उन्हें लॉग करता है. साथ ही, सूचनाओं का इस्तेमाल करके उपयोगकर्ता को सुझाव देता है.

बॉटम शीट फ़्लो को ट्रिगर करना

स्टार्टअप पर BottomSheet() को कॉल करने के लिए, अपनी MainActivity क्लास को अपडेट करें. YOUR_CLIENT_ID_HERE की जगह अपना वेब ऐप्लिकेशन क्लाइंट आईडी डालें:

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 से साइन इन करें' सुविधा के ब्रैंडिंग दिशा-निर्देशों के मुताबिक हों.

ब्रैंड का आइकॉन जोड़ना

  1. ब्रैंड ऐसेट को यहां से डाउनलोड करें और ZIP फ़ाइल को अनज़िप करें.
  2. signin-assets/Android/png@2x/neutral/android_neutral_sq_SI@2x.png कॉपी करें.
  3. Android Studio में, फ़ाइल को res > drawable फ़ोल्डर में चिपकाएं. इसके बाद, उसका नाम बदलकर siwg_button.png करें और OK पर क्लिक करें. बटन जोड़ना

बटन फ़्लो कोड

यह फ़्लो, signIn हेल्पर फ़ंक्शन का फिर से इस्तेमाल करता है. हालांकि, यह 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)
    )
}

कोड ब्रेकडाउन

  • GetSignInWithGoogleOption: बॉटम शीट फ़्लो के उलट, बटन फ़्लो में इस विकल्प का इस्तेमाल किया जाता है. इससे उपयोगकर्ताओं को अपने Google खाते को चुनने के लिए कहा जाता है. इसमें खातों को अपने-आप फ़िल्टर नहीं किया जाता.
  • coroutineScope.launch: यह बटन पर क्लिक करने पर, एसिंक्रोनस तरीके से सस्पेंड signIn फ़ंक्शन को एक्ज़ीक्यूट करने के लिए, एक कोरूटीन लॉन्च करता है.
  • Image: ब्रैंड किए गए siwg_button ड्रॉएबल को दिखाता है. साथ ही, फ़्लो को ट्रिगर करने के लिए क्लिक लिसनर अटैच करता है.

बटन को यूज़र इंटरफ़ेस (यूआई) लेआउट में जोड़ना

अपने MainActivity लेआउट को अपडेट करें, ताकि वर्टिकल अलाइनमेंट में ऑटोमैटिक BottomSheet और साफ़ तौर पर बताए गए 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)
                    }
                }
            }
        }
    }
}

बटन फ़्लो की जांच करना

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

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.util.Log
import android.widget.Toast
import androidx.credentials.exceptions.GetCredentialException
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)
                    }
                }
            }
        }
    }
}

@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()

        coroutineScope.launch {
            signIn(request, context)
        }
    }
    Image(
        painter = painterResource(id = R.drawable.siwg_button),
        contentDescription = "",
        modifier = Modifier
            .fillMaxSize()
            .clickable(onClick = onClick)
    )
}

fun generateSecureRandomNonce(byteLength: Int = 32): String {
    val randomBytes = ByteArray(byteLength)
    SecureRandom.getInstanceStrong().nextBytes(randomBytes)
    return Base64.getUrlEncoder().withoutPadding().encodeToString(randomBytes)
}

@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!"
    //using delay() here helps prevent NoCredentialException when the BottomSheet Flow is triggered
    //on the initial running of our app
    delay(250)
    return 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())

        val credential = result.credential
        if (credential is CustomCredential &&
            credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) {
            val googleIdTokenCredential = GoogleIdTokenCredential.createFrom(credential.data)
            Log.i(TAG, "Signed in as: ${googleIdTokenCredential.id}")
        }

        Toast.makeText(context, "Sign in successful!", Toast.LENGTH_SHORT).show()
        Log.i(TAG, "(☞゚ヮ゚)☞  Sign in Successful!  ☜(゚ヮ゚☜)")
        null
    } catch (e: GoogleIdTokenParsingException) {
        Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
        Log.e(TAG, failureMessage + ": Issue with parsing received GoogleIdToken", e)
        e
    } catch (e: NoCredentialException) {
        Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
        Log.e(TAG, failureMessage + ": No credentials found", e)
        e
    } catch (e: GetCredentialCancellationException) {
        Toast.makeText(context, "Sign-in cancelled", Toast.LENGTH_SHORT).show()
        Log.e(TAG, failureMessage + ": Sign-in was cancelled", e)
        e
    } catch (e: GetCredentialCustomException) {
        Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
        Log.e(TAG, failureMessage + ": Issue with custom credential request", e)
        e
    } catch (e: GetCredentialException) {
        Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
        Log.e(TAG, failureMessage + ": Failure getting credentials", e)
        e
    }
}