1. Hinweis
Informationen zum Implementieren von „Über Google anmelden“ auf Android-Geräten mit dem Credential Manager
Vorbereitung
- Grundkenntnisse in Kotlin für die Android-Entwicklung
- Grundkenntnisse in Jetpack Compose (weitere Informationen).
Lerninhalte
- Google Cloud-Projekt und OAuth-Clients erstellen
- Anmeldevorgang für die Ansicht am unteren Rand implementieren
- Anmeldevorgang für die explizite Schaltfläche implementieren
Voraussetzungen
- Android Studio ist installiert.
- Ein Computer, der die Systemanforderungen für Android Studio und den Emulator erfüllt.
- Java Development Kit (JDK) ist installiert.
2. Android Studio-Projekt erstellen
Erstellen Sie zuerst ein neues Projekt in Android Studio:
- Öffnen Sie Android Studio und klicken Sie auf New Project (Neues Projekt).

- Wählen Sie Phone and Tablet > Empty Activity (Smartphone und Tablet > Leere Aktivität) aus und klicken Sie auf Next (Weiter).

- Konfigurieren Sie die Projekteinstellungen:
- Name: Wählen Sie einen Projektnamen aus.
- Package name (Paketname): Verwenden Sie den Standardnamen oder wählen Sie einen eigenen aus.
- Minimum SDK (Mindest-SDK): Wählen Sie die aktuelle stabile Version oder > Android 14 aus.

- Klicken Sie auf Finish (Fertig) und warten Sie, bis die erste Projekterstellung abgeschlossen ist.

3. Google Cloud-Projekt einrichten
Google Cloud-Projekt erstellen
- Rufen Sie die Google Cloud Console auf und wählen Sie ein Projekt aus oder erstellen Sie ein Projekt.

- Gehen Sie zu APIs & Services > OAuth-Zustimmungsbildschirm.

- Klicken Sie auf Get started (Jetzt starten) und füllen Sie die Pflichtfelder aus:
- App Name (App-Name): Verwenden Sie den Namen Ihrer Android-App.
- User Support Email (E-Mail-Adresse für den Nutzersupport): Wählen Sie Ihr Google-Konto aus.
- Audience (Zielgruppe): Wählen Sie External (Extern) aus.
- Contact Info (Kontaktinformationen): Geben Sie Ihre E-Mail-Adresse ein.

- Lesen Sie die Richtlinie zu Nutzerdaten für Google API-Dienste und klicken Sie auf Create (Erstellen).

OAuth-Clients einrichten
Sie müssen in der Google Cloud Console sowohl einen Web-Client als auch einen Android-Client erstellen, um die Client-IDs für die Authentifizierung zu erhalten.
- Android-Client: Schützt Anfragen durch Überprüfung des Paketnamens und der SHA-1-Signatur Ihrer App.
- Web-Client: Fungiert als Backend-Client für den Google-Anmeldedienst.
Android-OAuth 2.0-Client erstellen
- Klicken Sie auf der Seite Clients (Clients) auf Create Client (Client erstellen) und wählen Sie Android als Application type (Anwendungstyp) aus.

- Geben Sie den Paketnamen Ihrer App ein (entspricht Zeile 1 von
MainActivity.kt). - Generieren Sie Ihre SHA-1-Signatur. Öffnen Sie das Android Studio-Terminal und führen Sie den folgenden Befehl aus:macOS/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
- Kopieren Sie den SHA-1-Fingerabdruck aus der Befehlsausgabe, fügen Sie ihn in der Console in das Feld SHA-1 fingerprint ein und klicken Sie auf Create.

Web-OAuth 2.0-Client erstellen
- Klicken Sie noch einmal auf Create Client (Client erstellen) und wählen Sie Web Application (Webanwendung) als Application type (Anwendungstyp) aus.
- Geben Sie Ihrem Web-Client einen Namen, lassen Sie die Felder für URL/Origins leer und klicken Sie auf Create.

- Kopieren Sie die generierte Client ID (Client-ID) aus dem Bestätigungsdialogfeld. Sie verwenden sie in Ihrem Kotlin-Code.

4. Virtuelles Android-Gerät einrichten
Zum Testen der App können Sie ein physisches Android-Gerät oder ein virtuelles Android-Gerät (Android Virtual Device, AVD) verwenden.
AVD erstellen und ausführen
- Öffnen Sie in Android Studio den Device Manager (Geräteverwaltung), klicken Sie auf Create Virtual Device (Virtuelles Gerät erstellen) oder das Symbol + und wählen Sie Medium Phone (Mittelgroßes Smartphone) aus.
- Wählen Sie die aktuelle stabile Version als System-Image aus und klicken Sie auf Finish (Fertig).
- Starten Sie den Emulator, indem Sie neben dem Gerät auf das Symbol Play/Run (Wiedergabe/Ausführen) klicken.

Auf dem Gerät in einem Google-Konto anmelden
- Öffnen Sie im Emulator die App Einstellungen und gehen Sie zu Google.
- Klicken Sie auf In Ihrem Google-Konto anmelden und folgen Sie der Anleitung.

5. Abhängigkeiten hinzufügen
Fügen Sie Ihrem Projekt die für die Authentifizierung und die Google ID-Integration erforderlichen Bibliotheken hinzu:
- Gehen Sie zu File > Project Structure > Dependencies > app (Datei > Projektstruktur > Abhängigkeiten > App).
- Klicken Sie auf + > Library Dependency (+ > Bibliotheksabhängigkeit), suchen Sie nach
com.google.android.libraries.identity.googleid:googleidund wählen Sie die aktuelle Version aus (z.B.1.1.1). - Klicken Sie noch einmal auf + > Library Dependency (+ > Bibliotheksabhängigkeit), suchen Sie nach
play-services-authund wählen Sie die Bibliothek mit der Gruppen-IDcom.google.android.gmsaus. - Klicken Sie auf OK , um die Änderungen zu übernehmen und Ihr Projekt zu synchronisieren.

6. Anmeldevorgang für die Ansicht am unteren Rand implementieren

Der Anmeldevorgang für die Ansicht am unteren Rand nutzt die Credential Manager API, um Nutzern eine optimierte Möglichkeit zu bieten, sich auf Android-Geräten mit ihren Google-Konten in Ihrer App anzumelden. Dieser Vorgang ist auf Geschwindigkeit und Komfort ausgelegt, insbesondere für wiederkehrende Nutzer, und sollte beim Start der App ausgelöst werden.
Anmeldeanfrage erstellen
- Öffnen Sie zuerst
MainActivity.ktund entfernen Sie die StandardfunktionenGreeting()undGreetingPreview(). - Fügen Sie nach den vorhandenen Importanweisungen ab Zeile 3 die folgenden Importanweisungen hinzu:
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" - Fügen Sie diese Composable-Funktion unter der
MainActivityKlasse in derMainActivity.ktDatei hinzu:@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) }
Codeaufschlüsselung
LaunchedEffect(Unit): Löst den Anmeldevorgang sofort aus, wenn die Composable-Funktion zum ersten Mal angezeigt wird.GetGoogleIdOption.Builder(): Konfiguriert die Google ID-Tokenanfrage.setFilterByAuthorizedAccounts(true): Versucht zuerst eine automatische Anmeldung, indem nach Konten gefiltert wird, die der Nutzer bereits für diese App autorisiert hat. So wird die Anmeldung für wiederkehrende Nutzer vereinfacht.setNonce(...): Übergibt eine sichere zufällige Nonce, die für jede Anfrage vongenerateSecureRandomNonce()generiert wird, um Replay-Angriffe zu verhindern.
signIn(request, context): Führt die Anfrage aus. Wenn sie mit einerNoCredentialExceptionfehlschlägt (d. h., es ist kein zuvor autorisiertes Konto vorhanden), wird aufsetFilterByAuthorizedAccounts(false)zurückgegriffen, damit der Nutzer ein beliebiges Google-Konto auswählen kann, in dem er auf dem Gerät angemeldet ist.
Anmeldeanfrage senden
Nachdem Sie die Anmeldeanfrage erstellt haben, können Sie den Credential Manager verwenden, um den Anmeldevorgang abzuschließen. Erstellen Sie eine Funktion namens signIn, die die Anfrage ausführt und häufige Ausnahmen verarbeitet, die auftreten können.
Fügen Sie diese Funktion unter der Funktion BottomSheet in der Datei MainActivity.kt hinzu:
@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
}
}
Codeaufschlüsselung
credentialManager.getCredential(...): Ruft die Credential Manager API auf, um die Ansicht am unteren Rand oder das Dialogfeld zur Auswahl des Systemkontos anzuzeigen.delay(250): Hält kurz an, um eine Race-Bedingung zu verhindern, wenn die Ansicht am unteren Rand sofort beim Start der App ausgelöst wird, bevor der Credential Manager-Dienst initialisiert wurde.- Ausnahmebehandlung: Fängt häufige Anmeldedatenfehler ab und protokolliert sie (z.B. Abbruch, fehlende Anmeldedaten oder Probleme beim Parsen von Tokens) und gibt Nutzern Feedback über Toasts.
Anmeldevorgang für die Ansicht am unteren Rand auslösen
Aktualisieren Sie die Klasse MainActivity, um BottomSheet() beim Start aufzurufen. Ersetzen Sie YOUR_CLIENT_ID_HERE durch Ihre Webanwendungs-Client-ID:
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)
}
}
}
}
}
Speichern Sie Ihr Projekt (File > Save (Datei > Speichern)) und führen Sie die Anwendung aus:
- Klicken Sie auf die Schaltfläche „Ausführen“:

