Google+ Platform for Android

Google+ Sign-in for Android

Allow users to securely sign in to your app and create a more powerful and engaging experience. Google+ Sign-in also lets you grow your app engagement by letting your signed-in users create interactive posts to invite their friends to use your app. By connecting your users with Google, you will soon be able to influence your appearance in Google Play through trusted social recommendations that show your users their friends who are already using your app.

The Google+ Sign-In button authenticates the user and manages the OAuth 2.0 flow, which simplifies your integration with the Google APIs. Signing in is required for your app to create interactive posts, manage moments, and fetch profile and people information.

A user always has the option to revoke access to an application at any time.

Before you begin

You must create a Google APIs Console project and initialize the GoogleApiClient object.

Add the Google+ Sign-In button to your app

  1. Add the SignInButton in your application's layout:

    <com.google.android.gms.common.SignInButton
        android:id="@+id/sign_in_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    
  2. In the Android activity, register your button's OnClickListener to sign in the user when clicked:

    findViewById(R.id.sign_in_button).setOnClickListener(this);
    
  3. To use the sign-in button you will need to modify your `Activity`'s sign-in flow. Instead of starting user interaction to resolve errors immediately when your `Activity` receives an `onConnectionFailed` callback, your `Activity` should wait for the user to click the sign-in button.

    /* Track whether the sign-in button has been clicked so that we know to resolve
     * all issues preventing sign-in without waiting.
     */
    private boolean mSignInClicked;
    
    /* Store the connection result from onConnectionFailed callbacks so that we can
     * resolve them when the user clicks sign-in.
     */
    private ConnectionResult mConnectionResult;
    
    /* A helper method to resolve the current ConnectionResult error. */
    private void resolveSignInError() {
      if (mConnectionResult.hasResolution()) {
        try {
          mIntentInProgress = true;
          startIntentSenderForResult(mConnectionResult.getIntentSender(),
              RC_SIGN_IN, null, 0, 0, 0);
        } catch (SendIntentException e) {
          // The intent was canceled before it was sent.  Return to the default
          // state and attempt to connect to get an updated ConnectionResult.
          mIntentInProgress = false;
          mGoogleApiClient.connect();
        }
      }
    }
    
    public void onConnectionFailed(ConnectionResult result) {
      if (!mIntentInProgress) {
        // Store the ConnectionResult so that we can use it later when the user clicks
        // 'sign-in'.
        mConnectionResult = result;
    
        if (mSignInClicked) {
          // The user has already clicked 'sign-in' so we attempt to resolve all
          // errors until the user is signed in, or they cancel.
          resolveSignInError();
        }
      }
    }
    
  4. After the user has clicked the sign-in button, you should set the mSignInClicked flag and the resolveSignInError helper to resolve any connection errors returned in onConnectionFailed. Possible connection errors include prompting the user to select an account, and granting access to your app.

    public void onClick(View view) {
      if (view.getId() == R.id.sign_in_button
        && !mGoogleApiClient.isConnecting()) {
        mSignInClicked = true;
        resolveSignInErrors();
      }
    }
    
  5. You should then reset the state of the flags when control returns to your `Activity` in `onActivityResult`.

    protected void onActivityResult(int requestCode, int responseCode, Intent intent) {
      if (requestCode == RC_SIGN_IN) {
        if (responseCode != RESULT_OK) {
          mSignInClicked = false;
        }
    
        mIntentInProgress == false;
    
        if (!mGoogleApiClient.isConnecting()) {
          mGoogleApiClient.connect();
        }
      }
    }
    
  6. When the user has successfully signed in, your onConnected handler will be called. At this point, you are able to retrieve the user’s account name or make authenticated requests.

    @Override
    public void onConnected(Bundle connectionHint) {
      mSignInClicked = false;
      Toast.makeText(this, "User is connected!", Toast.LENGTH_LONG).show();
    }
    

Requesting additional scopes

Your app can request additional scopes anytime after the initial scopes have been granted. In this case, only those additional scopes will appear in the user's consent screen. Your app should request all previously granted scopes with these additional scopes to ensure your app proceeds with all the access it expects.

To request additional scopes, you disconnect the previous GoogleApiClient, then connect a new GoogleApiClient with the expanded set of scopes. You will receive an onConnectionFailed callback with a ConnectionResult that can be resolved as above to show a consent dialog requesting the additional permissions that your app has not already been granted.

You might use this technique if you suspect users are avoiding sign-in because your consent screen is overwhelming new users, or if you think users are confused why they are being asked for certain permissions. In either case, you can delay the additional scopes and present them just before they are needed.

Cross-platform single sign on

When a user runs your app for the first time on the Android device, the GoogleApiClient.onConnect() method automatically checks if the user previously granted authorization to your app on another platform. This allows the user to be signed in to your app immediately, if your project clients are configured to meet the following requirements:

If the user signed in to your web app previously, then onConnect() automatically succeeds and onConnected() is invoked immediately. You can proceed to access Google APIs to retrieve the user’s info and bypass the need for the user to sign in to your app again.

Sign out the user

You can add a sign out button to your app. Create a button in your app to act as your sign out button. Attach an onClickListener to the button and configure the onClick method to disconnect the GoogleApiClient:

@Override
public void onClick(View view) {
  if (view.getId() == R.id.sign_out_button) {
    if (mGoogleApiClient.isConnected()) {
      Plus.AccountApi.clearDefaultAccount(mGoogleApiClient);
      mGoogleApiClient.disconnect();
      mGoogleApiClient.connect();
    }
  }
}

This code clears which account is connected to the app. To sign in again, the user would choose their account again.

Revoking access tokens and disconnecting the app

To comply with the terms of the Google+ developer policies, you must offer users that signed in with Google the ability to disconnect from your app. If the user deletes their account, you must delete the information that your app obtained from the Google APIs.

The following code shows a simple example of calling the GoogleApiClient.revokeAccessAndDisconnect method and responding to the onAccessRevoked event.

// Prior to disconnecting, run clearDefaultAccount().
Plus.AccountApi.clearDefaultAccount(mGoogleApiClient);
Plus.AccountApi.revokeAccessAndDisconnect(mGoogleApiClient)
    .setResultCallback(new ResultCallback<Status>() {

  onResult(Status status) {
    // mGoogleApiClient is now disconnected and access has been revoked.
    // Trigger app logic to comply with the developer policies
  }

});

In the onResult callback, you can respond to the event and trigger any appropriate logic in your app or your back-end code. For more information, see the deletion rules in the developer policies.

Customizing your sign-in button

You can design a custom sign-in button to fit with your app's designs. The com.google.android.gms.common.SignInButton class offers you the ability to change the color theme and the dimensions of the button. If you require additional customization, you can define a custom button:

  1. Review the branding guidelines and download icons and images to use in your button.

  2. Add the button to your application layout.

    <Button
       android:id="@+id/button"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_centerHorizontal="true"
       android:text="@string/common_signin_button_text_long" />
    

This example loads localized text from the SDK. You could also use getString(com.google.android.gms.R.string.common_signin_button_text_long) within your activity's onCreate method to get the label for the button text. However you implement your sign-in button, you must follow the branding guidelines.

Localization

The SDK provides localized strings for the com.google.android.gms.common.SignInButton button and these are automatically available to users of your app. To view a full list of languages, you can examine the following directory in the SDK: <android-sdk-folder>/extras/google/google_play_services/libproject/google-play-services_lib/res/. In that location, you will find directories named values-<langcode>.

Server-side access for your app

If you use GoogleApiClient.connect(), your app is authenticating the user on the client side only. The GoogleApiClient is able to access the Google APIs while the user is actively using your app. If you wish for your servers to be able to make Google API calls on behalf of users or while they are offline, your server requires an access token and a refresh token.

To obtain an access token and refresh token for your server, you can request a one-time authorization code that your server exchanges for these two tokens. You request the one-time code by using the GoogleAuthUtil.getToken() method and specifying a unique scope string that includes the OAuth 2.0 client ID of your server.

After you successfully connect the user, you can call GoogleAuthUtil.getToken() which gives you a string with the code.

In the following example, you would replace: + <server-client-id> with your server's OAuth 2.0 client ID. + <scope1> <scope2> with a space-delimited list of scopes. + <app-activity1> <app-activity2> with a space-delimited list of app activity types.

Bundle appActivities = new Bundle();
appActivities.putString(GoogleAuthUtil.KEY_REQUEST_VISIBLE_ACTIVITIES,
          "<app-activity1> <app-activity2>");
String scopes = "oauth2:server:client_id:<server client-id>:api_scope:<scope1> <scope2>";
String code = null;
try {
  code = GoogleAuthUtil.getToken(
      this,                                              // Context context
      Plus.AccountApi.getAccountName(mGoogleApiClient),  // String accountName
      scopes,                                            // String scope
      appActivities                                      // Bundle bundle
  );

} catch (IOException transientEx) {
  // network or server error, the call is expected to succeed if you try again later.
  // Don't attempt to call again immediately - the request is likely to
  // fail, you'll hit quotas or back-off.
  ...
  return;
} catch (UserRecoverableAuthException e) {
  // Requesting an authorization code will always throw
  // UserRecoverableAuthException on the first call to GoogleAuthUtil.getToken
  // because the user must consent to offline access to their data.  After
  // consent is granted control is returned to your activity in onActivityResult
  // and the second call to GoogleAuthUtil.getToken will succeed.
  startActivityForResult(e.getIntent(), AUTH_CODE_REQUEST_CODE);
  return;
} catch (GoogleAuthException authEx) {
  // Failure. The call is not expected to ever succeed so it should not be
  // retried.
  ...
  return;
} catch (Exception e) {
  throw new RuntimeException(e);
}

After you obtain the one-time authorization, send it to your server to immediately exchange for the server's access and refresh tokens. This process at this point is similar to the process for web clients. Your server can then use the Google API Client libraries to exchange the one-time authorization code and then store the tokens. This one-time use code increases the security over a standard OAuth 2.0 flow; however, you need to exchange it for the tokens immediately to ensure the security of the tokens. You should send the one-time authorization code as securely as possible: use HTTPs and send it as POST data or in the request headers.

If you do not require offline access, you can retrieve the access token and send it to your server over a secure connection. You can obtain the access token directly using GoogleAuthUtil.getToken() by specifying the scopes without your server's OAuth 2.0 client ID. For example:

String accessToken = null;
try {
  accessToken = GoogleAuthUtil.getToken(this,
      Plus.AccountApi.getAccountName(mGoogleApiClient),
      "oauth2:" + TextUtils.join(' ', SCOPES));
} catch (IOException transientEx) {
  // network or server error, the call is expected to succeed if you try again later.
  // Don't attempt to call again immediately - the request is likely to
  // fail, you'll hit quotas or back-off.
  ...
  return;
} catch (UserRecoverableAuthException e) {
  // Recover
  accessToken = null;
} catch (GoogleAuthException authEx) {
  // Failure. The call is not expected to ever succeed so it should not be
  // retried.
  return;
} catch (Exception e) {
  throw new RuntimeException(e);
}

To learn more, see:

Next steps

Authentication required

You need to be signed in with Google+ to do that.

Signing you in...

Google Developers needs your permission to do that.