This post is about how to authenticate users via Google Sign-in using the Google sign-in API, how to extract basic profile details like displayName, email, etc., and add signOut functionality in Android with the help of a simple demo app.
Configuring a Google API Console project
Firstly, we must configure the google API console account before configuring a Google API Console project.
-
To configure a Google API Console project, use this link and click on “Configure a project”. Enter the project name, select Android, enter the package name and SHA-1 certificate.
- To generate the SHA1 follow the below steps:
1. Click Gradle in right side panel then navigate: app > Tasks > android
2. Double Click on signingReport (You will get SHA1 and MD5 in Run Bar (Sometimes it will be in Gradle Console)).
Creating new project
1 . Create a new project by going to File ⇒ New Android Project, select Empty Activity, provide app name, select language to kotlin and then finally click on finish.
2 . In your project’s top-level build.gradle file, ensure that Google’s Maven repository is included:
build.gradle
buildscript {
repositories {
google()
}
}
3 . Open app-level build.gradle file and add the below library under dependencies section:
build.gradle
dependencies {
implementation 'com.google.android.gms:play-services-auth:20.0.1'
}
4 . Open AndroidManifest.xml file and add the Internet permission above <application>.
AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
The Layout File
5 . Add the TextView and Google SignInButton in activity_main.xml file.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:gravity="center"
android:text="LOGIN"
android:textColor="@color/purple_500"
android:textSize="40sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.gms.common.SignInButton
android:id="@+id/sign_in_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="12dp"
android:layout_marginRight="12dp"
android:layout_marginBottom="30dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
6 . The activity_second.xml file defines the UI of the next activity(SecondActivity) that opens after the user sign in. It consists of a SignOut button two Textviews (to display user name and email).
activity_second.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SecondActivity">
<TextView
android:id="@+id/pName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="@color/purple_500"
android:textSize="21sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/pEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:gravity="center"
android:textColor="@color/purple_500"
android:textSize="21sp"
app:layout_constraintEnd_toEndOf="@+id/pName"
app:layout_constraintStart_toStartOf="@+id/pName"
app:layout_constraintTop_toBottomOf="@+id/pName" />
<Button
android:id="@+id/btnSignOut"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:padding="10dp"
android:text="Sign Out"
android:textAllCaps="false"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="@+id/pEmail"
app:layout_constraintStart_toStartOf="@+id/pEmail"
app:layout_constraintTop_toBottomOf="@+id/pEmail" />
</androidx.constraintlayout.widget.ConstraintLayout>
7 . Create a new kotlin object Utility and add the below code:
Utility.kt
object Utility {
// Check for existing Google Sign In account, if the user is already signed in
// the GoogleSignInAccount will be non-null.
fun isUserSignedIn(context: Context): Boolean {
val account = GoogleSignIn.getLastSignedInAccount(context)
return account != null
}
fun getGoogleSigninClient(activity: Activity): GoogleSignInClient {
// Configure sign-in to request the user's ID, email address, and basic
// profile. ID and basic profile are included in DEFAULT_SIGN_IN.
val gso = GoogleSignInOptions
.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.requestProfile()
.build()
// Build a GoogleSignInClient with the options specified by gso.
return GoogleSignIn.getClient(activity, gso)
}
}
8 . Open MainActivity.kt file and add the below code:
MainActivity.kt
class MainActivity : AppCompatActivity() {
private lateinit var activityMainBinding: ActivityMainBinding
lateinit var mGoogleSignInClient: GoogleSignInClient
lateinit var startActivityForResult: ActivityResultLauncher<Intent>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activityMainBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(activityMainBinding.root)
mGoogleSignInClient = getGoogleSigninClient(this@MainActivity)
activityMainBinding.signInButton.setSize(SignInButton.SIZE_WIDE)
activityMainBinding.signInButton.setOnClickListener {
GoogleSignIn()
}
startActivityForResult =
registerForActivityResult(ActivityResultContracts.StartActivityForResult(),
ActivityResultCallback<ActivityResult>()
{
if (it.resultCode == Activity.RESULT_OK) {
handleSignData(it.data)
}
})
}
private fun GoogleSignIn() {
if (!isUserSignedIn(this)) {
//creating a sign-in intent with the getSignInIntent method,
// and starting the intent by calling startActivityForResult.
// Starting the intent prompts the user to select a Google account to sign in with.
val signInIntent = mGoogleSignInClient.signInIntent
startActivityForResult.launch(signInIntent)
} else {
Toast.makeText(this, "User already signed-in", Toast.LENGTH_SHORT).show()
}
}
private fun handleSignData(data: Intent?) {
//After the user signs in, you can get a GoogleSignInAccount object for the user,
//The GoogleSignInAccount object contains information about the signed-in user.
GoogleSignIn.getSignedInAccountFromIntent(data)
.addOnCompleteListener {
"isSuccessful ${it.isSuccessful}".print()
if (it.isSuccessful) {
// user successfully logged-in
"account ${it.result?.account}".print()
"displayName ${it.result?.displayName}".print()
"Email ${it.result?.email}".print()
// start next activity
val intent = Intent(this, SecondActivity::class.java)
startActivity(intent)
} else {
// authentication failed
"exception ${it.exception}".print()
}
}
}
companion object {
const val TAG_MAINACTIVITY = "TAG_MAINACTIVITY"
}
}
fun Any.print() {
Log.v(MainActivity.TAG_MAINACTIVITY, " $this")
}
9 . The SecondActivity.kt file contains the logic related to sign-out button functionality and here, we get the information related to the sign-in user and display it in textviews.
SecondActivity.kt
class SecondActivity : AppCompatActivity() {
private lateinit var activitySecondBinding: ActivitySecondBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activitySecondBinding = ActivitySecondBinding.inflate(layoutInflater)
setContentView(activitySecondBinding.root)
val account = GoogleSignIn.getLastSignedInAccount(this)
if (account != null) {
activitySecondBinding.pName.text = account.displayName
activitySecondBinding.pEmail.text = account.email
}
activitySecondBinding.btnSignOut.setOnClickListener {
signout()
}
}
private fun signout() {
if (isUserSignedIn(this)) {
//clears the account, which is connected to the app
getGoogleSigninClient(this@SecondActivity).signOut().addOnCompleteListener {
if (it.isSuccessful) {
Toast.makeText(this@SecondActivity, " Signed out ", Toast.LENGTH_SHORT).show()
//opens login activity
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
} else {
Toast.makeText(this@SecondActivity, " Error ", Toast.LENGTH_SHORT).show()
}
}
}
}
}
When you run the app it will look like this: