您可以使用 GoogleApiClient
(“Google API 客户端”)
对象来访问 Google Play 服务库中提供的 Google API
(例如 Google 登录、游戏和云端硬盘)。Google API 客户端提供了
Google Play 服务和管理网络的通用入口点
用户的设备与每项 Google 服务之间的连接。
不过,较新的 GoogleApi
接口及其实现更易于
和 是访问 Play 服务 API 的首选方式。
请参阅访问 Google API。
本指南介绍了如何执行以下操作:
- 自动管理与 Google Play 服务的关联。
- 对任何 Google Play 服务执行同步和异步 API 调用。
- 在极少数情况下,您需要手动管理与 Google Play 服务的连接 。如需了解详情,请参阅手动管理的连接。
首先,您必须先安装 Google Play 服务库(修订版 15 或更高版本) 。如果您尚未执行此操作,请按照 设置 Google Play 服务 SDK。
启动自动管理的连接
在您的项目关联到 Google Play 服务库后,创建
GoogleApiClient
,使用
GoogleApiClient.Builder
API(位于您的 Activity 的
onCreate()
方法。通过
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();
您可以将多个 API 和多个范围添加到同一个
GoogleApiClient
方法是向 addApi()
附加其他调用
和addScope()
。
重要提示:如果您要将 Wearable
API 与其他 API 一起添加到
GoogleApiClient
,
未安装 Wear OS 应用。接收者
为避免连接错误,请调用 addApiIfAvailable()
方法并传入
Wearable
API,以允许您的客户端妥善处理缺少的
API。如需了解详情,请参阅访问 Wearable API。
如需启动自动管理的连接,您必须指定
OnConnectionFailedListener
的实现
接收无法解析的连接错误。当您自动管理
GoogleApiClient
实例尝试连接到 Google API,系统将自动
显示界面,以尝试修复任何可解决的连接故障(例如,
Google Play 服务需要更新)。如果发生
问题解决后,我们会立即致电
onConnectionFailed()
。
如果您的应用需要知道ConnectionCallbacks
建立或暂停自动管理的连接。例如,如果
您的应用进行调用以向 Google API 写入数据,则应调用这些调用
仅在调用 onConnected()
方法之后才发生。
以下是一个实现回调接口并添加 发送到 Google API 客户端:
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
实例将在活动后自动连接
会调用 onStart()
,并在调用 onStop()
后断开连接。
您的应用可以立即开始
在构建 GoogleApiClient
后向 Google API 发出读取请求,而不
等待连接完成
与 Google 服务通信
连接后,您的客户端可以使用服务专属 API 进行读取和写入调用,
您添加到
GoogleApiClient
实例。
注意:在调用特定 Google 服务之前,您可能需要先注册您的 了解其应用。有关说明,请参阅 入门指南,例如 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 Play 服务会在 Google API 客户端未连接时写入方法。
使用异步调用
要异步发出请求,请调用
setResultCallback()
位于PendingResult
上,并提供
实施
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. // ... } }); }
当您的应用在 Result
onResult()
回调后,
它作为您正在使用的 API 指定的相应子类的实例进行传递,
例如
DriveApi.MetadataBufferResult
。
使用同步调用
如果您希望代码按严格定义的顺序执行,可能是因为
一个调用作为另一个调用的参数,您可以通过调用
await()
(位于
PendingResult
。这会阻塞线程
并在调用 时返回 Result
对象
请求完成将此对象作为相应子类的实例进行传递,
您使用的 API,例如
DriveApi.MetadataBufferResult
。
因为调用 await()
在结果到达之前阻塞线程,则您的应用绝不应在
界面线程。您的应用可以使用 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 由系统可以发送和同步的一组数据对象组成,以及 使用数据层通知应用的重要事件的监听器。通过 Wearable API 适用于搭载 Android 4.3(API 级别 18)或更高版本的设备, 已连接穿戴式设备并且 Wear OS 配套应用 是否已安装在设备上。
单独使用 Wearable API
如果您的应用使用的是 Wearable API 但未使用其他 Google API,您可以通过以下方法添加此 API:
调用 addApi()
方法。以下示例展示了如何将
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
可以成功连接到
Google 云端硬盘,而不连接到 Wearable API(如果不可用)。更新后
请连接你的GoogleApiClient
实例,在进行 API 调用之前确保 Wearable API 可用:
boolean wearAvailable = mGoogleApiClient.hasConnectedApi(Wearable.API);
忽略 API 连接故障
如果您调用 addApi()
,但 GoogleApiClient
无法执行以下操作:
成功连接到该 API,则该客户端的整个连接操作将失败,并且
触发 onConnectionFailed()
回调。
您可以使用
addApiIfAvailable()
。如果通过
由于发生不可恢复的错误,addApiIfAvailable()
无法连接
(如 Wear 的 API_UNAVAILABLE
),
该 API 将从您的 GoogleApiClient
丢弃,并且客户端继续
连接到其他 API。但是,如果任何 API 连接因可恢复的错误(如
OAuth 同意解析 intent),则客户端连接操作将失败。时间
如果使用的是自动管理的连接,GoogleApiClient
将尝试
以解决此类错误。使用手动管理的连接时
包含解析 intent 的 ConnectionResult
传递给 onConnectionFailed()
回调。API
仅当没有针对连接故障的解决方法时,系统才会忽略此故障
并且该 API 已添加到
与 addApiIfAvailable()
共享。
了解如何实现手动连接失败
请参阅处理连接故障。
由于使用
addApiIfAvailable()
可能并不总是出现在已连接的
GoogleApiClient
实例,则应通过添加检查代码来保护对这些 API 的调用
(使用 hasConnectedApi()
)。为了解
当客户端的整个连接操作成功时,特定 API 连接失败,请调用
getConnectionResult()
,并从
ConnectionResult
对象。如果您的客户端在未调用某个 API 时调用该 API,
调用将失败,并显示
API_NOT_AVAILABLE
状态代码。
如果您通过 addApiIfAvailable()
添加的 API 需要一个或
请将这些范围作为参数添加到
addApiIfAvailable()
方法调用,而不是使用
addScope()
方法。如果 API
则连接失败后才能获得 OAuth 同意,而使用
始终请求 addScope()
。
手动管理的连接
本指南的大部分内容将介绍如何使用
enableAutoManage
方法启动
具有自动解决的错误的自动管理连接。即将在
在所有情况下,这是从您的
Android 应用。不过,在某些情况下,您需要使用
在您的应用中手动管理与 Google API 的连接:
- 在活动之外访问 Google API 或保留对 API 的控制权 连接
- 自定义连接错误的处理和解决方法
本部分提供了这些及其他高级用例的示例。
启动手动管理的连接
如需启动与 GoogleApiClient
的手动管理连接,您必须:
为回调接口指定实现
ConnectionCallbacks
和OnConnectionFailedListener
。
这些接口会收到回调以响应异步
connect()
方法,
与 Google Play 服务的连接成功、失败或被暂停。
mGoogleApiClient = new GoogleApiClient.Builder(this) .addApi(Drive.API) .addScope(Drive.SCOPE_FILE) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .build()
手动管理连接时,您需要调用
connect()
和
disconnect()
在应用的生命周期的正确时间点添加方法。在活动中
上下文,最佳实践是在 activity 的 onStart()
中调用 connect()
方法,以及 activity 的 onStop()
方法中的 disconnect()
。
connect()
和
disconnect()
方法
在使用自动管理的连接时会自动调用。
如果您使用 GoogleApiClient
连接到需要
例如 Google 云端硬盘或 Google Play 游戏
您的第一次连接尝试将失败,并且您的应用将收到呼叫
发送至onConnectionFailed()
使用SIGN_IN_REQUIRED
错误,原因是未指定用户账号。
处理连接故障
当应用收到对 onConnectionFailed()
的调用时
回调,则应调用 hasResolution()
提供的ConnectionResult
对象。如果它返回 true,您的应用可以通过以下方式请求用户立即采取措施来解决错误:
正在呼叫startResolutionForResult()
针对 ConnectionResult
对象的操作。
startResolutionForResult()
方法
在这种情况下,行为与 startActivityForResult()
相同,
并启动一个适合上下文的 activity,以帮助用户解决错误(例如,帮助用户解决相关问题的 activity)
选择账号)。
如果状态为 hasResolution()
返回 false,您的应用应调用
GoogleApiAvailability.getErrorDialog()
、
将错误代码传递给此方法。这将返回一个
Dialog
(由 Google Play 提供)
对相应错误进行适当更改的服务。对话框可能只会提供一条消息
也可能提供一个操作来启动可以解决该错误的 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 会收到
onActivityResult()
回调
RESULT_OK
结果代码。
然后,您的应用就可以调用
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 实例持续存在此布尔值时,它才会有其预期用途。 下一部分将介绍如何维护应用的错误处理状态(即便有其他用户操作) 或事件中发生的事件
解决错误时保持状态
为避免在 Cloud Shell 中
onConnectionFailed()
而之前尝试解决某个错误时,您需要保留一个布尔值,
跟踪您的应用是否已尝试解决错误。
如上面的代码示例所示,应用每次调用时都应将布尔值设置为 true
startResolutionForResult()
或者从
GoogleApiAvailability.getErrorDialog()
。
然后,当您的应用收到
RESULT_OK
(在
onActivityResult()
回调,请将布尔值设置为 false
。
如需在 activity 重启时(例如当用户旋转屏幕时)跟踪该布尔值,
使用以下代码在 activity 的已保存实例数据中保存布尔值:
onSaveInstanceState()
:
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 服务了。