১. শুরু করার আগে
ক্রেডেনশিয়াল ম্যানেজার ব্যবহার করে অ্যান্ড্রয়েডে ‘সাইন ইন উইথ গুগল’ কীভাবে প্রয়োগ করতে হয় তা শিখুন।
পূর্বশর্ত
- অ্যান্ড্রয়েড ডেভেলপমেন্টের জন্য কোটলিন সম্পর্কে প্রাথমিক ধারণা।
- জেটপ্যাক কম্পোজ সম্পর্কে প্রাথমিক ধারণা ( আরও জানুন )।
আপনি যা শিখবেন
- একটি গুগল ক্লাউড প্রজেক্ট এবং OAuth ক্লায়েন্ট তৈরি করুন।
- বটম শীট সাইন-ইন প্রক্রিয়াটি বাস্তবায়ন করুন।
- সুস্পষ্ট বাটন সাইন-ইন প্রবাহ বাস্তবায়ন করুন।
আপনার যা প্রয়োজন
- অ্যান্ড্রয়েড স্টুডিও ইনস্টল করা হয়েছে।
- একটি কম্পিউটার যা অ্যান্ড্রয়েড স্টুডিও এবং এমুলেটরের সিস্টেমের প্রয়োজনীয়তা পূরণ করে।
- জাভা ডেভেলপমেন্ট কিট (JDK) ইনস্টল করা হয়েছে।
২. একটি অ্যান্ড্রয়েড স্টুডিও প্রজেক্ট তৈরি করুন।
শুরু করার জন্য, অ্যান্ড্রয়েড স্টুডিওতে একটি নতুন প্রজেক্ট তৈরি করুন:
- অ্যান্ড্রয়েড স্টুডিও খুলুন এবং নতুন প্রজেক্ট-এ ক্লিক করুন।

- ফোন ও ট্যাবলেট > খালি কার্যকলাপ নির্বাচন করুন, তারপর পরবর্তী ক্লিক করুন।

- প্রকল্পের সেটিংস কনফিগার করুন:
- নাম : প্রকল্পের একটি নাম নির্বাচন করুন।
- প্যাকেজের নাম : ডিফল্টটি ব্যবহার করুন অথবা আপনার নিজের পছন্দমতো বেছে নিন।
- ন্যূনতম SDK : সর্বশেষ স্থিতিশীল সংস্করণ অথবা Android 14 নির্বাচন করুন।

- ফিনিশ-এ ক্লিক করুন এবং প্রাথমিক প্রজেক্ট বিল্ড সম্পূর্ণ হওয়া পর্যন্ত অপেক্ষা করুন।

৩. আপনার গুগল ক্লাউড প্রজেক্ট সেট আপ করুন।
একটি গুগল ক্লাউড প্রজেক্ট তৈরি করুন
- গুগল ক্লাউড কনসোলে যান এবং একটি প্রজেক্ট নির্বাচন করুন বা তৈরি করুন।

- API ও পরিষেবা > OAuth সম্মতি স্ক্রিনে যান।

- 'Get started'- এ ক্লিক করুন এবং প্রয়োজনীয় ক্ষেত্রগুলি পূরণ করুন:
- অ্যাপের নাম : আপনার অ্যান্ড্রয়েড অ্যাপের নামটি ব্যবহার করুন।
- ব্যবহারকারী সহায়তা ইমেল : আপনার গুগল অ্যাকাউন্টটি নির্বাচন করুন।
- দর্শক : বাহ্যিক নির্বাচন করুন।
- যোগাযোগের তথ্য : আপনার ইমেল ঠিকানা লিখুন।

- Google API Services: User Data Policy পর্যালোচনা করুন এবং Create-এ ক্লিক করুন।

