۱. قبل از شروع
آموزش پیاده سازی ورود با گوگل در اندروید با استفاده از Credential Manager.
پیشنیازها
- آشنایی اولیه با کاتلین برای توسعه اندروید
- درک اولیه از Jetpack Compose ( بیشتر بدانید ).
آنچه یاد خواهید گرفت
- یک پروژه Google Cloud و کلاینتهای OAuth ایجاد کنید.
- جریان ورود به سیستم Bottom Sheet را پیادهسازی کنید.
- جریان ورود به سیستم با دکمه را به صورت صریح پیادهسازی کنید.
آنچه شما نیاز دارید
- اندروید استودیو نصب شد.
- کامپیوتری که الزامات سیستم اندروید استودیو و شبیهساز را برآورده کند.
- کیت توسعه جاوا (JDK) نصب شده است.
۲. یک پروژه اندروید استودیو ایجاد کنید
برای شروع، یک پروژه جدید در اندروید استودیو ایجاد کنید:
- اندروید استودیو را باز کنید و روی «پروژه جدید» کلیک کنید.

- تلفن و تبلت > خالی کردن فعالیت را انتخاب کنید، سپس روی بعدی کلیک کنید.

- تنظیمات پروژه را پیکربندی کنید:
- نام : یک نام برای پروژه انتخاب کنید.
- نام بسته : از پیشفرض استفاده کنید یا نام دلخواه خود را انتخاب کنید.
- حداقل SDK : جدیدترین نسخه پایدار یا > اندروید ۱۴ را انتخاب کنید.

- روی Finish کلیک کنید و منتظر بمانید تا ساخت اولیه پروژه تکمیل شود.

۳. پروژه گوگل کلود خود را راهاندازی کنید
ایجاد یک پروژه گوگل کلود
- به کنسول گوگل کلود بروید و یک پروژه انتخاب یا ایجاد کنید.

- به صفحه APIها و خدمات > رضایت OAuth بروید.

- روی شروع کلیک کنید و فیلدهای مورد نیاز را پر کنید:
- نام برنامه : از نام برنامه اندروید خود استفاده کنید.
- ایمیل پشتیبانی کاربر : حساب گوگل خود را انتخاب کنید.
- مخاطب : خارجی را انتخاب کنید.
- اطلاعات تماس : آدرس ایمیل خود را وارد کنید.

- سیاستهای مربوط به دادههای کاربر در سرویسهای API گوگل را مرور کنید و روی ایجاد کلیک کنید.

راهاندازی کلاینتهای OAuth
برای دریافت شناسههای کلاینت جهت احراز هویت، باید هم یک کلاینت وب و هم یک کلاینت اندروید در کنسول ابری گوگل ایجاد کنید.
- کلاینت اندروید : با تأیید نام بسته برنامه و امضای SHA-1، درخواستها را ایمن میکند.
- کلاینت وب : به عنوان کلاینت پشتیبان برای سرویس ورود به سیستم گوگل عمل میکند.
ایجاد کلاینت اندروید OAuth 2.0
- در صفحه کلاینتها ، روی ایجاد کلاینت کلیک کنید و اندروید را به عنوان نوع برنامه انتخاب کنید.

- نام بسته برنامه خود را وارد کنید (مطابق با خط 1 از
MainActivity.kt). - امضای SHA-1 خود را ایجاد کنید. ترمینال اندروید استودیو را باز کنید و دستور زیر را اجرا کنید: macOS/Linux:
ویندوز: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
- اثر انگشت SHA-1 را از خروجی دستور کپی کنید، آن را در فیلد اثر انگشت SHA-1 در کنسول جایگذاری کنید و روی ایجاد کلیک کنید.

ایجاد کلاینت Web OAuth 2.0
- دوباره روی ایجاد کلاینت کلیک کنید و نوع برنامه را Web Application انتخاب کنید.
- نام کلاینت وب خود را وارد کنید، فیلدهای URL/Origins را خالی بگذارید و روی Create کلیک کنید.

- شناسه کلاینت تولید شده را از پنجره تأیید کپی کنید. از این در کد کاتلین خود استفاده خواهید کرد.

