21 Kasım 2017
The release of version 11.6.0 of the Google Play services SDK moves a number of popular APIs to a new paradigm for accessing Google APIs on Android. We have reworked the APIs to reduce boilerplate, improve UX, and simplify authentication and authorization.
The primary change in this release is the introduction of new Task
and GoogleApi
based APIs to replace the GoogleApiClient access pattern.
The following APIs are newly updated to eliminate the use of
GoogleApiClient:
These APIs join others that made the switch in previous releases, such as the Awareness, Cast, Places, Location, and Wallet APIs.
Here is a simple Activity that demonstrates how one would access the Google
Drive API using GoogleApiClient using a previous version of the
Play services SDK:
public class MyActivity extends AppCompatActivity implements
GoogleApiClient.OnConnectionFailedListener,
GoogleApiClient.ConnectionCallbacks {
private static final int RC_SIGN_IN = 9001;
private GoogleApiClient mGoogleApiClient;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GoogleSignInOptions options =
new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestScopes(Drive.SCOPE_FILE)
.build();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this, this)
.addConnectionCallbacks(this)
.addApi(Auth.GOOGLE_SIGN_IN_API, options)
.addApi(Drive.API)
.build();
}
// ...
// Not shown: code to handle sign in flow
// ...
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
// GoogleApiClient connection failed, most API calls will not work...
}
@Override
public void onConnected(@Nullable Bundle bundle) {
// GoogleApiClient is connected, API calls should succeed...
}
@Override
public void onConnectionSuspended(int i) {
// ...
}
private void createDriveFile() {
// If this method is called before "onConnected" then the app will crash,
// so the developer has to manage multiple callbacks to make this simple
// Drive API call.
Drive.DriveApi.newDriveContents(mGoogleApiClient)
.setResultCallback(new ResultCallback<DriveApi.DriveContentsResult>() {
// ...
});
}
}
The code is dominated by the concept of a connection, despite using the
simplified "automanage" feature. A GoogleApiClient is only
connected when all APIs are available and the user has signed in (when APIs
require it).
This model has a number of pitfalls:
GoogleApiClient objects is unwieldy.
onConnected is called will result in a crash.
GoogleApiClient is connected and another for the API call
itself.
Over the years the need to replace GoogleApiClient became apparent,
so we set out to completely abstract the "connection" process and make it easier
to access individual Google APIs without boilerplate.
Rather than tacking multiple APIs onto a single API client, each API now has a
purpose-built client object class that extends GoogleApi. Unlike
with GoogleApiClient there is no performance cost to creating many
client objects. Each of these client objects abstracts the connection logic,
connections are automatically managed by the SDK in a way that maximizes both
speed and efficiency.
When using GoogleApiClient, authentication was part of the
"connection" flow. Now that you no longer need to manage connections, you
should use the new GoogleSignInClient class to initiate
authentication:
public class MyNewActivity extends AppCompatActivity {
private static final int RC_SIGN_IN = 9001;
private GoogleSignInClient mSignInClient;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GoogleSignInOptions options =
new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestScopes(Drive.SCOPE_FILE)
.build();
mSignInClient = GoogleSignIn.getClient(this, options);
}
private void signIn() {
// Launches the sign in flow, the result is returned in onActivityResult
Intent intent = mSignInClient.getSignInIntent();
startActivityForResult(intent, RC_SIGN_IN);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RC_SIGN_IN) {
Task<GoogleSignInAccount> task =
GoogleSignIn.getSignedInAccountFromIntent(data);
if (task.isSuccessful()) {
// Sign in succeeded, proceed with account
GoogleSignInAccount acct = task.getResult();
} else {
// Sign in failed, handle failure and update UI
// ...
}
}
}
}
Making API calls to authenticated APIs is now much simpler and does not require waiting for multiple callbacks.
private void createDriveFile() {
// Get currently signed in account (or null)
GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(this);
// Synchronously check for necessary permissions
if (!GoogleSignIn.hasPermissions(account, Drive.SCOPE_FILE)) {
// Note: this launches a sign-in flow, however the code to detect
// the result of the sign-in flow and retry the API call is not
// shown here.
GoogleSignIn.requestPermissions(this, RC_DRIVE_PERMS,
account, Drive.SCOPE_FILE);
return;
}
DriveResourceClient client = Drive.getDriveResourceClient(this, account);
client.createContents()
.addOnCompleteListener(new OnCompleteListener<DriveContents>() {
@Override
public void onComplete(@NonNull Task<DriveContents> task) {
// ...
}
});
}
Before making the API call we add an inline check to make sure that we have signed in and that the sign in process granted the scopes we require.
The call to createContents() is simple, but it's actually taking
care of a lot of complex behavior. If the connection to Play services has not
yet been established, the call is queued until there is a connection. This is in
contrast to the old behavior where calls would fail or crash if made before
connecting.
In general, the new GoogleApi-based APIs have the following
benefits:
GoogleSignInAccount which makes it easier to use authenticated APIs
throughout your app.
Task API rather than
PendingResult, which allows for easier management and
chaining.These new APIs will improve your development process and enable you to make better apps.
Ready to get started with the new Google Play services SDK?
Happy building!