OAuth ক্লায়েন্ট সেট আপ করুন
প্রমাণীকরণের জন্য ক্লায়েন্ট আইডিগুলো পেতে আপনাকে গুগল ক্লাউড কনসোলে একটি ওয়েব ক্লায়েন্ট এবং একটি অ্যান্ড্রয়েড ক্লায়েন্ট উভয়ই তৈরি করতে হবে।
- অ্যান্ড্রয়েড ক্লায়েন্ট : আপনার অ্যাপের প্যাকেজ নেম এবং SHA-1 সিগনেচার যাচাই করার মাধ্যমে অনুরোধগুলোকে সুরক্ষিত করে।
- ওয়েব ক্লায়েন্ট : গুগল সাইন-ইন পরিষেবার ব্যাকএন্ড ক্লায়েন্ট হিসেবে কাজ করে।
অ্যান্ড্রয়েড OAuth 2.0 ক্লায়েন্ট তৈরি করুন
- ক্লায়েন্টস পেজে, ক্রিয়েট ক্লায়েন্ট-এ ক্লিক করুন এবং অ্যাপ্লিকেশন টাইপ হিসেবে অ্যান্ড্রয়েড নির্বাচন করুন।

- আপনার অ্যাপের প্যাকেজ নামটি লিখুন (যা আপনার
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 ফিঙ্গারপ্রিন্ট ফিল্ডে পেস্ট করুন এবং Create-এ ক্লিক করুন।

ওয়েব OAuth 2.0 ক্লায়েন্ট তৈরি করুন
- আবার Create Client-এ ক্লিক করুন এবং Application type হিসেবে Web Application নির্বাচন করুন।
- আপনার ওয়েব ক্লায়েন্টের নাম দিন, URL/Origins ফিল্ডগুলো খালি রাখুন এবং Create-এ ক্লিক করুন।

- কনফার্মেশন ডায়ালগ থেকে তৈরি হওয়া ক্লায়েন্ট আইডিটি কপি করুন। এটি আপনাকে আপনার কোটলিন কোডে ব্যবহার করতে হবে।

৪. একটি অ্যান্ড্রয়েড ভার্চুয়াল ডিভাইস সেট আপ করুন
অ্যাপটি পরীক্ষা করার জন্য, আপনি একটি বাস্তব অ্যান্ড্রয়েড ডিভাইস অথবা একটি অ্যান্ড্রয়েড ভার্চুয়াল ডিভাইস (AVD) ব্যবহার করতে পারেন।
AVD তৈরি করুন এবং চালান
- অ্যান্ড্রয়েড স্টুডিওতে, ডিভাইস ম্যানেজার খুলুন, ক্রিয়েট ভার্চুয়াল ডিভাইস (বা + আইকনে) ক্লিক করুন এবং মিডিয়াম ফোন নির্বাচন করুন।
- সিস্টেম ইমেজ হিসেবে সর্বশেষ স্থিতিশীল সংস্করণটি নির্বাচন করুন এবং ফিনিশ-এ ক্লিক করুন।
- ডিভাইসটির পাশে থাকা প্লে/রান আইকনে ক্লিক করে এমুলেটরটি চালু করুন।

ডিভাইসে একটি গুগল অ্যাকাউন্টে সাইন ইন করুন
- এমুলেটরে, সেটিংস অ্যাপটি খুলুন এবং গুগল- এ যান।
- আপনার গুগল অ্যাকাউন্টে সাইন ইন করতে ক্লিক করুন এবং নির্দেশাবলী অনুসরণ করুন।

৫. নির্ভরতা যোগ করুন
আপনার প্রজেক্টে অথেনটিকেশন এবং গুগল আইডি ইন্টিগ্রেশনের জন্য প্রয়োজনীয় লাইব্রেরিগুলো যোগ করুন:
- ফাইল > প্রজেক্ট স্ট্রাকচার > ডিপেন্ডেন্সি > অ্যাপ- এ যান।
- + > লাইব্রেরি ডিপেন্ডেন্সি-তে ক্লিক করুন,
com.google.android.libraries.identity.googleid:googleidসার্চ করুন এবং সর্বশেষ ভার্সনটি (যেমন,1.1.1) বেছে নিন। - আবার + > লাইব্রেরি ডিপেন্ডেন্সি-তে ক্লিক করুন,
play-services-authলিখে সার্চ করুন এবংcom.google.android.gmsগ্রুপ আইডি-যুক্ত লাইব্রেরিটি সিলেক্ট করুন। - পরিবর্তনগুলো প্রয়োগ করতে এবং আপনার প্রজেক্ট সিঙ্ক করতে OK-তে ক্লিক করুন।

৬. বটম শীট ফ্লো বাস্তবায়ন করুন

বটম শীট ফ্লোটি ক্রেডেনশিয়াল ম্যানেজার এপিআই ব্যবহার করে অ্যান্ড্রয়েডে ব্যবহারকারীদের তাদের গুগল অ্যাকাউন্ট দিয়ে আপনার অ্যাপে সাইন ইন করার একটি সহজ উপায় প্রদান করে। গতি এবং সুবিধার কথা মাথায় রেখে, বিশেষ করে পুরনো ব্যবহারকারীদের জন্য ডিজাইন করা এই ফ্লোটি অ্যাপ চালু হওয়ার সাথে সাথে ট্রিগার হওয়া উচিত।
সাইন-ইন অনুরোধ তৈরি করুন
- শুরু করার জন্য,
MainActivity.ktখুলুন এবং ডিফল্টGreeting()ওGreetingPreview()ফাংশনগুলো মুছে ফেলুন। - ৩ নং লাইন থেকে শুরু করে বিদ্যমান ইম্পোর্ট স্টেটমেন্টগুলোর পরে নিম্নলিখিত ইম্পোর্ট স্টেটমেন্টগুলো যোগ করুন:
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" - আপনার
MainActivity.ktফাইলেMainActivityক্লাসের নিচে এই Composable ফাংশনটি যোগ করুন:@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(): গুগল আইডি টোকেন অনুরোধটি কনফিগার করে।-
setFilterByAuthorizedAccounts(true): প্রথমে, ব্যবহারকারী এই অ্যাপের জন্য ইতিমধ্যে অনুমোদন দিয়েছেন এমন অ্যাকাউন্টগুলিকে ফিল্টার করে একটি নীরব সাইন-ইন করার চেষ্টা করে, যা পুরনো ব্যবহারকারীদের জন্য অসুবিধা কমিয়ে দেয়। -
setNonce(...): রিপ্লে অ্যাটাক প্রতিরোধ করার জন্যgenerateSecureRandomNonce()দ্বারা প্রতিটি অনুরোধের জন্য তৈরি একটি সুরক্ষিত র্যান্ডম ননস প্রেরণ করে।
-
-
signIn(request, context): অনুরোধটি কার্যকর করে। যদি এটিNoCredentialException(অর্থাৎ পূর্বে অনুমোদিত কোনো অ্যাকাউন্ট না থাকা) সহ ব্যর্থ হয়, তাহলে ফ্লোটিsetFilterByAuthorizedAccounts(false)এ ফিরে যায়, যাতে ব্যবহারকারী ডিভাইসে সাইন ইন করা যেকোনো Google অ্যাকাউন্ট থেকে বেছে নিতে পারেন।
সাইন-ইন করার অনুরোধ করুন
সাইন-ইন অনুরোধটি তৈরি হয়ে গেলে, আপনি সাইন-ইন প্রক্রিয়াটি সম্পন্ন করতে ক্রেডেনশিয়াল ম্যানেজার ব্যবহার করতে পারেন। 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(...): সিস্টেম অ্যাকাউন্ট সিলেক্টর বটম শীট বা ডায়ালগ প্রদর্শন করার জন্য ক্রেডেনশিয়াল ম্যানেজার এপিআই-কে কল করে। -
delay(250): অ্যাপ চালু হওয়ার সাথে সাথে ক্রেডেনশিয়াল ম্যানেজার সার্ভিসটি ইনিশিয়ালাইজ হওয়া শেষ হওয়ার আগেই বটম শীট ট্রিগার হলে, রেস কন্ডিশন এড়ানোর জন্য এটি অল্প সময়ের জন্য বিরতি দেয়। - ব্যতিক্রম পরিচালনা : সাধারণ ক্রেডেনশিয়াল ত্রুটিগুলি (যেমন, বাতিলকরণ, অনুপস্থিত ক্রেডেনশিয়াল, বা টোকেন পার্সিং সমস্যা) ধরে ফেলে এবং লগ করে, এবং টোস্টের মাধ্যমে ব্যবহারকারীকে প্রতিক্রিয়া জানায়।
বটম শীট প্রবাহ চালু করুন
আপনার 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)
}
}
}
}
}
আপনার প্রজেক্টটি সেভ করুন ( ফাইল > সেভ ) এবং অ্যাপ্লিকেশনটি রান করুন:
- রান বাটন টিপুন:

