26

I want to integrate google sign in to my app, when user first sign in I will create an account bind to this, so I need some profiles like gender, locale, etc. and I tried as the google-sign-in doc and quick-start sample shows:

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

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

when click to sign in I will call:

  Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
    startActivityForResult(signInIntent, RC_SIGN_IN);

sign in successful, I can get a data structure GoogleSignInResult in onActivityResult, from GoogleSignInResult I can get a GoogleSignInAccount, which only contains DisplayName, email and id. but when in https://developers.google.com/apis-explorer/#p/, I can get profiles like gender, locale. Is there anything I missed?

and I tried google plus api, it seems that I can get what I want. but don't know how to use, the doc says create client like this:

mGoogleApiClient = new GoogleApiClient.Builder(this)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(Plus.API)
            .addScope(new Scope(Scopes.PLUS_LOGIN))
            .addScope(new Scope(Scopes.PLUS_ME))
            .build();

but when I use this, click signin button will cause app crash.

Update: problems when update to new version of google sign in Missing api_key/current key with Google Services 3.0.0

Community
  • 1
  • 1
dx3906
  • 327
  • 1
  • 4
  • 12
  • did you find anything or not ?? – aman verma Nov 26 '15 at 16:01
  • @amanverma I read your new question. IMO, you should read the comments between the OP and me below my answer at this question. – BNK Dec 19 '15 at 13:56
  • nah actually i think as google sign-in is working fine so there is nothing wrong in my keystore i think problem is somewhere else ?? – aman verma Dec 19 '15 at 15:47
  • @amanverma the OP has had the same issue as yours. Pls read his entire question again. – BNK Dec 20 '15 at 00:03
  • what do u mean by OP ?? – aman verma Dec 20 '15 at 10:41
  • @amanverma in SO, "OP" to refer to the person who asked a question. – BNK Dec 20 '15 at 13:01
  • About `Missing api_key/current key with Google Services 3.0.0` you should re-generate the configuration file at https://developers.google.com/cloud-messaging/android/client#get-config, or manually add API key into your app's exisiting config file, looks like `"api_key": [ { "current_key": "AIzaS.....BeQK6Q" } ],` – BNK Jun 24 '16 at 02:38

5 Answers5

32

UPDATE:

Since Plus.PeopleApi has been deprecated in Google Play services 9.4 as Google's declaration notes, please refer to the following solutions using Google People API instead:

Get person details in new google sign in Play Services 8.3 (Isabella Chen's answer);

Cannot get private birthday from Google Plus account although explicit request

END OF UPDATE


First of all, make sure you have created Google+ profile for your Google account. Then you can refer to the following code:

GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)             
                .requestScopes(new Scope(Scopes.PLUS_LOGIN))
                .requestEmail()
                .build();

and

mGoogleApiClient = new GoogleApiClient.Builder(this)
                .enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
                .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
                .addApi(Plus.API)
                .build();

Then

    @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);

            // G+
            Person person  = Plus.PeopleApi.getCurrentPerson(mGoogleApiClient);
            Log.i(TAG, "--------------------------------");
            Log.i(TAG, "Display Name: " + person.getDisplayName());
            Log.i(TAG, "Gender: " + person.getGender());
            Log.i(TAG, "AboutMe: " + person.getAboutMe());
            Log.i(TAG, "Birthday: " + person.getBirthday());
            Log.i(TAG, "Current Location: " + person.getCurrentLocation());
            Log.i(TAG, "Language: " + person.getLanguage());
        }
    }

Inside build.gradle file

// Dependency for Google Sign-In
compile 'com.google.android.gms:play-services-auth:8.3.0'
compile 'com.google.android.gms:play-services-plus:8.3.0'

You can take a look at My GitHub sample project. Hope this helps!

Community
  • 1
  • 1
BNK
  • 23,994
  • 8
  • 77
  • 87
  • mGoogleApiClient.isConnected() returns true but Plus.PeopleApi.getCurrentPerson(mGoogleApiClient) returns null ,I use the keystore at C:\Users\xxx\.android\debug.keystore to generate sha1,and your project lack google-service.json. – dx3906 Nov 25 '15 at 08:21
  • If you use my sample project, of course you must update with your application Id and your google-service.json file – BNK Nov 25 '15 at 08:33
  • i don't know why ,but when i use a debug key i will get null,both in your and my sample project,when i integrate it in my released app,and use the custom-signed keystore ,i get a right result . – dx3906 Nov 25 '15 at 09:34
  • The debug key, you created as Google documentation? My sample project works with my debug key. Default pass is android. – BNK Nov 25 '15 at 09:37
  • it was caused by sha1 dismatch,google doc gives the shell code is the sha1 of %USERPROFILE%\.android\debug.keystore,and mydefalut key is %ANDROID_SDK_HOME%\.android\debug.keystore.see the second answer here http://stackoverflow.com/questions/16622528/android-studio-debug-keystore – dx3906 Nov 26 '15 at 06:27
  • 1
    yes ,in developer's console i register the sha1 of %USERPROFILE%\.android\debug.keystore,but when build AS uses %ANDROID_SDK_HOME%\.android\debug.keystore,the dismatch caused getPerson return null . – dx3906 Nov 26 '15 at 07:01
  • hey @BNK suppose one user has account on google but not on google plus then accdng to you what will happen ?? – aman verma Nov 26 '15 at 09:29
  • @amanverma: I met that case, the app will crash with some meaningful information, you need try-catch exception – BNK Nov 26 '15 at 09:30
  • just tell me one more thing that the file you send me in that you are using only one api that is plus but here in your answer you are using both api now can you tell me which is correct ????? – aman verma Nov 26 '15 at 11:35
  • @amanverma: The file I sent you? Which file? I don't send you any file, but the link to my sample project in GitHub – BNK Nov 26 '15 at 11:53
  • sorry can u write here your github link ?? – aman verma Nov 26 '15 at 11:57
  • nah its not working when i am signin in onactivity result it is returning -1 as result code ?? – aman verma Nov 26 '15 at 12:43
  • @amanverma You must update with your application Id and google-services.json file as Google's guide. – BNK Nov 26 '15 at 13:02
  • can ou pls tell me how can i do that and what do u men by ap_id u mean sha1 or what also i am using android studio?? – aman verma Nov 26 '15 at 13:06
  • nah stil not working getting -1 as resultcode i have added google-services.json by d way what is app_id ?? – aman verma Nov 26 '15 at 13:26
  • @amanverma In your question, you said your app work well with google signin, so you know what app id is. Now, you only need to update you working app with my code in MainActivity.java. If still not working, post your app to github or google drive, I'll check tomorrow – BNK Nov 26 '15 at 13:33
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/96261/discussion-between-aman-verma-and-bnk). – aman verma Nov 26 '15 at 14:08
  • hey can you please tell me what is app name in here https://developers.google.com/mobile/add?platform=android&cntapi=gcm&cntapp=Default%20Demo%20App&cntpkg=gcm.play.android.samples.com.gcmquickstart&cnturl=https:%2F%2Fdevelopers.google.com%2Fcloud-messaging%2Fandroid%2Fstart%3Fconfigured%3Dtrue&cntlbl=Continue%20with%20Try%20Cloud%20Messaging – aman verma Dec 20 '15 at 11:41
  • also in google-services.json do i have to edit something like api key and all and if yes then where please tell me ?? – aman verma Dec 20 '15 at 11:42
  • @amanverma app name you can set anything, only pay attention to `Android package name`, which must be the same as `applicationId` in `build.gradle` file, and `package` in AndroidManifest.xml, for example in my sample project you will find `applicationId "com.example.googlesignindemo"` and ``. Don't edit google-services.json – BNK Dec 20 '15 at 12:55
  • @amanverma I suggest that you upload your full project to google drive or github...so that tomorrow morning I'll check more. – BNK Dec 21 '15 at 15:23
  • `Plus.PeopleApi.getCurrentPerson( gac )` is deprecated now... any solution? – injecteer Jan 21 '16 at 00:03
  • @injecteer I think you can find a solution at this link http://stackoverflow.com/questions/34412157/plus-peopleapi-getcurrentperson-deprecated-in-play-services-8-4-how-to-get-user – BNK Jan 21 '16 at 01:48
  • but not all users have google plus so it can bring null right? – Nasz Njoka Sr. Feb 01 '16 at 10:50
  • @NaszNjokaSr. I think so, you can give it a try :) – BNK Feb 01 '16 at 14:33
  • 1
    @suku see my project at Github, pay attention at "if (mGoogleApiClient.hasConnectedApi..." and "if (person != null)" – BNK Apr 03 '16 at 02:44
  • 1
    thanks!! I missed the `.requestScopes(new Scope(Scopes.PLUS_LOGIN))` thats why I always got 0 for gender. – Beeing Jk Jul 15 '16 at 06:51
  • Whats is TAG? I have in Red – Nicolas Schmidt Jul 18 '16 at 20:20
  • @NicolasSchmidt it's a string, for example TAG="MyAndroid" :) – BNK Jul 18 '16 at 23:30
  • @NicolasSchmidt it's just a string type variable. You can use Log.i("MyAndroid","Your message content"); instead – BNK Jul 19 '16 at 00:16
  • This method deprecated! – Ram Suthakar Nov 20 '18 at 08:05
10

The Plus people stuff is deprecated, don't use it anymore. The way to do this is with the Google People API Enable this API in your project. If you don't, the exception thrown in Studio includes a link directly to your project to enable it (nice).

Include the following dependencies in your app's build.gradle:

compile 'com.google.api-client:google-api-client:1.22.0'
compile 'com.google.api-client:google-api-client-android:1.22.0'
compile 'com.google.apis:google-api-services-people:v1-rev4-1.22.0'

Do an authorized GoogleSignIn like normal. It doesn't need any Scopes or Api's other than the basic account ones e.g.

GoogleSignInOptions.DEFAULT_SIGN_IN

.addApi(Auth.GOOGLE_SIGN_IN_API, gso)

and requests for email and profile is all you need.

Now, once you have a successful signin result, you can get the account, including the email (could maybe do this with the id too).

final GoogleSignInAccount acct = googleSignInResult.getSignInAccount();

Now the new part: Create and execute an AsyncTask to call the Google People API after you get the acct email.

// get Cover Photo Asynchronously
new GetCoverPhotoAsyncTask().execute(Prefs.getPersonEmail());

Here is the AsyncTask:

// Retrieve and save the url to the users Cover photo if they have one
private class GetCoverPhotoAsyncTask extends AsyncTask<String, Void, Void> {
    HttpTransport httpTransport = new NetHttpTransport();
    JacksonFactory jsonFactory = new JacksonFactory();

    // Retrieved from the sigin result of an authorized GoogleSignIn
    String personEmail;

    @Override
    protected Void doInBackground(String... params) {
        personEmail = params[0];
        Person userProfile = null;
        Collection<String> scopes = new ArrayList<>(Collections.singletonList(Scopes.PROFILE));

        GoogleAccountCredential credential =
                GoogleAccountCredential.usingOAuth2(SignInActivity.this, scopes);
        credential.setSelectedAccount(new Account(personEmail, "com.google"));

        People service = new People.Builder(httpTransport, jsonFactory, credential)
                .setApplicationName(getString(R.string.app_name)) // your app name
                .build();

        // Get info. on user
        try {
            userProfile = service.people().get("people/me").execute();
        } catch (IOException e) {
            Log.e(TAG, e.getMessage(), e);
        }

        // Get whatever you want
        if (userProfile != null) {
            List<CoverPhoto> covers = userProfile.getCoverPhotos();
            if (covers != null && covers.size() > 0) {
                CoverPhoto cover = covers.get(0);
                if (cover != null) {
                    // save url to cover photo here, load at will
                    //Prefs.setPersonCoverPhoto(cover.getUrl());
                }
            }
        }

        return null;
    }
}

Here is the stuff that is available from the Person

If you paste the code into your project, make sure the imports get resolved correctly. There are overlapping Class Names with some of the older API's.

Michael Updike
  • 644
  • 1
  • 6
  • 13
3

After login, do:

 Plus.PeopleApi.load(mGoogleApiClient, acct.getId()).setResultCallback(new ResultCallback<People.LoadPeopleResult>() {
        @Override
        public void onResult(@NonNull People.LoadPeopleResult loadPeopleResult) {
            Person person = loadPeopleResult.getPersonBuffer().get(0);

            LogUtil.d("googleuser: getGivenName " + (person.getName().getGivenName()));
            LogUtil.d("googleuser: getFamilyName " + (person.getName().getFamilyName()));
            LogUtil.d("googleuser: getDisplayName " + (person.getDisplayName()));
            LogUtil.d("googleuser: getGender " + (person.getGender() + ""));
            LogUtil.d("googleuser: getBirthday " + (person.getBirthday() + ""));
        }
    });
Frank
  • 12,010
  • 8
  • 61
  • 78
2

Create the google signin options like below. This works perfect for me

GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestEmail()
            .requestProfile()
            .requestScopes(new Scope(Scopes.PLUS_ME))
            .requestScopes(new Scope(Scopes.PLUS_LOGIN))
            .build();
Jiju Induchoodan
  • 4,236
  • 1
  • 22
  • 24
0

I spent some time to find a solution so let me share current way to achieve it.

You need to extend Google Sign in options like this:

GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestIdToken(getString(R.string.google_client_id)) //like: '9241xyz.apps.googleusercontent.com'
            .requestEmail()
            .requestProfile()
            .requestServerAuthCode(getString(R.string.google_client_id))
            .build();

Then in response you receive GoogleSignInResult object with GoogleSignInAccount. You extract both token id and auth code from it.

private void handleGoogleSignInResult(GoogleSignInResult result) {
    if (result.isSuccess()) {
        GoogleSignInAccount acct = result.getSignInAccount();
        String authCode = acct.getServerAuthCode();
        String idToken = acct.getIdToken();
    }
}

What you need to do next is to get access_token with POST request:

POST https://www.googleapis.com/oauth2/v4/token
Body (x-www-form-urlencoded):
grant_type authorization_code
client_id 9241xyz.apps.googleusercontent.com
client_secret MNw...fMO
redirect_uri ""
code auth_code_from_google_account
id_token id_token_from_google_account

Request can be done in Android app, but I recommend to do it on server side as it's not safe to keep client_secret in Android app. But it's up to you. Response for such request looks like this:

{
"access_token": "ya29.GluIBuHTXZ...kTglmCceBG",
"expires_in": 3552,
"scope": "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/plus.me",
"token_type": "Bearer",
"id_token": "eyJhbGciOiJSUzI1NiIsImt....V6EAlQd3-Y9CQ"
}

Then you can query user profile endpoint for user details:

GET https://www.googleapis.com/oauth2/v3/userinfo
Headers:
Authorization : Bearer ya29.GluIBuHTXZ...kTglmCceBG

Response looks like this:

{
"sub": "107...72",
"name": "Johny Big",
"given_name": "Johny",
"family_name": "Big",
"profile": "https://plus.google.com/107417...990272",
"picture": "https://lh3.googleusercontent.com/-....IxRQ/mo/photo.jpg",
"email": "johny.biggy.test@gmail.com",
"email_verified": true,
"gender" : "male",
"locale": "en"
}

However, if user doesn't have public access to info about him, gender field might be missing here. Probably you need to ask for additional scope in Google Sign in request, but I didn't check. (sharing options are under Google account page: https://myaccount.google.com/personal-info)

pkleczko
  • 807
  • 9
  • 6