۴. یک دستگاه مجازی اندروید راهاندازی کنید
برای آزمایش برنامه، میتوانید از یک دستگاه اندروید فیزیکی یا یک دستگاه مجازی اندروید (AVD) استفاده کنید.
AVD را ایجاد و اجرا کنید
- در اندروید استودیو، Device Manager را باز کنید، روی Create Virtual Device (یا آیکون + ) کلیک کنید و Medium Phone را انتخاب کنید.
- جدیدترین نسخه پایدار را به عنوان تصویر سیستم انتخاب کنید و روی Finish کلیک کنید.
- با کلیک روی آیکون Play/Run در کنار دستگاه، شبیهساز را اجرا کنید.

وارد حساب گوگل خود در دستگاه شوید
- در شبیهساز، برنامه تنظیمات (Settings ) را باز کنید و به گوگل (Google) بروید.
- روی «ورود به حساب Google خود» کلیک کنید و دستورالعملها را دنبال کنید.

۵. وابستگیها را اضافه کنید
کتابخانههای مورد نیاز برای احراز هویت و ادغام Google ID را به پروژه خود اضافه کنید:
- به مسیر فایل > ساختار پروژه > وابستگیها > برنامه بروید.
- روی + > Library Dependency کلیک کنید، عبارت
com.google.android.libraries.identity.googleid:googleidرا جستجو کنید و آخرین نسخه (مثلاً1.1.1) را انتخاب کنید. - دوباره روی + > Library Dependency کلیک کنید، عبارت
play-services-authرا جستجو کنید و کتابخانهای که شناسه گروه آنcom.google.android.gmsاست را انتخاب کنید. - برای اعمال تغییرات و همگامسازی پروژه، روی تأیید کلیک کنید.

۶. جریان برگه پایانی را پیادهسازی کنید

جریان Bottom Sheet از API مدیریت اعتبارنامه (Credential Manager API) بهره میبرد تا روشی ساده برای ورود کاربران به برنامه شما با استفاده از حسابهای گوگل خود در اندروید فراهم کند. این جریان که برای سرعت و راحتی، به ویژه برای کاربران قدیمی طراحی شده است، باید در هنگام اجرای برنامه فعال شود.
درخواست ورود را بسازید
- برای شروع،
MainActivity.ktرا باز کنید و توابع پیشفرضGreeting()وGreetingPreview()را حذف کنید. - دستورات import زیر را بعد از دستورات موجود که از خط ۳ شروع میشوند، اضافه کنید:
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" - این تابع Composable را زیر کلاس
MainActivityدر فایلMainActivity.ktخود اضافه کنید:@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): بلافاصله پس از نمایش Composable، جریان ورود به سیستم را فعال میکند. -
GetGoogleIdOption.Builder(): درخواست توکن شناسه گوگل را پیکربندی میکند.-
setFilterByAuthorizedAccounts(true): ابتدا با فیلتر کردن حسابهایی که کاربر قبلاً برای این برنامه مجاز کرده است، ورود بیصدا را امتحان میکند و دردسر را برای کاربران قدیمی به حداقل میرساند. -
setNonce(...): یک nonce تصادفی امن که برای هر درخواست توسطgenerateSecureRandomNonce()تولید میشود را برای جلوگیری از حملات بازپخش ارسال میکند.
-
-
signIn(request, context): درخواست را اجرا میکند. اگر با خطایNoCredentialException(به این معنی که هیچ حساب کاربری قبلاً مجاز وجود ندارد) شکست بخورد، جریان بهsetFilterByAuthorizedAccounts(false)برمیگردد تا به کاربر اجازه دهد از هر حساب گوگلی که در دستگاه وارد شده است، انتخاب کند.
درخواست ورود را انجام دهید
با ایجاد درخواست ورود، میتوانید از Credential Manager برای تکمیل فرآیند ورود استفاده کنید. تابعی به نام signIn ایجاد کنید که درخواست را اجرا کرده و استثنائات رایجی را که ممکن است رخ دهد، مدیریت کند.
این تابع را زیر تابع BottomSheet در فایل MainActivity.kt خود اضافه کنید:
@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(...): رابط برنامهنویسی کاربردی مدیریت اعتبار را فراخوانی میکند تا برگه یا کادر محاورهای انتخابگر حساب سیستم را نمایش دهد. -
delay(250): برای جلوگیری از ایجاد شرایط رقابتی، زمانی که Bottom Sheet بلافاصله در هنگام راهاندازی برنامه و قبل از اتمام مقداردهی اولیه سرویس Credential Manager فعال میشود، مکث کوتاهی ایجاد میکند. - مدیریت خطاها : خطاهای رایج اعتبارنامه (مثلاً لغو، فقدان اعتبارنامه یا مشکلات تجزیه توکن) را ثبت و گزارش میکند و با استفاده از Toastها به کاربر بازخورد میدهد.
جریان برگه پایانی را فعال کنید
کلاس MainActivity خود را بهروزرسانی کنید تا در هنگام راهاندازی BottomSheet() فراخوانی کند. 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 ) و برنامه را اجرا کنید:
- دکمه اجرا را فشار دهید:

- وقتی برنامه روی شبیهساز اجرا میشود، صفحه پایانی ورود باید ظاهر شود. برای آزمایش جریان، روی ادامه کلیک کنید.

- یک اعلان Toast باید ظاهر شود که تأیید میکند ورود به سیستم موفقیتآمیز بوده است.

۷. جریان دکمه را پیادهسازی کنید

جریان دکمه، گزینهای صریح برای ورود یا ثبت نام کاربران فراهم میکند. استفاده از برندسازی استاندارد، تجربهای یکپارچه را تضمین میکند. از داراییهای از پیش تأیید شدهای استفاده کنید که با دستورالعملهای برندسازی ورود با گوگل مطابقت دارند.
نماد برند را اضافه کنید
- فایلهای مربوط به برند را از اینجا دانلود کرده و فایل زیپ را استخراج کنید.
-
signin-assets/Android/png@2x/neutral/android_neutral_sq_SI@2x.pngرا کپی کنید. - در اندروید استودیو، فایل را در پوشه res > drawable خود پیست کنید، نام آن را به
siwg_button.pngتغییر دهید و روی OK کلیک کنید.
کد جریان دکمه
این جریان از همان تابع کمکی signIn استفاده مجدد میکند اما به جای GetGoogleIdOption یک GetSignInWithGoogleOption ارسال میکند. برخلاف جریان Bottom Sheet، جریان دکمه صریح، اعتبارنامهها یا کلیدهای عبور ذخیره شده را از قبل فیلتر نمیکند یا به طور خودکار درخواست نمیکند. این تابع Composable را زیر تابع 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: برخلاف جریان Bottom Sheet، جریان دکمهی صریح از این گزینه برای ترغیب کاربران به انتخاب حساب گوگل خود بدون فیلتر خودکار استفاده میکند. -
coroutineScope.launch: یک کوروتین را برای اجرای ناهمگام تابع suspendsignInهنگام کلیک روی دکمه، راهاندازی میکند. -
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)
}
}
}
}
}
}
جریان دکمه را آزمایش کنید
- اپلیکیشن را اجرا کنید.
- با کلیک کردن در خارج از ناحیهی صفحه، برگهی پایانی اولیه را غیرفعال کنید.
- برای اجرای پنجرهی ورود، روی دکمهی ورود با گوگل کلیک کنید و حساب کاربری خود را انتخاب کنید.

- نتیجه را تأیید کنید: برای تأیید چاپ نام کاربری/آدرس ایمیل خود، Logcat را بررسی کنید.
۸. نتیجهگیری
تبریک! شما با موفقیت ورود به سیستم با گوگل را با استفاده از Android Credential Manager پیادهسازی کردید.
منابع اضافی
- مستندات مدیریت اعتبارنامه اندروید
- راهنمای عیبیابی مدیریت اعتبارنامهها
- سوالات متداول مدیر اعتبارنامه
- پشتیبانی از استکاورفلو
کد کامل 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
}
}