您可以使用 GoogleApiClient
(“Google API 客户端”)对象访问 Google Play 服务库(例如 Google 登录、游戏和云端硬盘)中提供的 Google API。Google API 客户端为 Google Play 服务提供一个通用的入口点,并管理用户设备和每项 Google 服务之间的网络连接。
不过,较新的 GoogleApi
接口及其实现更易于使用,是访问 Play 服务 API 的首选方式。请参阅访问 Google API。
本指南介绍了如何完成以下操作:
- 自动管理与 Google Play 服务的连接。
- 对任何 Google Play 服务执行同步和异步 API 调用。
- 在极少数情况下,您需要手动管理与 Google Play 服务的连接。如需了解详情,请参阅手动管理的连接。

首先,您必须安装 Android SDK 的 Google Play 服务库(修订版 15 或更高版本)。如果您尚未执行此操作,请按照设置 Google Play 服务 SDK 中的说明操作。
启动自动管理的连接
将您的项目关联到 Google Play 服务库后,使用 Activity 的 onCreate()
方法中的 GoogleApiClient.Builder
API 创建 GoogleApiClient
实例。GoogleApiClient.Builder
类提供的方法可让您指定要使用的 Google API 和所需的 OAuth 2.0 范围。下面的代码示例可以创建一个与 Google 云端硬盘服务连接的 GoogleApiClient
实例:
GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this) .enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */) .addApi(Drive.API) .addScope(Drive.SCOPE_FILE) .build();
您可以通过向 addApi()
和 addScope()
附加调用,向同一 GoogleApiClient
添加多个 API 和多个范围。
重要提示:如果您要将 Wearable
API 以及其他 API 添加到 GoogleApiClient
,则可能会在未安装 Wear OS 应用的设备上遇到客户端连接错误。为避免连接错误,请调用 addApiIfAvailable()
方法并传入 Wearable
API,让您的客户端能够妥善处理缺失的 API。如需了解详情,请参阅访问 Wearable API。
如需开始自动管理的连接,您必须为 OnConnectionFailedListener
接口指定一个实现,以接收无法解析的连接错误。当您的自动管理 GoogleApiClient
实例尝试连接到 Google API 时,它会自动显示界面以尝试修复任何可解决的连接故障(例如,如果 Google Play 服务需要更新)。如果发生无法解决的错误,您会收到对 onConnectionFailed()
的调用。
如果您的应用需要知道自动托管连接建立或暂停的时间,您也可以为 ConnectionCallbacks
接口指定可选的实现。例如,如果您的应用向 Google API 写入数据调用,则只有在调用 onConnected()
方法之后,才能调用这些 API。
以下是实现回调接口并将其添加到 Google API 客户端的示例 Activity:
import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener; import gms.drive.*; import android.support.v4.app.FragmentActivity; public class MyActivity extends FragmentActivity implements OnConnectionFailedListener { private GoogleApiClient mGoogleApiClient; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Create a GoogleApiClient instance mGoogleApiClient = new GoogleApiClient.Builder(this) .enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */) .addApi(Drive.API) .addScope(Drive.SCOPE_FILE) .build(); // ... } @Override public void onConnectionFailed(ConnectionResult result) { // An unresolvable error has occurred and a connection to Google APIs // could not be established. Display an error message, or handle // the failure silently // ... } }
您的 GoogleApiClient
实例会在 activity 调用 onStart()
后自动连接,并在调用 onStop()
后断开连接。构建 GoogleApiClient
后,您的应用可以立即开始向 Google API 发出读取请求,而无需等待连接完成。
与 Google 服务通信
连接后,您的客户端可以使用应用授权的服务专用 API(根据您添加到 GoogleApiClient
实例的 API 和范围)进行读取和写入调用。
注意:在调用特定 Google 服务之前,您可能需要先在 Google Developers Console 中注册您的应用。有关说明,请参阅适用于您所用 API 的相应入门指南,例如 Google 云端硬盘或 Google 登录。
当您使用 GoogleApiClient
执行读取或写入请求时,API 客户端会返回代表该请求的 PendingResult
对象。请求会在应用向调用的 Google 服务发送之前立即发生。
例如,下面是一个请求,用于读取 Google 云端硬盘中提供 PendingResult
对象的文件:
Query query = new Query.Builder() .addFilter(Filters.eq(SearchableField.TITLE, filename)); PendingResult<DriveApi.MetadataBufferResult> result = Drive.DriveApi.query(mGoogleApiClient, query);
在您的应用拥有 PendingResult
对象后,便可以指定该请求是作为异步调用处理还是作为同步调用处理。
提示:您的应用可以在未连接到 Google Play 服务的情况下将读取请求加入队列。例如,无论您的 GoogleApiClient
实例是否已连接,您的应用都可以调用方法来读取 Google 云端硬盘中的文件。建立连接后,系统会执行已加入队列的读取请求。如果您的应用在未连接 Google API 客户端的情况下调用 Google Play 服务写入方法,写入请求会生成错误。
使用异步调用
如需将请求设为异步,请对 PendingResult
调用 setResultCallback()
,并提供 ResultCallback
接口的实现。例如,以下是异步执行的请求:
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<DriveApi.MetadataBufferResult>() { @Override public void onResult(DriveApi.MetadataBufferResult result) { // Success! Handle the query result. // ... } }); }
当您的应用在 onResult()
回调中收到 Result
对象时,它会作为您使用的子类(由您使用的 API 指定,如 DriveApi.MetadataBufferResult
)的实例实例提供。
使用同步调用
如果您希望代码按严格定义的顺序执行,可能是因为某个调用的结果需要作为另一个调用的参数,所以您可以对 PendingResult
调用 await()
来使请求同步。这会阻塞线程并在请求完成时返回 Result
对象。此对象将作为您使用的子类(由您使用的 API 指定)的实例提供,例如 DriveApi.MetadataBufferResult
。
由于调用 await()
会阻塞线程,直到结果达到为止。您的应用绝不应在界面线程中向 Google API 发出同步请求。您的应用可以使用 AsyncTask
对象创建新线程,并使用该线程发出同步请求。
以下示例展示了如何以同步调用的形式向 Google 云端硬盘发出文件请求:
private void loadFile(String filename) { new GetFileTask().execute(filename); } private class GetFileTask extends AsyncTask{ 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 // ... } }
访问 Wearable API
Wearable API 为手持设备和穿戴式设备上运行的应用提供通信通道。该 API 由一组数据对象(系统可以发送和同步)和监听器(使用数据层通知应用)组成。在运行穿戴式设备 4.3(API 级别 18)或更高版本的设备上,只要设备安装了 Wear OS 配套应用,便可以使用 Wearable API。
单独使用 Wearable API
如果您的应用使用 Wearable API 而不是其他 Google API,您可以通过调用 addApi()
方法添加此 API。以下示例展示了如何将 Wearable API 添加到 GoogleApiClient
实例:
GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this) .enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */) .addApi(Wearable.API) .build();
在 Wearable API 不可用的情况下,包含 Wearable API 的连接请求会失败并显示 API_UNAVAILABLE
错误代码。
以下示例展示了如何确定 Wearable API 是否可用:
// Connection failed listener method for a client that only // requests access to the Wearable API @Override public void onConnectionFailed(ConnectionResult result) { if (result.getErrorCode() == ConnectionResult.API_UNAVAILABLE) { // The Wearable API is unavailable } // ... }
将 Wearable API 与其他 Google API 搭配使用
如果您的应用除了其他 Google API 之外,还使用 Wearable API,请调用 addApiIfAvailable()
方法并传入 Wearable API,以检查其是否可用。您可以使用此检查来帮助应用妥善处理 API 不可用的情况。
以下示例展示了如何访问 Wearable API 和 Drive API:
// Create a GoogleApiClient instance mGoogleApiClient = new GoogleApiClient.Builder(this) .enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */) .addApi(Drive.API) .addApiIfAvailable(Wearable.API) .addScope(Drive.SCOPE_FILE) .build();
在上面的示例中,GoogleApiClient
可在未连接到 Wearable API 的情况下成功与 Google 云端硬盘连接。连接 GoogleApiClient
实例后,请先确保 Wearable API 可用,然后再进行 API 调用:
boolean wearAvailable = mGoogleApiClient.hasConnectedApi(Wearable.API);
忽略 API 连接失败
如果您调用 addApi()
且 GoogleApiClient
无法成功连接到该 API,则该客户端的整个连接操作将会失败并触发 onConnectionFailed()
回调。
您可以使用 addApiIfAvailable()
注册要忽略的 API 连接失败情况。如果使用 addApiIfAvailable()
添加的 API 由于不可恢复的错误(例如适用于 Wear 的 API_UNAVAILABLE
)连接失败,则该 API 会从您的 GoogleApiClient
中丢弃,并且客户端会继续连接到其他 API。但是,如果任何 API 连接失败且出现可恢复的错误(如 OAuth 同意解决 intent),客户端连接操作就会失败。如果使用自动管理的连接,GoogleApiClient
将尽可能尝试解决此类错误。使用手动管理的连接时,包含解析 intent 的 ConnectionResult
会传递到 onConnectionFailed()
回调。只有在失败原因没有解决,且使用 addApiIfAvailable()
添加了 API 时,才会忽略 API 连接失败情况。如需了解如何实现手动连接故障处理,请参阅处理连接故障。
由于使用 addApiIfAvailable()
添加的 API 可能并不总是存在于已连接的 GoogleApiClient
实例中,因此您应使用 hasConnectedApi()
添加检查机制,以限制对这些 API 的调用。若要了解特定 API 在客户端的整个连接操作成功时无法连接的原因,请调用 getConnectionResult()
,并从 ConnectionResult
对象获取错误代码。如果您的客户端在未连接到客户端时调用 API,调用将失败并显示 API_NOT_AVAILABLE
状态代码。
如果您通过 addApiIfAvailable()
添加的 API 需要一个或多个范围,请在 addApiIfAvailable()
方法调用中将这些范围作为参数添加,而不是使用 addScope()
方法添加。如果在获得 OAuth 同意之前 API 连接失败,则可以请求使用此方法添加的范围,而始终请求使用 addScope()
添加的范围。
手动管理的连接
本指南的大部分内容介绍了如何使用 enableAutoManage
方法启动具有自动解决的错误的自动连接。几乎在所有情况下,从 Android 应用连接到 Google API 都是最好、最简单的方式。不过,在某些情况下,您需要在应用中使用手动管理的连接连接到 Google API:
- 为了在 activity 之外访问 Google API 或保留对 API 连接的控制
- 自定义连接错误处理和解决方法
本部分将介绍这些用例和其他高级用例。
启动手动管理的连接
如需启动与 GoogleApiClient
的手动连接,您必须为回调接口(ConnectionCallbacks
和 OnConnectionFailedListener
)指定实现。当与 Google Play 服务的连接成功、失败或被暂停时,这些接口会收到回调以响应异步 connect()
方法。
mGoogleApiClient = new GoogleApiClient.Builder(this) .addApi(Drive.API) .addScope(Drive.SCOPE_FILE) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .build()
手动管理连接时,您需要在应用生命周期的正确位置调用 connect()
和 disconnect()
方法。在 activity 上下文中,最佳做法是在 activity 的 onStart()
方法中调用 connect()
,并在 activity 的 onStop()
方法中调用 disconnect()
。使用自动管理的连接时,系统会自动调用 connect()
和 disconnect()
方法。
如果您使用 GoogleApiClient
连接到需要身份验证的 API(例如 Google 云端硬盘或 Google Play 游戏),那么您的首次连接尝试可能会失败,您的应用会收到对 onConnectionFailed()
的调用,其中包含 SIGN_IN_REQUIRED
错误,因为该用户帐号未指定。
处理连接故障
当您的应用收到对 onConnectionFailed()
回调的调用时,您应对提供的 ConnectionResult
对象调用 hasResolution()
。如果返回 true,您的应用可以通过对 ConnectionResult
对象调用 startResolutionForResult()
来请求用户立即执行操作来消除错误。在这种情况下,startResolutionForResult()
方法的行为与 startActivityForResult()
相同,并将启动与上下文一起帮助用户解决错误的 activity(例如,帮助用户选择帐号的 activity)。
如果 hasResolution()
返回 false,您的应用应调用 GoogleApiAvailability.getErrorDialog()
,并将错误代码传递给此方法。这将返回 Google Play 服务提供的适合该错误的 Dialog
。该对话框可能只是提供一条说明错误的消息,或提供一项操作来启动可解决该错误的 activity(例如,用户需要安装更高版本的 Google Play 服务时)。
例如,您的 onConnectionFailed()
回调方法现在应如下所示:
public class MyActivity extends Activity 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; // ... @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 GoogleApiAvailability.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() { } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { // Get the error code and retrieve the appropriate dialog int errorCode = this.getArguments().getInt(DIALOG_ERROR); return GoogleApiAvailability.getInstance().getErrorDialog( this.getActivity(), errorCode, REQUEST_RESOLVE_ERROR); } @Override public void onDismiss(DialogInterface dialog) { ((MyActivity) getActivity()).onDialogDismissed(); } } }
用户完成 startResolutionForResult()
提供的对话框或关闭 GoogleApiAvailability.getErrorDialog()
提供的消息后,您的 activity 会收到包含 RESULT_OK
结果代码的 onActivityResult()
回调。然后,您的应用可以再次调用 connect()
。例如:
@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(); } } } }
在上面的代码中,您可能已经注意到布尔值 mResolvingError
。这样做可以在用户解决错误时跟踪应用状态,以避免重复尝试解决相同的错误。例如,当帐号选择器对话框显示可帮助用户解决 SIGN_IN_REQUIRED
错误时,用户或许可以旋转屏幕。这会重新创建您的 activity 并导致 onStart()
方法再次调用,然后再次调用 connect()
。这会导致对 startResolutionForResult()
进行另一个调用,这将在现有帐号选择器之前创建另一个帐号选择器对话框。
此布尔值仅在 activity 实例之间保留其预期用途。下一部分将介绍如何在设备上成功处理其他用户操作或事件,以保持应用的错误处理状态。
在解决错误时保持状态
为避免在之前尝试解决错误时执行 onConnectionFailed()
中的代码,您需要保留一个布尔值,用于跟踪应用是否已尝试解决错误。
如上面的代码示例所示,您的应用应在每次调用 startResolutionForResult()
或显示来自 GoogleApiAvailability.getErrorDialog()
的对话框时将布尔值设置为 true
。然后,当您的应用在 onActivityResult()
回调中收到 RESULT_OK
时,将布尔值设置为 false
。
如需在 activity 重启(例如用户旋转屏幕)时跟踪布尔值,请使用 onSaveInstanceState()
将布尔值保存在 activity 保存的实例数据中:
private static final String STATE_RESOLVING_ERROR = "resolving_error"; @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putBoolean(STATE_RESOLVING_ERROR, mResolvingError); }
然后,在 onCreate()
期间恢复保存的状态:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // ... mResolvingError = savedInstanceState != null && savedInstanceState.getBoolean(STATE_RESOLVING_ERROR, false); }
现在,您可以安全地运行应用并手动连接到 Google Play 服务了。