am a2739fa7: am a4c5bba0: add document about GoogleApiClient and one about GoogleAuthUtil also remove the Authorization document from the Google Services section. bug:10679818

* commit 'a2739fa795981f597b044e93a5c552051cfe1c00':
  add document about GoogleApiClient and one about GoogleAuthUtil also remove the Authorization document from the Google Services section. bug:10679818
This commit is contained in:
Scott Main
2014-02-12 17:03:26 +00:00
committed by Android Git Automerger
7 changed files with 1107 additions and 73 deletions

Binary file not shown.

View File

@ -0,0 +1,536 @@
page.title=Accessing Google Play Services APIs
page.tags="oauth 2.0","GoogleAuthUtil"
trainingnavtop=true
startpage=true
@jd:body
<div id="qv-wrapper">
<div id="qv">
<h2>In this document</h2>
<ol>
<li><a href="#Starting">Start a Connection</a>
<ol>
<li><a href="#HandlingFailures">Handle connection failures</a></li>
<li><a href="#MaintainingState">Maintain state while resolving an error</a></li>
</ol>
</li>
<li><a href="#Communicating">Communicate with Google Services</a>
<ol>
<li><a href="#Async">Using asynchronous calls</a></li>
<li><a href="#Sync">Using synchronous calls</a></li>
</ol>
</li>
</ol>
</div>
</div>
<p>When you want to make a connection to one of the Google APIs provided in the Google Play services
library (such as Google+, Games, or Drive), you need to create an instance of <a
href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html">{@code
GoogleApiClient}</a> ("Google API Client"). The Google API Client provides a common entry point to all
the Google Play services and manages the network connection between the user's device and each
Google service.</p>
<div class="sidebox" style="clear:right;width:190px">
<h2>Connecting to REST APIs</h2>
<p>If the Google API you want to use is not included in the Google Play services library, you can
connect using the appropriate REST API, but you must obtain an OAuth 2.0 token. For more
information, read <a href="{@docRoot}google/auth/http-auth.html">Authorizing with Google
for REST APIs</a>.</p>
</div>
<p>This guide shows how you can use Google API Client to:</p>
<ul>
<li>Connect to one or more Google Play services asynchronously and handle failures.</li>
<li>Perform synchronous and asynchronous API calls to any of the Google Play services.</li>
</ul>
<p class="note">
<strong>Note:</strong> If you have an existing app that connects to Google Play services with a
subclass of <a
href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.html">{@code GooglePlayServicesClient}</a>, you should migrate to <a
href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html">{@code
GoogleApiClient}</a> as soon as possible.</p>
<img src="{@docRoot}images/google/GoogleApiClient@2x.png" width="464px" alt="" />
<p class="img-caption">
<strong>Figure 1.</strong> An illustration showing how the Google API Client provides an
interface for connecting and making calls to any of the available Google Play services such as
Google Play Games and Google Drive.</p>
<p>To get started, you must first install the Google Play services library (revision 15 or higher) for
your Android SDK. If you haven't done so already, follow the instructions in <a
href="{@docRoot}google/play-services/setup.html">Set Up Google
Play Services SDK</a>.</p>
<h2 id="Starting">Start a Connection</h2>
<p>Once your project is linked to the Google Play services library, create an instance of <a
href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html">{@code
GoogleApiClient}</a> using the <a
href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.Builder.html">{@code
GoogleApiClient.Builder}</a> APIs in your activity's {@link
android.app.Activity#onCreate onCreate()} method. The <a
href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.Builder.html">{@code
GoogleApiClient.Builder}</a> class
provides methods that allow you to specify the Google APIs you want to use and your desired OAuth
2.0 scopes. For example, here's a <a
href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html">{@code
GoogleApiClient}</a> instance that connects with the Google
Drive service:</p>
<pre>
GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Drive.API)
.addScope(Drive.SCOPE_FILE)
.build();
</pre>
<p>You can add multiple APIs and multiple scopes to the same <a
href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html">{@code
GoogleApiClient}</a> by appending
additional calls to
<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.Builder.html#addApi(com.google.android.gms.common.api.Api)"
>{@code addApi()}</a> and
<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.Builder.html#addScope(com.google.android.gms.common.api.Scope)"
>{@code addScope()}</a>.</p>
<p>However, before you can begin a connection by calling <a
href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html#connect()"
>{@code connect()}</a> on the <a
href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html">{@code
GoogleApiClient}</a>, you must specify an implementation for the callback interfaces, <a
href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html"
>{@code ConnectionCallbacks}</a> and <a
href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.OnConnectionFailedListener.html"
>{@code onConnectionFailedListener}</a>. These interfaces receive callbacks in
response to the asynchronous <a
href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html#connect()"
>{@code connect()}</a> method when the connection to Google Play services
succeeds, fails, or becomes suspended.</p>
<p>For example, here's an activity that implements the callback interfaces and adds them to the Google
API Client:</p>
<pre>
import gms.common.api.*;
import gms.drive.*;
import android.support.v4.app.FragmentActivity;
public class MyActivity extends FragmentActivity
implements ConnectionCallbacks, OnConnectionFailedListener {
private GoogleApiClient mGoogleApiClient;
&#64;Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Create a GoogleApiClient instance
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Drive.API)
.addScope(Drive.SCOPE_FILE)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
...
}
&#64;Override
public void onConnected(Bundle connectionHint) {
// Connected to Google Play services!
// The good stuff goes here.
}
&#64;Override
public void onConnectionSuspended(int cause) {
// The connection has been interrupted.
// Disable any UI components that depend on Google APIs
// until onConnected() is called.
}
&#64;Override
public void onConnectionFailed(ConnectionResult result) {
// This callback is important for handling errors that
// may occur while attempting to connect with Google.
//
// More about this in the next section.
...
}
}
</pre>
<p>With the callback interfaces defined, you're ready to call <a
href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html#connect()"
>{@code connect()}</a>. To gracefully manage
the lifecycle of the connection, you should call <a
href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html#connect()"
>{@code connect()}</a> during the activity's {@link
android.app.Activity#onStart onStart()} (unless you want to connect later), then call <a
href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html#disconnect()"
>{@code disconnect()}</a> during the {@link android.app.Activity#onStop onStop()} method. For example:</p>
<pre>
&#64;Override
protected void onStart() {
super.onStart();
if (!mResolvingError) { // more about this later
mGoogleApiClient.connect();
}
}
&#64;Override
protected void onStop() {
mGoogleApiClient.disconnect();
super.onStop();
}
</pre>
<p>However, if you run this code, there's a good chance it will fail and your app will receive a call
to <a
href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html#onConnectionFailed(com.google.android.gms.common.ConnectionResult)"
>{@code onConnectionFailed()}</a> with the <a
href="{@docRoot}reference/com/google/android/gms/common/ConnectionResult.html#SIGN_IN_REQUIRED"
>{@code SIGN_IN_REQUIRED}</a> error because the user account
has not been specified. The next section shows how to handle this error and others.</p>
<h3 id="HandlingFailures">Handle connection failures</h3>
<p>When you receive a call to the <a
href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html#onConnectionFailed(com.google.android.gms.common.ConnectionResult)"
>{@code onConnectionFailed()}</a> callback, you should call <a
href="{@docRoot}reference/com/google/android/gms/common/ConnectionResult.html#hasResolution()"
>{@code hasResolution()}</a> on the provided <a
href="{@docRoot}reference/com/google/android/gms/common/ConnectionResult.html"
>{@code ConnectionResult}</a> object. If it returns true, you can
request the user take immediate action to resolve the error by calling <a
href="{@docRoot}reference/com/google/android/gms/common/ConnectionResult.html#startResolutionForResult(android.app.Activity, int)">{@code startResolutionForResult()}</a> on the <a
href="{@docRoot}reference/com/google/android/gms/common/ConnectionResult.html"
>{@code ConnectionResult}</a> object. The <a
href="{@docRoot}reference/com/google/android/gms/common/ConnectionResult.html#startResolutionForResult(android.app.Activity, int)"
>{@code startResolutionForResult()}</a> behaves the same as {@link
android.app.Activity#startActivityForResult startActivityForResult()} and launches the
appropriate activity for the user
to resolve the error (such as an activity to select an account).</p>
<p>If <a
href="{@docRoot}reference/com/google/android/gms/common/ConnectionResult.html#hasResolution()"
>{@code hasResolution()}</a> returns false, you should instead call <a
href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesUtil.html#getErrorDialog(int, android.app.Activity, int)"
>{@code GooglePlayServicesUtil.getErrorDialog()}</a>, passing it the error code. This returns a {@link
android.app.Dialog} provided by Google Play services that's appropriate for the given error. The
dialog may simply provide a message explaining the error, but it may also provide an action to
launch an activity that can resolve the error (such as when the user needs to install a newer
version of Google Play services).</p>
<p>For example, your <a
href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html#onConnectionFailed(com.google.android.gms.common.ConnectionResult)"
>{@code onConnectionFailed()}</a> callback method should now look like this:</p>
<pre>
public class MyActivity extends FragmentActivity
implements ConnectionCallbacks, OnConnectionFailedListener {
// Request code to use when launching the resolution activity
private static final int REQUEST_RESOLVE_ERROR = 1001;
// Unique tag for the error dialog fragment
private static final String DIALOG_ERROR = "dialog_error";
// Bool to track whether the app is already resolving an error
private boolean mResolvingError = false;
...
&#64;Override
public void onConnectionFailed(ConnectionResult result) {
if (mResolvingError) {
// Already attempting to resolve an error.
return;
} else if (result.hasResolution()) {
try {
mResolvingError = true;
result.startResolutionForResult(this, REQUEST_RESOLVE_ERROR);
} catch (SendIntentException e) {
// There was an error with the resolution intent. Try again.
mGoogleApiClient.connect();
}
} else {
// Show dialog using GooglePlayServicesUtil.getErrorDialog()
showErrorDialog(result.getErrorCode());
mResolvingError = true;
}
}
// The rest of this code is all about building the error dialog
/* Creates a dialog for an error message */
private void showErrorDialog(int errorCode) {
// Create a fragment for the error dialog
ErrorDialogFragment dialogFragment = new ErrorDialogFragment();
// Pass the error that should be displayed
Bundle args = new Bundle();
args.putInt(DIALOG_ERROR, errorCode);
dialogFragment.setArguments(args);
dialogFragment.show(getSupportFragmentManager(), "errordialog");
}
/* Called from ErrorDialogFragment when the dialog is dismissed. */
public void onDialogDismissed() {
mResolvingError = false;
}
/* A fragment to display an error dialog */
public static class ErrorDialogFragment extends DialogFragment {
public ErrorDialogFragment() { }
&#64;Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Get the error code and retrieve the appropriate dialog
int errorCode = this.getArguments().getInt(DIALOG_ERROR);
return GooglePlayServicesUtil.getErrorDialog(errorCode,
this.getActivity(), REQUEST_RESOLVE_ERROR);
}
&#64;Override
public void onDismiss(DialogInterface dialog) {
((MainActivity)getActivity()).onDialogDismissed();
}
}
}
</pre>
<p>Once the user completes the resolution provided by <a
href="{@docRoot}reference/com/google/android/gms/common/ConnectionResult.html#startResolutionForResult(android.app.Activity, int)"
>{@code startResolutionForResult()}</a> or <a
href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesUtil.html#getErrorDialog(int, android.app.Activity, int)"
>{@code GooglePlayServicesUtil.getErrorDialog()}</a>, your activity receives the {@link
android.app.Activity#onActivityResult onActivityResult()} callback with the {@link
android.app.Activity#RESULT_OK}
result code. You can then call <a
href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html#connect()"
>{@code connect()}</a> again. For example:</p>
<pre>
&#64;Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_RESOLVE_ERROR) {
mResolvingError = false;
if (resultCode == RESULT_OK) {
// Make sure the app is not already connected or attempting to connect
if (!mGoogleApiClient.isConnecting() &&
!mGoogleApiClient.isConnected()) {
mGoogleApiClient.connect();
}
}
}
}
</pre>
<p>In the above code, you probably noticed the boolean, {@code mResolvingError}. This keeps track of
the app state while the user is resolving the error to avoid repetitive attempts to resolve the
same error. For instance, while the account picker dialog is showing to resolve the <a
href="{@docRoot}reference/com/google/android/gms/common/ConnectionResult.html#SIGN_IN_REQUIRED"
>{@code SIGN_IN_REQUIRED}</a> error, the user may rotate the screen. This recreates your activity and causes
your {@link android.app.Activity#onStart onStart()} method to be called again, which then calls <a
href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html#connect()"
>{@code connect()}</a> again. This results in another call to <a
href="{@docRoot}reference/com/google/android/gms/common/ConnectionResult.html#startResolutionForResult(android.app.Activity, int)"
>{@code startResolutionForResult()}</a>, which
creates another account picker dialog in front of the existing one.</p>
<p>This boolean is effective only
if retained across activity instances, though. The next section explains further.</p>
<h3 id="MaintainingState">Maintain state while resolving an error</h3>
<p>To avoid executing the code in <a
href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html#onConnectionFailed(com.google.android.gms.common.ConnectionResult)"
>{@code onConnectionFailed()}</a> while a previous attempt to resolve an
error is ongoing, you need to retain a boolean that tracks whether your app is already attempting
to resolve an error.</p>
<p>As shown in the code above, you should set a boolean to {@code true} each time you call <a
href="{@docRoot}reference/com/google/android/gms/common/ConnectionResult.html#startResolutionForResult(android.app.Activity, int)"
>{@code startResolutionForResult()}</a> or display the dialog from <a
href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesUtil.html#getErrorDialog(int, android.app.Activity, int)"
>{@code GooglePlayServicesUtil.getErrorDialog()}</a>. Then when you
receive {@link android.app.Activity#RESULT_OK} in the {@link android.app.Activity#onActivityResult
onActivityResult()} callback, set the boolean to {@code false}.</p>
<p>To keep track of the boolean across activity restarts (such as when the user rotates the screen),
save the boolean in the activity's saved instance data using {@link
android.app.Activity#onSaveInstanceState onSaveInstanceState()}:</p>
<pre>
private static final String STATE_RESOLVING_ERROR = "resolving_error";
&#64;Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(STATE_RESOLVING_ERROR, mResolvingError);
}
</pre>
<p>Then recover the saved state during {@link android.app.Activity#onCreate onCreate()}:</p>
<pre>
&#64;Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
mResolvingError = savedInstanceState != null
&& savedInstanceState.getBoolean(STATE_RESOLVING_ERROR, false);
}
</pre>
<p>Now you're ready to safely run your app and connect to Google Play services.
How you can perform read and write requests to any of the Google Play services
using <a
href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html">{@code
GoogleApiClient}</a> is discussed in the next section.</p>
<p>For more information about each services's APIs available once you're connected,
consult the corresponding documentation, such as for
<a href="{@docRoot}google/play-services/games.html">Google Play Games</a> or
<a href="{@docRoot}google/play-services/drive.html">Google Drive</a>.
</p>
<h2 id="Communicating">Communicate with Google Services</h2>
<p>Once connected, your client can make read and write calls using the service-specific APIs for which
your app is authorized, as specified by the APIs and scopes you added to your <a
href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html">{@code
GoogleApiClient}</a> instance.</p>
<p class="note">
<strong>Note:</strong> Before making calls to specific Google services, you may first need to
register your app in the Google Developer Console. For specific instructions, refer to the
appropriate getting started guide for the API you're using, such as <a href=
"https://developers.google.com/drive/android/get-started">Google Drive</a> or <a href=
"https://developers.google.com/+/mobile/android/getting-started">Google+</a>.</p>
<p>When you perform a read or write request using Google API Client, the immediate result is returned
as a <a href="{@docRoot}reference/com/google/android/gms/common/api/PendingResult.html">{@code
PendingResult}</a> object. This is an object representing the request, which hasn't yet
been delivered to the Google service.</p>
<p>For example, here's a request to read a file from Google Drive that provides a
<a href="{@docRoot}reference/com/google/android/gms/common/api/PendingResult.html">{@code
PendingResult}</a> object:</p>
<pre>
Query query = new Query.Builder()
.addFilter(Filters.eq(SearchableField.TITLE, filename));
PendingResult result = Drive.DriveApi.query(mGoogleApiClient, query);
</pre>
<p>Once you have the
<a href="{@docRoot}reference/com/google/android/gms/common/api/PendingResult.html">{@code
PendingResult}</a>, you can continue by making the request either asynchronous
or synchronous.</p>
<h3 id="Async">Using asynchronous calls</h3>
<p>To make the request asynchronous, call <a
href="{@docRoot}reference/com/google/android/gms/common/api/PendingResult.html#setResultCallback(com.google.android.gms.common.api.ResultCallback<R>)"
>{@code setResultCallback()}</a> on the
<a href="{@docRoot}reference/com/google/android/gms/common/api/PendingResult.html">{@code
PendingResult}</a> and
provide an implementation of the <a
href="{@docRoot}reference/com/google/android/gms/common/api/ResultCallback.html"
>{@code ResultCallback}</a> interface. For example, here's the request
executed asynchronously:</p>
<pre>
private void loadFile(String filename) {
// Create a query for a specific filename in Drive.
Query query = new Query.Builder()
.addFilter(Filters.eq(SearchableField.TITLE, filename))
.build();
// Invoke the query asynchronously with a callback method
Drive.DriveApi.query(mGoogleApiClient, query)
.setResultCallback(new ResultCallback&lt;DriveApi.MetadataBufferResult>() {
&#64;Override
public void onResult(DriveApi.MetadataBufferResult result) {
// Success! Handle the query result.
...
}
});
}
</pre>
<p>When your app receives a <a
href="{@docRoot}reference/com/google/android/gms/common/api/Result.html">{@code Result}</a>
object in the <a
href="{@docRoot}reference/com/google/android/gms/common/api/ResultCallback.html#onResult(R)"
>{@code onResult()}</a> callback, it is delivered as an instance of the
appropriate subclass as specified by the API you're using, such as <a
href="{@docRoot}reference/com/google/android/gms/drive/DriveApi.MetadataBufferResult.html"
>{@code DriveApi.MetadataBufferResult}</a>.</p>
<h3 id="Sync">Using synchronous calls</h3>
<p>If you want your code to execute in a strictly defined order, perhaps because the result of one
call is needed as an argument to another, you can make your request synchronous by calling <a
href="{@docRoot}reference/com/google/android/gms/common/api/PendingResult.html#await()"
>{@code await()}</a> on the
<a href="{@docRoot}reference/com/google/android/gms/common/api/PendingResult.html">{@code
PendingResult}</a>. This blocks the thread and returns the <a
href="{@docRoot}reference/com/google/android/gms/common/api/Result.html">{@code Result}</a> object
when the request completes, which is delivered as an instance of the
appropriate subclass as specified by the API you're using, such as <a
href="{@docRoot}reference/com/google/android/gms/drive/DriveApi.MetadataBufferResult.html"
>{@code DriveApi.MetadataBufferResult}</a>.</p>
<p>Because calling <a
href="{@docRoot}reference/com/google/android/gms/common/api/PendingResult.html#await()"
>{@code await()}</a> blocks the thread until the result arrives, it's important that you
never perform this call on the UI thread. So, if you want to perform synchronous requests to a
Google Play service, you should create a new thread, such as with {@link android.os.AsyncTask} in
which to perform the request. For example, here's how to perform the same file request to Google
Drive as a synchronous call:</p>
<pre>
private void loadFile(String filename) {
new GetFileTask().execute(filename);
}
private class GetFileTask extends AsyncTask<String, Void, Void> {
protected void doInBackground(String filename) {
Query query = new Query.Builder()
.addFilter(Filters.eq(SearchableField.TITLE, filename))
.build();
// Invoke the query synchronously
DriveApi.MetadataBufferResult result =
Drive.DriveApi.query(mGoogleApiClient, query).await();
// Continue doing other stuff synchronously
...
}
}
</pre>
<p class="note">
<strong>Tip:</strong> You can also enqueue read requests while not connected to Google Play
services. For example, execute a method to read a file from Google Drive regardless of whether your
Google API Client is connected yet. Then once a connection is established, the read requests
execute and you'll receive the results. Any write requests, however, will generate an error if you
call them while your Google API Client is not connected.</p>

