Allowing users to sign-in is now basic requirement in almost every Android App. Once the user logs in we have access to some of his basic information which we can use to not only personalize his user experience but also his credentials can be used to save user specific app information on the server. But instead of implementing your own email sign up/authentication you can simply add a Google Login Button and enjoy all the benefits. Following are some of the reasons why implementing Google Sign-in is better
- Most importantly you save the user from lengthy sign-up(register) process. Almost everyone has a Google account
- Users will not have privacy concerns. Generally users are more comfortable sharing information with a tech giant like Google rather than entering all their personal information in a third party app.
- You don’t need to implement any email verification or back end APIs. Google completes the credential verification on its own and returns you basic information of the user.
- Users are already logged into their google account on their mobile devices. This means the user doesn’t even need to re enter his email and password. Just a button click logs him into the android app.
In this Google Sign-In example we will developing an Android App which will use Google Sign-In to login the user and display his basic information
Google Sign-In Example : First Step
Create a new Project in your Android Studio. Note the package name as this will be used while registering your app with Google
Registering your app with Google
- Open Google’s Sign In Integration page and check for all the prerequisites mentioned. Make sure you are logged into your Google account
- Now click on “Configure a Project” button same as shown in the screenshot below
- Now enter a Project name of your choice.
- Configure the OAuth details. Basically enter your app name which will be seen in the consent screen.
- Enter your package name and SHA1 signature. If you are not sure how to find your SHA1 signature read this.
Add Gradle Dependencies
- Add the following in project level build.gradle
allprojects { repositories { google() ... } }
- Add the following dependency in app level build.gradle
implementation 'com.google.android.gms:play-services-auth:15.0.1'
Note that 15.0.1 is the latest version available while writing this tutorial. Please check the latest version while implementing this example.
In this example we will have two activities. First is a LoginActivity with a log-in button and second is a ProfileActivity which will display user information and a sign out button.
Adding Google Sign-In Button
- Following is the layout file for LoginActivity. We have added a single SignIn button to initiate Sign In
<?xml version="1.0" encoding="utf-8"?> <FrameLayout 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"> <com.google.android.gms.common.SignInButton android:id="@+id/sign_in_button" android:layout_gravity="center" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </FrameLayout>
- Now initialize the same button in JAVA file LoginActivity.java
public class MainActivity extends AppCompatActivity { private static final String TAG = "AndroidClarified"; private SignInButton googleSignInButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); googleSignInButton = findViewById(R.id.sign_in_button); } }
Configure Google Sign-In
- To configure Google sign in first we need to create a GoogleSignInOptions object. This object configuration depends on what information is requested from Google. For example, to request basic user information we use the DEFAULT_SIGN_IN configuration as shown below. Based on the default configuration we can add additional configuration using APIs like requestEmail(), requestTokenId() etc. We create the GoogleSignInOption object in onCreate method as shown below
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); googleSignInButton = findViewById(R.id.sign_in_button); GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestEmail() .build(); }
- Create a GoogleSignInClient object using the GoogleSignInOptions as shown in the snippet below
public class MainActivity extends AppCompatActivity { private static final String TAG = "AndroidClarified"; private GoogleSignInClient googleSignInClient; private SignInButton googleSignInButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); googleSignInButton = findViewById(R.id.sign_in_button); GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestIdToken() .requestEmail() .build(); googleSignInClient = GoogleSignIn.getClient(this, gso); } }
- Now implement the OnClickListener on the login button. Here we launch the login screen using the Intent we get by calling getSignInIntent on the GoogleSignInClient object . We start the login by calling startActivityForResult as shown below
public class MainActivity extends AppCompatActivity { private static final String TAG = "AndroidClarified"; private GoogleSignInClient googleSignInClient; private SignInButton googleSignInButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); googleSignInButton = findViewById(R.id.sign_in_button); GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestIdToken() .requestEmail() .build(); googleSignInClient = GoogleSignIn.getClient(this, gso); googleSignInButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent signInIntent = googleSignInClient.getSignInIntent(); startActivityForResult(signInIntent, 101); } }); } }
User is prompted with a dialog to select the Account he was log into. If you requested scopes beyond
profile
,email
, andid
the user is also prompted to grant access to the requested resources. - Result of Sign-In intent launched in the previous step is received in onActivityResult. Therefore we implement onActivityResult in our LoginActivity. We can use the result returned to get the task object which in turns gives us the GoogleSignInAccount object. This object is used to fetch all the information requested from Google(email, name etc)
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == Activity.RESULT_OK) switch (requestCode) { case 101: try { // The Task returned from this call is always completed, no need to attach // a listener. Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data); GoogleSignInAccount account = task.getResult(ApiException.class); onLoggedIn(account); } catch (ApiException e) { // The ApiException status code indicates the detailed failure reason. Log.w(TAG, "signInResult:failed code=" + e.getStatusCode()); } break; } }
- We call a private method onLoggedIn() from onActivtyResult(). In this method we will create an Intent to start ProfileActivity and pass GoogleSignInAccount object along with it.
private void onLoggedIn(GoogleSignInAccount googleSignInAccount) { Intent intent = new Intent(this, ProfileActivity.class); intent.putExtra(ProfileActivity.GOOGLE_ACCOUNT, googleSignInAccount); startActivity(intent); finish(); }
Note : We have not created ProfileActivity so far. Will do in the next section.
Checking if already Logged In
- Interesting thing about Google Sign In is user isn’t logged out when he kills the app. Which means you need to check if the user is already logged in every time you enter LoginActivity. This can be simply done by implementing onStart() method as shown below
@Override public void onStart() { super.onStart(); GoogleSignInAccount alreadyloggedAccount = GoogleSignIn.getLastSignedInAccount(this); if (alreadyloggedAccount != null) { Toast.makeText(this, "Already Logged In", Toast.LENGTH_SHORT).show(); onLoggedIn(alreadyloggedAccount); } else { Log.d(TAG, "Not logged in"); } }
GoogleSignIn.getLastSignedInAccount returns the GoogleSignInAccount object if the user has already signed in . It returns null if user has not logged in yet.
Getting Basic User Information from Google
- The whole point of enabling Sign-In in your Android app is that we can get some basic information of the user. In the last section we retrieved the GoogleSignInAccount from Google and passed it to ProfileActivity. In this section we will create that ProfileActivity and get user information from GoogleSignInAccount object.
- Below is the layout of activity of ProfileActivity. It has two TextViews to display email and username, one ImageView to display profile picture and one button for sign out.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout 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=".ProfileActivity"> <ImageView android:layout_margin="20dp" android:layout_centerHorizontal="true" android:id="@+id/profile_image" android:layout_width="150dp" android:layout_height="150dp" /> <TextView android:layout_width="wrap_content" android:layout_margin="10dp" tools:text="Irshad Kumail" android:id="@+id/profile_text" android:textSize="16sp" android:layout_below="@id/profile_image" android:layout_centerHorizontal="true" android:layout_height="wrap_content" /> <TextView android:textSize="14sp" android:id="@+id/profile_email" android:layout_width="wrap_content" android:layout_margin="10dp" tools:text="irshadkumail@gmail.com" android:layout_centerHorizontal="true" android:layout_below="@id/profile_text" android:layout_height="wrap_content" /> <Button android:layout_width="140dp" android:text="SIGN OUT" android:id="@+id/sign_out" android:layout_marginBottom="50dp" android:layout_centerHorizontal="true" android:layout_alignParentBottom="true" android:layout_height="wrap_content" /> </RelativeLayout>
- Now we initialize the views in our java file
public class ProfileActivity extends AppCompatActivity { public static final String GOOGLE_ACCOUNT = "google_account"; private TextView profileName, profileEmail; private ImageView profileImage; private Button signOut; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_profile); profileName = findViewById(R.id.profile_text); profileEmail = findViewById(R.id.profile_email); profileImage = findViewById(R.id.profile_image); signOut=findViewById(R.id.sign_out); } }
- We will use the GoogleSignInObject received along with Intent to display user information by creating a private method setDataOnView() as shown below
private void setDataOnView() { GoogleSignInAccount googleSignInAccount = getIntent().getParcelableExtra(GOOGLE_ACCOUNT); Picasso.get().load(googleSignInAccount.getPhotoUrl()).centerInside().fit().into(profileImage); profileName.setText(googleSignInAccount.getDisplayName()); profileEmail.setText(googleSignInAccount.getEmail()); }
Sign-Out Implementation
As you can see in the screenshot pasted above we also have sign-out button to log out the user. Its implementation is fairly simple wherein we use googleSignInClient.signOut() API.
signOut.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { /* Sign-out is initiated by simply calling the googleSignInClient.signOut API. We add a listener which will be invoked once the sign out is the successful */ googleSignInClient.signOut().addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { //On Succesfull signout we navigate the user back to LoginActivity Intent intent=new Intent(ProfileActivity.this,MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(intent); } }); } });
Backend Server Authentication with Google
Here comes the bonus part of this Google Sign-In example. Read this to find how Google Sign-In can help you with your backend implementation
You can also use Google Sign-In to identify the user on your backend server. This can be done with the help of idToken returned from Google. Instead of directly getting user information and just displaying it in your app you can pass the user’s idToken to your server which can either create a session or a create new account with it. Following are the steps of how to implement it
- Go to Google API Console and select the project created in step one. Once the project is selected click on credentials in the left panel.
- Now copy the client id next to Web client (Auto-created for Google Sign-in).
- Add the copied client id in your Android project’s strings.xml
- Now while configuring GoogleSignInOptions instead of requesting email address we request for id token as shown in the snippet below
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); googleSignInButton = findViewById(R.id.sign_in_button); GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestIdToken(getResources().getString(R.string.web_client_id)) .build(); }
- Once the user has logged in you can obtain id token as shown in the snippet below
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == Activity.RESULT_OK) switch (requestCode) { case 101: try { // The Task returned from this call is always completed, no need to attach // a listener. Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data); GoogleSignInAccount account = task.getResult(ApiException.class); String idToken = account.getIdToken(); /* Write to the logic send this id token to server using HTTPS */ } catch (ApiException e) { // The ApiException status code indicates the detailed failure reason. Log.w(TAG, "signInResult:failed code=" + e.getStatusCode()); } break; } }
Conclusion
I hope you enjoyed this tutorial and understood how easy and useful is implementing Google Sign-In for your Android App. If you liked this tutorial read more Android Examples here
We have a one more interesting tutorial on use of Google APIs. Read this to learn to how to fetch and display your current location on Google Maps
The sign in works fine for already existing email address, however, if i try to sigh up from system’s sign in dialog, the display number is null after successful sign up. any clue?
LikeLike
Is it possible send me project’s file ,
i have an problem whit Implementation.
behzad.esoft@yahoo.com
LikeLike
i have problem whit sign out .
it dose’t work! when i click on sign out the app will crash.
LikeLike
Please paste the crash logs.
LikeLike
I get the following error:
W/System.err: java.lang.NullPointerException: Attempt to invoke virtual method ‘int android.view.View.getVisibility()’ on a null object reference
W/System.err: at android.view.ViewRootImpl.getHostVisibility(ViewRootImpl.java:1809)
W/System.err: at android.view.ViewRootImpl.handleAppVisibility(ViewRootImpl.java:1445)
at android.view.ViewRootImpl$ViewRootHandler.handleMessage(ViewRootImpl.java:4841)
W/System.err: at android.os.Handler.dispatchMessage(Handler.java:106)
W/System.err: at android.os.Looper.loop(Looper.java:214)
W/System.err: at android.app.ActivityThread.main(ActivityThread.java:7078)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:964)
LikeLike
On which view are u calling getVisibility()?
LikeLike
I am getting null object reference on sign out button click
java.lang.NullPointerException: Attempt to invoke virtual method ‘com.google.android.gms.tasks.Task com.google.android.gms.auth.api.signin.GoogleSignInClient.signOut()’ on a null object reference
LikeLike
Hello Sir,
How to create a Custom Google Sign in Button in Android.
I create Different deigns for Google Button.
Please help me and Please create a one Post on How to create a Custom Google Sign in Button in Android.
LikeLike
googleSignInClient object referred in signout method is not the same used in signin. This throws nullpointer exception when signout button is clicked.
To fix, refer to the original object of signin method.
LikeLike