How to get profile like gender from google signin in Android?

后端 未结 5 2409
臣服心动
臣服心动 2020-11-27 16:34

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

相关标签:
5条回答
  • 2020-11-27 16:42

    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!

    0 讨论(0)
  • 2020-11-27 16:48

    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.

    0 讨论(0)
  • 2020-11-27 16:51

    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)

    0 讨论(0)
  • 2020-11-27 16:59

    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() + ""));
            }
        });
    
    0 讨论(0)
  • 2020-11-27 16:59

    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();
    
    0 讨论(0)
提交回复
热议问题