View File

@ -0,0 +1,534 @@
page.title=Authorizing with Google for REST APIs
page.tags="oauth 2.0","GoogleAuthUtil"
trainingnavtop=true
startpage=true
@jd:body
<div id="qv-wrapper">
<div id="qv">
<h2>In this document</h2>
<ol>
<li><a href="#Register">Register Your App</a></li>
<li><a href="#AccountPicker">Invoke the Account Picker</a></li>
<li><a href="#AccountName">Retrieve the Account Name</a></li>
<li><a href="#ExtendAsyncTask">Extend AsyncTask to Get the Auth Token</a></li>
<li><a href="#HandleExceptions">Handle Exceptions</a></li>
</ol>
<h2>Try it out</h2>
<div class="download-box">
<a href="http://developer.android.com/shareables/training/GoogleAuth.zip"
class="button">Download the sample app</a>
<p class="filename">GoogleAuth.zip</p>
</div>
</div>
</div>
<p>When you want your Android app to access Google APIs using the user's Google account over
HTTP, the <a href=
"{@docRoot}reference/com/google/android/gms/auth/GoogleAuthUtil.html">{@code GoogleAuthUtil}</a>
class and related APIs provide your users a secure and consistent experience for picking an
account and retrieving an OAuth 2.0 token for your app.</p>
<p>You can then use that token in your HTTP-based communications with Google API services
that are not included in the <a href="{@docRoot}google/play-services/index.html">Google Play
services</a> library, such as the Blogger or Translate APIs.</p>
<p class="note"><strong>Note:</strong> An OAuth 2.0 token using <a href=
"{@docRoot}reference/com/google/android/gms/auth/GoogleAuthUtil.html">{@code GoogleAuthUtil}</a>
is required only for certain types of Google
APIs that you need to access over HTTP. If you're instead using the <a
href="{@docRoot}google/play-services/index.html">Google Play services library</a> to access Google
APIs such as <a href="{@docRoot}google/play-services/plus.html">Google+</a> or <a
href="{@docRoot}google/play-services/games.html">Play Games</a>, you don't need an OAuth 2.0
token and you can instead access these services using the {@code GoogleApiClient}. For more
information, read <a href="{@docRoot}google/auth/api-client.html">Accessing Google Play
Services APIs</a>.</p>
<p>To get started with <a href=
"{@docRoot}reference/com/google/android/gms/auth/GoogleAuthUtil.html">{@code GoogleAuthUtil}</a>
for accessing Google's REST APIs, you must set up your Android app project with the Google Play
services library. Follow the procedures in <a href=
"{@docRoot}google/play-services/setup.html">Setup Google Play Services SDK</a>.</p>
<h2 id="Register">Register Your App</h2>
<p>Before you can publish an app that retrieves an OAuth 2.0 token for Google REST APIs,
you must register your Android app with the Google Cloud Console by providing your app's
package name and the SHA1 fingerprint of the keystore with which you sign your release APK.</p>
<p class="caution"><strong>Caution:</strong> While you are testing an APK that's <a
href="{@docRoot}tools/publishing/app-signing.html#debugmode">signed with a
debug key</a>, Google does not require that your app be registered in Google Cloud Console. However,
your app must be registered in Google Cloud Console in order to continue working once it is
<a href="{@docRoot}tools/publishing/app-signing.html#releasemode">signed
with a release key</a>.</p>
<p>To register your Android app with Google Cloud Console:</p>
<ol>
<li>Visit <a href="https://cloud.google.com/console" class="external-link" target="_blank"
>Google Cloud Console</a>.
<li>If you have an existing project to which you're adding an Android app, select the project.
Otherwise, click <strong>Create project</strong> at the top, enter your project name and ID,
then click <strong>Create</strong>.
<p class="note"><strong>Note:</strong> The name you provide for the project is the name that
appears to users in the Google Settings app in the list of <em>Connected apps</em>.</p>
<li>In the left-side navigation, select <strong>APIs &amp; auth</strong>.
<li>Enable the API you'd like to use by setting the Status to <strong>ON</strong>.
<li>In the left-side navigation, select <strong>Credentials</strong>.
<li>Click <strong>Create new client ID</strong> or <strong>Create new key</strong>
as appropriate for your app.</li>
<li>Complete the form that appears by filling in your Android app details.
<p>To get the SHA1 fingerprint for your app, run the following command in a terminal:
<pre class="no-pretty-print">
keytool -exportcert -alias &lt;keystore_alias> -keystore &lt;keystore_path> -list -v
</pre>
<p>For example, you're using a debug-key with Eclipse, then the command looks like this:</p>
<pre class="no-pretty-print">
keytool -exportcert -alias androiddebugkey-keystore ~/.android/debug.keystore -list -v
</pre>
<p>Then the keystore password is "android".</p>
</li>
<li>Click <strong>Create</strong>.
</ol>
<p>The Credentials page then provides the available credentials such as an OAuth 2.0 client ID and
an Android Key, but you don't need these to authorize your Android users. Simply registering your
app with the package name and SHA1 makes the Google services accessible by your app.
<p>To acquire the OAuth 2.0 token that will grant you access to Google APIs over HTTP, you need to
first identify the user's Google account with which you'll query the servers. For this task, the
Google Play services library provides a convenient account picker dialog you can invoke using
<a href="{@docRoot}reference/com/google/android/gms/common/AccountPicker.html">{@code
AccountPicker}</a>. The result delivered to your activity from the account picker is the account
name you'll use to request the OAuth 2.0 token in the next lesson.</p>
<p class="note"><strong>Note:</strong> In order to use the APIs discussed here, you must
include the Google Play services library with your project. If you haven't set up your project
with the library yet, read the guide to <a
href="{@docRoot}google/play-services/setup.html">Setup Google Play Services SDK</a>.</p>
<h2 id="AccountPicker">Invoke the Account Picker</h2>
<p>To open the account picker dialog that's managed by the Google Play services library, call
{@link android.app.Activity#startActivityForResult startActivityForResult()} using an {@link
android.content.Intent} returned by <a href=
"{@docRoot}reference/com/google/android/gms/common/AccountPicker.html#newChooseAccountIntent(android.accounts.Account,%20java.util.ArrayList%3Candroid.accounts.Account%3E,%20java.lang.String[],%20boolean,%20java.lang.String,%20java.lang.String,%20java.lang.String[],%20android.os.Bundle)">
{@code AccountPicker.newChooseAccountIntent}</a>.</p>
<p>For example:</p>
<pre>
static final int REQUEST_CODE_PICK_ACCOUNT = 1000;
private void pickUserAccount() {
String[] accountTypes = new String[]{"com.google"};
Intent intent = AccountPicker.newChooseAccountIntent(null, null,
accountTypes, false, null, null, null, null);
startActivityForResult(intent, REQUEST_CODE_PICK_ACCOUNT);
}
</pre>
<p>When this code executes, a dialog appears for the user to pick an account. When the user
selects the account, your activity receives the result in the {@link
android.app.Activity#onActivityResult onActivityResult()} callback.</p>
<p>Most apps should pass the <a href=
"{@docRoot}reference/com/google/android/gms/common/AccountPicker.html#newChooseAccountIntent(android.accounts.Account,%20java.util.ArrayList%3Candroid.accounts.Account%3E,%20java.lang.String[],%20boolean,%20java.lang.String,%20java.lang.String,%20java.lang.String[],%20android.os.Bundle)">
{@code newChooseAccountIntent()}</a> method the same arguments shown in the above example,
which indicate that:</p>
<ul>
<li>There is no currently selected account.</li>
<li>There is no restricted list of accounts.</li>
<li>The dialog should list only accounts from the "com.google" domain.</li>
<li>Don't prompt the user to pick an account if there's only one available account (just use that
one). However, even if only one account currently exists, the dialog may include an option for the
user to add a new account.</li>
<li>There is no custom title for the dialog.</li>
<li>There is no specific auth token type required.</li>
<li>There are no restrictions based on account features.</li>
<li>There are no authenticator-specific options.</li>
</ul>
<p>For more details about these arguments, see the <a href=
"{@docRoot}reference/com/google/android/gms/common/AccountPicker.html#newChooseAccountIntent(android.accounts.Account,%20java.util.ArrayList%3Candroid.accounts.Account%3E,%20java.lang.String[],%20boolean,%20java.lang.String,%20java.lang.String,%20java.lang.String[],%20android.os.Bundle)">
{@code newChooseAccountIntent()}</a> method documentation.</p>
<h2 id="AccountName">Retrieve the Account Name</h2>
<p>Once the user selects an account, your activity receives a call to its
{@link android.app.Activity#onActivityResult onActivityResult()} method. The received
{@link android.content.Intent} includes an extra for
{@link android.accounts.AccountManager#KEY_ACCOUNT_NAME}, specifying the account name
(an email address) you must use to acquire the OAuth 2.0 token.</p>
<p>Here's an example implementation of the callback {@link android.app.Activity#onActivityResult
onActivityResult()} that receives the selected account:</p>
<pre>
String mEmail; // Received from <a href=
"{@docRoot}reference/com/google/android/gms/common/AccountPicker.html#newChooseAccountIntent(android.accounts.Account,%20java.util.ArrayList%3Candroid.accounts.Account%3E,%20java.lang.String[],%20boolean,%20java.lang.String,%20java.lang.String,%20java.lang.String[],%20android.os.Bundle)"
>{@code newChooseAccountIntent()}</a>; passed to <a href=
"{@docRoot}reference/com/google/android/gms/auth/GoogleAuthUtil.html#getToken(android.content.Context,%20java.lang.String,%20java.lang.String)">{@code getToken()}</a>
&#64;Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE_PICK_ACCOUNT) {
// Receiving a result from the AccountPicker
if (resultCode == RESULT_OK) {
mEmail = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
// With the account name acquired, go get the auth token
getUsername();
} else if (resultCode == RESULT_CANCELED) {
// The account picker dialog closed without selecting an account.
// Notify users that they must pick an account to proceed.
Toast.makeText(this, R.string.pick_account, Toast.LENGTH_SHORT).show();
}
}
// Later, more code will go here to handle the result from some exceptions...
}
</pre>
<p>You can now pass the account name held by {@code mEmail} to <a href=
"{@docRoot}reference/com/google/android/gms/auth/GoogleAuthUtil.html#getToken(android.content.Context,%20java.lang.String,%20java.lang.String)">
{@code GoogleAuthUtil.getToken()}</a> (which is what the {@code getUsername()} method
does), but because it performs network transactions, this method should not be called from the
UI thread. The next lesson shows how to create an {@link android.os.AsyncTask} to get the auth token
on a separate thread.</p>
<p>Once you have retrieved the account name for the user's Google account, you can call <a href=
"{@docRoot}reference/com/google/android/gms/auth/GoogleAuthUtil.html#getToken(android.content.Context,%20java.lang.String,%20java.lang.String)">
{@code GoogleAuthUtil.getToken()}</a>, which returns the access token string required by Google API
services.</p>
<p>Calling this method is generally a straightforward procedure, but you must be
aware that:</p>
<ul>
<li>The <a href=
"{@docRoot}reference/com/google/android/gms/auth/GoogleAuthUtil.html#getToken(android.content.Context,%20java.lang.String,%20java.lang.String)">
{@code GoogleAuthUtil.getToken()}</a> method requires a network connection, so your app must
acquire the {@link android.Manifest.permission#INTERNET} permission. You should also check whether
the device has a network connection at runtime by querying {@link android.net.NetworkInfo}, which
requires that your app also acquire the {@link android.Manifest.permission#ACCESS_NETWORK_STATE}
permissions&mdash;for more details, read <a href=
"{@docRoot}training/basics/network-ops/connecting.html">Connecting to the Network</a>.</li>
<li>Because the <a href=
"{@docRoot}reference/com/google/android/gms/auth/GoogleAuthUtil.html#getToken(android.content.Context,%20java.lang.String,%20java.lang.String)">
{@code GoogleAuthUtil.getToken()}</a> method performs a synchronous network transaction, you should
always perform this call from a worker thread to avoid blocking your app's UI thread.</li>
<li>As is true when performing any network transaction, you should be prepared to handle
exceptions that may occur. There are also specific exceptions that
<a href=
"{@docRoot}reference/com/google/android/gms/auth/GoogleAuthUtil.html#getToken(android.content.Context,%20java.lang.String,%20java.lang.String)">
{@code GoogleAuthUtil.getToken()}</a> may throw, defined as <a href=
"{@docRoot}reference/com/google/android/gms/auth/GoogleAuthException.html">{@code
GoogleAuthException}</a> objects.</li>
</ul>
<p>This lesson shows how you can gracefully handle these concerns by performing authentication in
an {@link android.os.AsyncTask} and providing users with the appropriate information and available
actions during known exceptions.</p>
<p class="note"><strong>Note:</strong> The code shown in this lesson, using <a href=
"{@docRoot}reference/com/google/android/gms/auth/GoogleAuthUtil.html#getToken(android.content.Context,%20java.lang.String,%20java.lang.String)">{@code GoogleAuthUtil.getToken()}</a>,
is appropriate when you will be requesting the OAuth token from an {@link android.app.Activity}.
However, if you need to request the OAuth token from a {@link android.app.Service}, then you
should instead use <a
href="{@docRoot}reference/com/google/android/gms/auth/GoogleAuthUtil.html#getTokenWithNotification(android.content.Context, java.lang.String, java.lang.String, android.os.Bundle)">{@code
getTokenWithNotification()}</a>. This method works the same as <a href=
"{@docRoot}reference/com/google/android/gms/auth/GoogleAuthUtil.html#getToken(android.content.Context,%20java.lang.String,%20java.lang.String)">{@code GoogleAuthUtil.getToken()}</a>, but if an error occurs, it
also creates an appropriate
<a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">notification</a>
that allows the user can recover from the error.
The sample available for download above includes code showing how to use this method instead.</p>
<h2 id="ExtendAsyncTask">Extend AsyncTask to Get the Auth Token</h2>
<p>The {@link android.os.AsyncTask} class provides a simple way to create a worker thread for jobs
that should not run on your UI thread. This lesson focuses on how to create such a thread
to get your auth token; for a more complete discussion about {@link android.os.AsyncTask},
read <a href="{@docRoot}training/articles/perf-anr.html">Keeping Your
App Responsive</a> and the {@link android.os.AsyncTask} class reference.</p>
<p>The {@link android.os.AsyncTask#doInBackground doInBackground()} method in your {@link
android.os.AsyncTask} class is where you should call the <a href=
"{@docRoot}reference/com/google/android/gms/auth/GoogleAuthUtil.html#getToken(android.content.Context,%20java.lang.String,%20java.lang.String)">
{@code GoogleAuthUtil.getToken()}</a> method. You can also use it to catch some of the generic
exceptions that may occur during your network transactions.</p>
<p>For example, here's part of an {@link android.os.AsyncTask} subclass that calls <a href=
"{@docRoot}reference/com/google/android/gms/auth/GoogleAuthUtil.html#getToken(android.content.Context,%20java.lang.String,%20java.lang.String)">
{@code GoogleAuthUtil.getToken()}</a>:</p>
<pre>
public class GetUsernameTask extends AsyncTask<Void, Void, Void>{
Activity mActivity;
String mScope;
String mEmail;
GetUsernameTask(Activity activity, String name, String scope) {
this.mActivity = activity;
this.mScope = scope;
this.mEmail = name;
}
/**
* Executes the asynchronous job. This runs when you call execute()
* on the AsyncTask instance.
*/
&#64;Override
protected Void doInBackground(Void... params) {
try {
String token = fetchToken();
if (token != null) {
// <b>Insert the good stuff here.</b>
// Use the token to access the user's Google data.
...
}
} catch (IOException e) {
// The fetchToken() method handles Google-specific exceptions,
// so this indicates something went wrong at a higher level.
// TIP: Check for network connectivity before starting the AsyncTask.
...
}
return null;
}
/**
* Gets an authentication token from Google and handles any
* GoogleAuthException that may occur.
*/
protected String fetchToken() throws IOException {
try {
<b>return GoogleAuthUtil.getToken(mActivity, mEmail, mScope);</b>
} catch (UserRecoverableAuthException userRecoverableException) {
// GooglePlayServices.apk is either old, disabled, or not present
// so we need to show the user some UI in the activity to recover.
mActivity.handleException(userRecoverableException);
} catch (GoogleAuthException fatalException) {
// Some other type of unrecoverable exception has occurred.
// Report and log the error as appropriate for your app.
...
}
return null;
}
...
}
</pre>
<p>In order to call <a href=
"{@docRoot}reference/com/google/android/gms/auth/GoogleAuthUtil.html#getToken(android.content.Context,%20java.lang.String,%20java.lang.String)">
{@code GoogleAuthUtil.getToken()}</a>, you must provide the app {@link android.content.Context},
the account name retrieved from the account picker, and the scope for your auth
token request. The above sample code (and the attached sample) defines these arguments with
class members that the host activity passes to
the {@link android.os.AsyncTask} class constructor.</p>
<p class="note"><strong>Note:</strong>
As shown by the {@code fetchToken()} method above, you must handle
special exceptions that may occur during the <a href=
"{@docRoot}reference/com/google/android/gms/auth/GoogleAuthUtil.html#getToken(android.content.Context,%20java.lang.String,%20java.lang.String)">
{@code GoogleAuthUtil.getToken()}</a> method. The next section shows how you should
respond to these exceptions.</p>
<p>Once you have an {@link android.os.AsyncTask} subclass defined,
you can instantiate and execute an instance after you get the user's
account name from the account picker.
For example, back in the {@link android.app.Activity} class you can do something like this:</p>
<pre>
String mEmail; // Received from <a href=
"{@docRoot}reference/com/google/android/gms/common/AccountPicker.html#newChooseAccountIntent(android.accounts.Account,%20java.util.ArrayList%3Candroid.accounts.Account%3E,%20java.lang.String[],%20boolean,%20java.lang.String,%20java.lang.String,%20java.lang.String[],%20android.os.Bundle)"
>{@code newChooseAccountIntent()}</a>; passed to <a href=
"{@docRoot}reference/com/google/android/gms/auth/GoogleAuthUtil.html#getToken(android.content.Context,%20java.lang.String,%20java.lang.String)">{@code getToken()}</a>
private static final String SCOPE =
"oauth2:https://www.googleapis.com/auth/userinfo.profile";
/**
* Attempts to retrieve the username.
* If the account is not yet known, invoke the picker. Once the account is known,
* start an instance of the AsyncTask to get the auth token and do work with it.
*/
private void getUsername() {
if (mEmail == null) {
pickUserAccount();
} else {
if (isDeviceOnline()) {
<b>new GetUsernameTask(HelloActivity.this, mEmail, SCOPE).execute();</b>
} else {
Toast.makeText(this, R.string.not_online, Toast.LENGTH_LONG).show();
}
}
}
</pre>
<p>The {@code pickUserAccount()} method is shown in the first lesson, <a
href="{@docRoot}training/auth-google/picking-account.html">Picking the User's Account</a>.
<p>For information about how to check whether the device is currently online (as performed by
the {@code isDeviceOnline()} method above), see the attached sample app or the
<a href=
"{@docRoot}training/basics/network-ops/connecting.html">Connecting to the Network</a> lesson.</p>
<p>The only part left is how you should handle the exceptions that may occur when you call
<a href=
"{@docRoot}reference/com/google/android/gms/auth/GoogleAuthUtil.html#getToken(android.content.Context,%20java.lang.String,%20java.lang.String)">
{@code GoogleAuthUtil.getToken()}</a>.</p>
<h2 id="HandleExceptions">Handle Exceptions</h2>
<p>As shown in the <code>fetchToken()</code> method above, you must catch all occurrences of <a href=
"{@docRoot}reference/com/google/android/gms/auth/GoogleAuthException.html">{@code
GoogleAuthException}</a> when you call <a href=
"{@docRoot}reference/com/google/android/gms/auth/GoogleAuthUtil.html#getToken(android.content.Context,%20java.lang.String,%20java.lang.String)">
{@code GoogleAuthUtil.getToken()}</a>.</p>
<p>To provide users information and a proper solution to issues that may occur while acquiring the
auth token, it's important that you properly handle the following subclasses of <a href=
"{@docRoot}reference/com/google/android/gms/auth/GoogleAuthException.html">{@code
GoogleAuthException}</a>:</p>
<dl>
<dt><a href="{@docRoot}reference/com/google/android/gms/auth/UserRecoverableAuthException.html">{@code UserRecoverableAuthException}</a></dt>
<dd>This is an error that users can resolve through some verification. For example, users may
need to confirm that your app is allowed to access their Google data or they may need to re-enter
their account password. When you receive this exception, call <a href=
"{@docRoot}reference/com/google/android/gms/auth/UserRecoverableAuthException.html#getIntent()">{@code
getIntent()}</a> on the instance and pass the returned {@link android.content.Intent} to {@link
android.app.Activity#startActivityForResult startActivityForResult()} to give users the opportunity
to solve the problem, such as by logging in.</dd>
<dt><a href="{@docRoot}reference/com/google/android/gms/auth/GooglePlayServicesAvailabilityException.html">{@code GooglePlayServicesAvailabilityException}</a></dt>
<dd>This is a specific type of <a
href="{@docRoot}reference/com/google/android/gms/auth/UserRecoverableAuthException.html">{@code
UserRecoverableAuthException}</a> indicating that the user's current version
of Google Play services is outdated. Although the recommendation above for
<a href="{@docRoot}reference/com/google/android/gms/auth/UserRecoverableAuthException.html">{@code
UserRecoverableAuthException}</a> also works for this exception, calling {@link
android.app.Activity#startActivityForResult startActivityForResult()} will immediately send users
to Google Play Store to install an update, which may be confusing. So you should instead call <a
href="{@docRoot}reference/com/google/android/gms/auth/GooglePlayServicesAvailabilityException.html#getConnectionStatusCode()">
{@code getConnectionStatusCode()}</a> and pass the result to <a href=
"{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesUtil.html#getErrorDialog(int,%20android.app.Activity,%20int,%20android.content.DialogInterface.OnCancelListener)">
{@code GooglePlayServicesUtil.getErrorDialog()}</a>. This returns a {@link android.app.Dialog}
that includes an appropriate message and a button to take users to Google Play Store so they
can install an update.</dd>
</dl>
<p>For example, the <code>fetchToken()</code> method in the above sample code catches any
occurrence of <a
href="{@docRoot}reference/com/google/android/gms/auth/UserRecoverableAuthException.html">{@code
UserRecoverableAuthException}</a> and passes it back to the activity with a method called
{@code handleException()}. Here's what that method in the activity may look like:</p>
<pre>
static final int REQUEST_CODE_RECOVER_FROM_PLAY_SERVICES_ERROR = 1001;
/**
* This method is a hook for background threads and async tasks that need to
* provide the user a response UI when an exception occurs.
*/
public void handleException(final Exception e) {
// Because this call comes from the AsyncTask, we must ensure that the following
// code instead executes on the UI thread.
runOnUiThread(new Runnable() {
&#64;Override
public void run() {
if (e instanceof GooglePlayServicesAvailabilityException) {
// The Google Play services APK is old, disabled, or not present.
// Show a dialog created by Google Play services that allows
// the user to update the APK
int statusCode = ((GooglePlayServicesAvailabilityException)e)
.getConnectionStatusCode();
Dialog dialog = GooglePlayServicesUtil.getErrorDialog(statusCode,
HelloActivity.this,
REQUEST_CODE_RECOVER_FROM_PLAY_SERVICES_ERROR);
dialog.show();
} else if (e instanceof UserRecoverableAuthException) {
// Unable to authenticate, such as when the user has not yet granted
// the app access to the account, but the user can fix this.
// Forward the user to an activity in Google Play services.
Intent intent = ((UserRecoverableAuthException)e).getIntent();
startActivityForResult(intent,
REQUEST_CODE_RECOVER_FROM_PLAY_SERVICES_ERROR);
}
}
});
}
</pre>
<p>Notice that in both cases, the {@code REQUEST_CODE_RECOVER_FROM_PLAY_SERVICES_ERROR}
request code is passed with the request to handle the exception with a dialog or activity.
This way, when the user completes the appropriate action to resolve the exception,
your {@link android.app.Activity#onActivityResult onActivityResult()} method receives an
intent that includes this request code and you can try to acquire the auth
token again.</p>
<p>For example, the following code is a complete implementation of {@link
android.app.Activity#onActivityResult onActivityResult()} that handles results for
both the {@code REQUEST_CODE_PICK_ACCOUNT} action (shown in the previous lesson, <a
href="{@docRoot}training/auth-google/picking-account.html">Picking the User's Account</a>)
and the {@code REQUEST_CODE_RECOVER_FROM_PLAY_SERVICES_ERROR} action, which occurs after the user
completes one of the actions above to resolve an exception.</p>
<pre>
&#64;Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE_PICK_ACCOUNT) {
// Receiving a result from the AccountPicker
if (resultCode == RESULT_OK) {
mEmail = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
// With the account name acquired, go get the auth token
getUsername();
} else if (resultCode == RESULT_CANCELED) {
// The account picker dialog closed without selecting an account.
// Notify users that they must pick an account to proceed.
Toast.makeText(this, R.string.pick_account, Toast.LENGTH_SHORT).show();
}
} else if ((requestCode == REQUEST_CODE_RECOVER_FROM_AUTH_ERROR ||
requestCode == REQUEST_CODE_RECOVER_FROM_PLAY_SERVICES_ERROR)
&& resultCode == RESULT_OK) {
// Receiving a result that follows a GoogleAuthException, try auth again
getUsername();
}
}
</pre>
<p>For a complete set of code that acquires the OAuth token and queries a Google service
over HTTP (including how to use <a
href="{@docRoot}reference/com/google/android/gms/auth/GoogleAuthUtil.html#getTokenWithNotification(android.content.Context, java.lang.String, java.lang.String, android.os.Bundle)">{@code
getTokenWithNotification()}</a> when you need to acquire the token from
a {@link android.app.Service}), see the sample app available for download at the top
of this page.</p>

View File

@ -65,12 +65,6 @@
<span class="en">Wallet</span>
</a></div>
</li>
<li class="nav-section">
<div class="nav-section-header empty"><a href="<?cs var:toroot?>google/play-services/auth.html">
<span class="en">Authorization</span>
</a></div>
</li>
<li class="nav-section">
@ -81,6 +75,18 @@
<li><a href="<?cs var:toroot?>google/play-services/setup.html">
<span class="en">Setup</span></a>
</li>
<li class="nav-section">
<div class="nav-section-header"><a href="<?cs var:toroot?>google/auth/api-client.html">
<span class="en">Accessing Google Play Services APIs</span></a>
</div>
<ul>
<li>
<a href="<?cs var:toroot ?>google/auth/http-auth.html">
<span class="en">Authorizing with Google for REST APIs</span>
</a>
</li>
</ul>
</li>
<li id="gms-tree-list" class="nav-section">
<div class="nav-section-header">
<a href="<?cs var:toroot ?>reference/gms-packages.html">

View File

@ -187,14 +187,13 @@ to your <code>gradle.build</code> file's build types. For more information, see
</ol>
<h2 id="ensure">Ensure Devices Have the Google Play services APK</h2>
<p>As described in the <a href="{@docRoot}google/play-services/index.html">Google Play services
introduction</a>, Google Play delivers service updates for users on
Android 2.3 through the Google Play Store app. However, updates might not reach
all users immediately.</p>
Android 2.3 and higher through the Google Play Store app. However, updates might not reach
all users immediately, so your app should verify the version available before attempting to
perform API transactions.</p>
<p class="caution">
<strong>Important:</strong>
@ -204,77 +203,36 @@ all users immediately.</p>
{@link android.app.Activity#onResume onResume()} method of the main activity.
</p>
<p>Here are four scenarios that describe the possible state of the Google Play services APK on
a user's device:</p>
<ol>
<li>
A recent version of the Google Play Store app is installed, and the most recent Google Play
services APK has been downloaded.
</li>
<li>
A recent version of the Google Play Store app is installed, but the most recent Google Play
services APK has <em>not</em> been downloaded.
</li>
<li>
An old version of the Google Play Store app, which does not proactively download Google Play
services updates, is present.
</li>
<li>
The Google Play services APK is missing or disabled on the device, which might happen if the
user explicitly uninstalls or disables it.
</li>
</ol>
<p>
Case 1 is the success scenario and is the most common. However, because the other scenarios can
still happen, you must handle them every time your app connects to a Google Play service to
ensure that the Google Play services APK is present, up-to-date, and enabled.
</p>
<p>
To help you, the Google Play services client library has utility methods to
determine whether or not the Google Play services APK is recent enough to support the
version of the client library you are using. If not, the client library sends users to the
Google Play Store to download the recent version of the Google Play services APK.
</p>
<p>The Google Play services library includes utility methods that help you determine whether or not
the Google Play services version on the device supports the version of the client library you are
using. If the version on the device is too old, the system will take the user to Google Play Store
in order to install the recent version of the Google Play services.</p>
<p class="note">
<b>Note:</b>
The Google Play services APK is not visible by searching the Google Play Store. The client
library provides a deep link into the Google Play Store when it detects that the device has a
missing or incompatible Google Play services APK.
</p>
<p>Because each app uses Google Play services differently, it's up to you decide the appropriate
place in your app to check verify the Google Play services version. For example, if Google Play
services is required for your app at all times, you might want to do it when your app first
launches. On the other hand, if Google Play services is an optional part of your app, you can check
the version only once the user navigates to that portion of your app.</p>
<p>
It is up to you choose the appropriate place in your app to do the following steps to check for
a valid Google Play services APK. For example, if Google Play services is required for your app,
you might want to do it when your app first launches. On the other hand, if Google Play services
is an optional part of your app, you can do these checks if the user navigates to that portion
of your app:
</p>
<ol>
<li>
Query for the status of Google Play services on the device with the
<a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesUtil.html#isGooglePlayServicesAvailable(android.content.Context)"
>{@code isGooglePlayServicesAvailable()}</a> method, which returns a result code.
</li>
<li>
If the result code is
<p>To verify the Google Play services version, call <a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesUtil.html#isGooglePlayServicesAvailable(android.content.Context)"
>{@code isGooglePlayServicesAvailable()}</a>. If the result code is
<a href="{@docRoot}reference/com/google/android/gms/common/ConnectionResult.html#SUCCESS"
>{@code SUCCESS}</a>,
then the Google Play services APK is up-to-date, and you can proceed as normal.
</li>
<li>
If the result code is
then the Google Play services APK is up-to-date and you can continue to make a connection.
If, however, the result code is
<a href="{@docRoot}reference/com/google/android/gms/common/ConnectionResult.html#SERVICE_MISSING"
>{@code SERVICE_MISSING}</a>,
<a href="{@docRoot}reference/com/google/android/gms/common/ConnectionResult.html#SERVICE_VERSION_UPDATE_REQUIRED"
>{@code SERVICE_VERSION_UPDATE_REQUIRED}</a>,
or
<a href="{@docRoot}reference/com/google/android/gms/common/ConnectionResult.html#SERVICE_DISABLED"
>{@code SERVICE_DISABLED}</a>, then
>{@code SERVICE_DISABLED}</a>, then the user needs to install an update. So,
call <a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesUtil.html#getErrorDialog(int, android.app.Activity, int)"
>{@code getErrorDialog()}</a>
to display an error message to the user, which allows the user to download the APK
from the Google Play Store or enable it in the device's system settings.
</li>
</ol>
>{@code GooglePlayServicesUtil.getErrorDialog()}</a> and pass it the result error code.
This returns a {@link android.app.Dialog} you should show, which provides an appropriate message
about the error and provides an action
that takes the user to Google Play Store to install the update.</p>
<p>To then begin a connection to Google Play services, read <a
href="{@docRoot}google/auth/api-client.html">Accessing Google Play Services APIs</a>.</p>

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB