Android Login with Google Plus Account

Google+ sign-in lets users sign in to your Android app with their existing Google account and get their profile information like name, email, profile pic and other details. By integrating google plus login in your apps, you can get all the user details in one shot. Not only login, you can do other things like posting to their g+ account, getting list of circles, friends list and lot more. The major advantage of integrating G+ login is, you can drive more users to your app by providing quicker & easiest way of registration process.

android login with google plus account

So let’s start by doing required setup.

1. Installing / updating Google Play Services

Google plus is a part of Google Play Services API. So first we need to download the google play services in Android SDK manager. If you have already installed play services, it it very important to update it to latest version. Open the SDK manager and install or update the play services under Extras section.

android sdk manager installing play services

2. Generating Google-Services.json

Now all the android projects which uses google apis, requires google-services.json file to be placed in project’s app folder. Follow the below steps to get your google-services.json file.

2.1 Java keytool can be used to generate SHA-1 fingerprint. Open your terminal and execute the following command to generate SHA-1 fingerprint. If it ask for password, type android and press enter.

On windows

keytool -list -v -keystore "%USERPROFILE%\.android\debug.keystore" -alias androiddebugkey -storepass android -keypass android

On Linux or Mac OS

keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android

In the output you can notice SHA1 fingerprint.

android generating sha1 fingerprint

2.2 Goto android quick start guide and click on Get A Configuration File button. This will redirect you to a page where you can choose the project and package name.

2.3 Create / choose an app and give your current app package name. I gave my package name as info.androidhive.gpluslogin.

2.4 Paste the SHA-1 fingerprint and click on Enable Google Sign-In. Finally click on Generate Configuration File to download your google-services.json

android-google-plus-google-services-json

3. Creating New Project

3.1. Create a new project in Android Studio from File ⇒ New Project. When it prompts you to select the default activity, select Blank Activity and proceed.

While filling the project details, use the same package name which you gave in google console. In my case I am using same info.androidhive.gpluslogin

3.2. Open project level build.gradle and add ‘com.google.gms:google-services:3.0.0’ class path to dependencies.

dependencies {
        classpath 'com.android.tools.build:gradle:2.1.0'
        classpath 'com.google.gms:google-services:3.0.0'
    }

3.3. Open app level build.gradle and add ‘compile com.google.android.gms:play-services-auth:9.2.1’ to dependencies. At the bottom of the file, add apply plugin: ‘com.google.gms.google-services’

You can notice that, Glide dependency also added here to load the google profile picture in image view. This is completely optional.

dependencies {
    // ..
    compile 'com.google.android.gms:play-services-auth:9.2.1'

    // glide is added to load the g+ profile image. Ignore if you want
    compile 'com.github.bumptech.glide:glide:3.7.0'
}

apply plugin: 'com.google.gms.google-services'

3.4 Open strings.xml file located under res ⇒ values and add following strings.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">G+ Login</string>
    <string name="action_settings">Settings</string>
    
    <!-- Button text -->
    <string name="btn_logout_from_google">Logout from Google</string>
    <string name="btn_revoke_access">Revoke Access</string>
</resources>

3.5. Now I am designing a simple layout to display user’s profile picture, name, email and other buttons. Paste the below code in layout file of your main activity. In my case my layout file name is activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp"
    tools:context=".MainActivity" >

    <LinearLayout
        android:id="@+id/llProfile"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="20dp"
        android:orientation="horizontal"
        android:weightSum="3"
        android:visibility="gone">

        <ImageView
            android:id="@+id/imgProfilePic"
            android:layout_width="80dp"
            android:layout_height="wrap_content" 
            android:layout_weight="1"/>

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:orientation="vertical"
            android:layout_weight="2" >

            <TextView
                android:id="@+id/txtName"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:padding="5dp"
                android:textSize="20dp" />

            <TextView
                android:id="@+id/txtEmail"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:padding="5dp"
                android:textSize="18dp" />
        </LinearLayout>
    </LinearLayout>

    <com.google.android.gms.common.SignInButton
        android:id="@+id/btn_sign_in"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" 
        android:layout_marginBottom="20dp"/>

    <Button
        android:id="@+id/btn_sign_out"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/btn_logout_from_google"
        android:visibility="gone" 
        android:layout_marginBottom="10dp"/>

    <Button
        android:id="@+id/btn_revoke_access"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/btn_revoke_access"
        android:visibility="gone" />