- যখন এমুলেটরে অ্যাপটি চালু হবে, তখন সাইন-ইন বটম শীটটি দেখা যাবে। প্রক্রিয়াটি পরীক্ষা করতে 'Continue'-তে ক্লিক করুন।

- সাইন-ইন সফল হয়েছে তা নিশ্চিত করে একটি টোস্ট নোটিফিকেশন প্রদর্শিত হবে।

৭. বাটন ফ্লো বাস্তবায়ন করুন

বাটন ফ্লো ব্যবহারকারীদের সাইন ইন বা সাইন আপ করার জন্য একটি সুস্পষ্ট বিকল্প প্রদান করে। স্ট্যান্ডার্ড ব্র্যান্ডিং ব্যবহার একটি সামঞ্জস্যপূর্ণ অভিজ্ঞতা নিশ্চিত করে। ‘ সাইন ইন উইথ গুগল ব্র্যান্ডিং গাইডলাইনস’ মেনে চলে এমন পূর্ব-অনুমোদিত অ্যাসেট ব্যবহার করুন।
ব্র্যান্ড আইকন যোগ করুন
- এখান থেকে ব্র্যান্ড অ্যাসেটগুলো ডাউনলোড করুন এবং ZIP ফাইলটি এক্সট্র্যাক্ট করুন।
-
signin-assets/Android/png@2x/neutral/android_neutral_sq_SI@2x.pngফাইলটি কপি করুন। - অ্যান্ড্রয়েড স্টুডিওতে, ফাইলটি আপনার 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: বটম শীট ফ্লো-এর বিপরীতে, এক্সপ্লিসিট বাটন ফ্লো এই অপশনটি ব্যবহার করে ব্যবহারকারীদেরকে স্বয়ংক্রিয় ফিল্টারিং ছাড়াই তাদের গুগল অ্যাকাউন্ট বেছে নিতে অনুরোধ করে। -
coroutineScope.launch: বাটনটি ক্লিক করা হলে সাসপেন্ডsignInফাংশনটি অ্যাসিঙ্ক্রোনাসভাবে সম্পাদন করার জন্য একটি কো-রুটিন চালু করে। -
Image: ব্র্যান্ডেডsiwg_buttonড্রয়েবলটি প্রদর্শন করে এবং ফ্লোটি ট্রিগার করার জন্য একটি ক্লিক লিসেনার সংযুক্ত করে।
UI লেআউটে বাটনটি যোগ করুন
স্বয়ংক্রিয় BottomSheet এবং সুস্পষ্ট ButtonUI উভয়ই উল্লম্বভাবে সারিবদ্ধ করে প্রদর্শন করার জন্য আপনার MainActivity লেআউটটি আপডেট করুন:
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)
}
}
}
}
}
}
বাটন প্রবাহ পরীক্ষা করুন
- অ্যাপ্লিকেশনটি চালান।
- শীট এলাকার বাইরে ক্লিক করে প্রাথমিক বটম শীটটি বাতিল করুন।
- সাইন-ইন ডায়ালগ বক্সটি চালু করতে 'Sign in with Google' বোতামটিতে ক্লিক করুন এবং আপনার অ্যাকাউন্টটি নির্বাচন করুন।

- ফলাফল যাচাই করুন: আপনার ইউজারনেম/ইমেল অ্যাড্রেসের প্রিন্টআউটটি নিশ্চিত করতে লগক্যাট (Logcat) দেখুন।
৮. উপসংহার
অভিনন্দন! আপনি অ্যান্ড্রয়েড ক্রেডেনশিয়াল ম্যানেজার ব্যবহার করে সফলভাবে ‘সাইন ইন উইথ গুগল’ চালু করেছেন।
অতিরিক্ত সম্পদ
- অ্যান্ড্রয়েড ক্রেডেনশিয়াল ম্যানেজার ডকুমেন্টেশন
- ক্রেডেনশিয়াল ম্যানেজার ট্রাবলশুটিং গাইড
- ক্রেডেনশিয়াল ম্যানেজার প্রায়শই জিজ্ঞাসিত প্রশ্নাবলী
- স্ট্যাকওভারফ্লো সমর্থন
সম্পূর্ণ 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
}
}