- Wenn die App im Emulator gestartet wird, sollte die Ansicht am unteren Rand für die Anmeldung angezeigt werden. Klicken Sie auf Continue (Weiter), um den Vorgang zu testen.

- Es sollte eine Toast-Benachrichtigung angezeigt werden, die bestätigt, dass die Anmeldung erfolgreich war.

7. Anmeldevorgang für die Schaltfläche implementieren

Der Anmeldevorgang für die Schaltfläche bietet Nutzern eine explizite Option, sich anzumelden oder zu registrieren. Die Verwendung von Standard-Branding sorgt für eine einheitliche Nutzererfahrung. Verwenden Sie vorab genehmigte Assets, die den Branding-Richtlinien für „Über Google anmelden“ entsprechen.
Markensymbol hinzufügen
- Laden Sie die Marken-Assets hier herunter und extrahieren Sie die ZIP-Datei.
- Kopieren Sie
signin-assets/Android/png@2x/neutral/android_neutral_sq_SI@2x.png. - Fügen Sie die Datei in Android Studio in den Ordner res > drawable ein, benennen Sie sie in
siwg_button.pngum und klicken Sie auf OK.
Code für den Anmeldevorgang für die Schaltfläche
Bei diesem Vorgang wird dieselbe Hilfsfunktion signIn wiederverwendet, aber anstelle von GetGoogleIdOption wird GetSignInWithGoogleOption übergeben. Im Gegensatz zum Anmeldevorgang für die Ansicht am unteren Rand werden beim Anmeldevorgang für die explizite Schaltfläche keine Vorabfilterung durchgeführt und keine gespeicherten Anmeldedaten oder Passkeys automatisch angefordert. Fügen Sie diese Composable-Funktion unter der Funktion BottomSheet ein:
@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)
)
}
Codeaufschlüsselung
GetSignInWithGoogleOption: Im Gegensatz zum Anmeldevorgang für die Ansicht am unteren Rand wird bei diesem Vorgang diese Option verwendet, um Nutzer aufzufordern, ihr Google-Konto auszuwählen, ohne automatische Filterung.coroutineScope.launch: Startet eine Coroutine, um die suspend-FunktionsignInasynchron auszuführen, wenn auf die Schaltfläche geklickt wird.Image: Zeigt das gebrandete Drawablesiwg_buttonan und fügt einen Klick-Listener hinzu, um den Vorgang auszulösen.
Schaltfläche zum UI-Layout hinzufügen
Aktualisieren Sie das Layout MainActivity, um sowohl die automatische BottomSheet als auch die explizite ButtonUI vertikal auszurichten:
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)
}
}
}
}
}
}
Anmeldevorgang für die Schaltfläche testen
- Führen Sie die Anwendung aus.
- Schließen Sie die erste Ansicht am unteren Rand, indem Sie außerhalb des Bereichs der Ansicht klicken.
- Klicken Sie auf die Schaltfläche Über Google anmelden , um das Anmeldedialogfeld zu öffnen, und wählen Sie Ihr Konto aus.

- Überprüfen Sie das Ergebnis: Sehen Sie im Logcat nach, ob Ihr Nutzername/Ihre E-Mail-Adresse ausgegeben wurde.
8. Fazit
Das wars! Sie haben „Über Google anmelden“ mit dem Android Credential Manager erfolgreich implementiert.
Zusätzliche Ressourcen
- Dokumentation zum Android Credential Manager
- Credential Manager Troubleshooting Guide
- Häufig gestellte Fragen zum Credential Manager
- Stack Overflow-Support
Vollständiger Code für MainActivity.kt
Hier ist der vollständige Code für MainActivity.kt als Referenz:
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
}
}