</LinearLayout>

3.6 . Now open MainActivity.java and do the below modifications. The code is self explanatory and very easy understand.

> implement the activity from GoogleApiClient.OnConnectionFailedListener

> Create the GoogleApiClient instance in onCrate() method.

> signIn() performs google plus sign in, signOut() logs out user from google account and revokeAccess() completely revokes the access from google plus.

> onActivityResult() is called whenever user returns from Google Login UI.

> In onStart() method, checked for cached google sign in session and appropriate UI is displayed.

> handleSignInResult() handles the google plus profile information upon successful login.

> updateUI() toggles the UI by showing / hiding the appropriate buttons and text views.

package info.androidhive.gpluslogin;

import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.google.android.gms.auth.api.Auth;
import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
import com.google.android.gms.auth.api.signin.GoogleSignInResult;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.SignInButton;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.OptionalPendingResult;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;

public class MainActivity extends AppCompatActivity implements
        View.OnClickListener,
        GoogleApiClient.OnConnectionFailedListener {

    private static final String TAG = MainActivity.class.getSimpleName();
    private static final int RC_SIGN_IN = 007;

    private GoogleApiClient mGoogleApiClient;
    private ProgressDialog mProgressDialog;

    private SignInButton btnSignIn;
    private Button btnSignOut, btnRevokeAccess;
    private LinearLayout llProfileLayout;
    private ImageView imgProfilePic;
    private TextView txtName, txtEmail;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnSignIn = (SignInButton) findViewById(R.id.btn_sign_in);
        btnSignOut = (Button) findViewById(R.id.btn_sign_out);
        btnRevokeAccess = (Button) findViewById(R.id.btn_revoke_access);
        llProfileLayout = (LinearLayout) findViewById(R.id.llProfile);
        imgProfilePic = (ImageView) findViewById(R.id.imgProfilePic);
        txtName = (TextView) findViewById(R.id.txtName);
        txtEmail = (TextView) findViewById(R.id.txtEmail);

        btnSignIn.setOnClickListener(this);
        btnSignOut.setOnClickListener(this);
        btnRevokeAccess.setOnClickListener(this);

        GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                .requestEmail()
                .build();

        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .enableAutoManage(this, this)
                .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
                .build();

        // Customizing G+ button
        btnSignIn.setSize(SignInButton.SIZE_STANDARD);
        btnSignIn.setScopes(gso.getScopeArray());
    }


    private void signIn() {
        Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
        startActivityForResult(signInIntent, RC_SIGN_IN);
    }


    private void signOut() {
        Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
                new ResultCallback<Status>() {
                    @Override
                    public void onResult(Status status) {
                        updateUI(false);
                    }
                });
    }

    private void revokeAccess() {
        Auth.GoogleSignInApi.revokeAccess(mGoogleApiClient).setResultCallback(
                new ResultCallback<Status>() {
                    @Override
                    public void onResult(Status status) {
                        updateUI(false);
                    }
                });
    }

    private void handleSignInResult(GoogleSignInResult result) {
        Log.d(TAG, "handleSignInResult:" + result.isSuccess());
        if (result.isSuccess()) {
            // Signed in successfully, show authenticated UI.
            GoogleSignInAccount acct = result.getSignInAccount();

            Log.e(TAG, "display name: " + acct.getDisplayName());

            String personName = acct.getDisplayName();
            String personPhotoUrl = acct.getPhotoUrl().toString();
            String email = acct.getEmail();

            Log.e(TAG, "Name: " + personName + ", email: " + email
                    + ", Image: " + personPhotoUrl);

            txtName.setText(personName);
            txtEmail.setText(email);
            Glide.with(getApplicationContext()).load(personPhotoUrl)
                    .thumbnail(0.5f)
                    .crossFade()
                    .diskCacheStrategy(DiskCacheStrategy.ALL)
                    .into(imgProfilePic);

            updateUI(true);
        } else {
            // Signed out, show unauthenticated UI.
            updateUI(false);
        }
    }

    @Override
    public void onClick(View v) {
        int id = v.getId();

        switch (id) {
            case R.id.btn_sign_in:
                signIn();
                break;

            case R.id.btn_sign_out:
                signOut();
                break;

            case R.id.btn_revoke_access:
                revokeAccess();
                break;
        }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        // Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
        if (requestCode == RC_SIGN_IN) {
            GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
            handleSignInResult(result);
        }
    }

    @Override
    public void onStart() {
        super.onStart();

        OptionalPendingResult<GoogleSignInResult> opr = Auth.GoogleSignInApi.silentSignIn(mGoogleApiClient);
        if (opr.isDone()) {
            // If the user's cached credentials are valid, the OptionalPendingResult will be "done"
            // and the GoogleSignInResult will be available instantly.
            Log.d(TAG, "Got cached sign-in");
            GoogleSignInResult result = opr.get();
            handleSignInResult(result);
        } else {
            // If the user has not previously signed in on this device or the sign-in has expired,
            // this asynchronous branch will attempt to sign in the user silently.  Cross-device
            // single sign-on will occur in this branch.
            showProgressDialog();
            opr.setResultCallback(new ResultCallback<GoogleSignInResult>() {
                @Override
                public void onResult(GoogleSignInResult googleSignInResult) {
                    hideProgressDialog();
                    handleSignInResult(googleSignInResult);
                }
            });
        }
    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
        // An unresolvable error has occurred and Google APIs (including Sign-In) will not
        // be available.
        Log.d(TAG, "onConnectionFailed:" + connectionResult);
    }

    private void showProgressDialog() {
        if (mProgressDialog == null) {
            mProgressDialog = new ProgressDialog(this);
            mProgressDialog.setMessage(getString(R.string.loading));
            mProgressDialog.setIndeterminate(true);
        }

        mProgressDialog.show();
    }

    private void hideProgressDialog() {
        if (mProgressDialog != null && mProgressDialog.isShowing()) {
            mProgressDialog.hide();
        }
    }

    private void updateUI(boolean isSignedIn) {
        if (isSignedIn) {
            btnSignIn.setVisibility(View.GONE);
            btnSignOut.setVisibility(View.VISIBLE);
            btnRevokeAccess.setVisibility(View.VISIBLE);
            llProfileLayout.setVisibility(View.VISIBLE);
        } else {
            btnSignIn.setVisibility(View.VISIBLE);
            btnSignOut.setVisibility(View.GONE);
            btnRevokeAccess.setVisibility(View.GONE);
            llProfileLayout.setVisibility(View.GONE);
        }
    }
}

5. Testing the app

On Real Device:
You can directly test this app on a real devices which is having Google account connected.

On Emulator:
You can also test the application on an emulator which runs Android 4.2.2 or greater. Follow below link to know how to configure an emulator by installing Google Play Services.
Configuring emulator with Google Play Services

If user clicks on sign in button, the following popup will be shown asking user to sign-in using google plus account.

android-google-plus-sign-in-choosing-the-account
android-sign-in-with-google-plus-account
Change Log

Updated On2nd Sep 2016 (Content Update, Bug fixes)
Ravi is hardcore Android programmer and Android programming has been his passion since he compiled his first hello-world program. Solving real problems of Android developers through tutorials has always been interesting part for him.