GoogleApiClient
(「Google API クライアント」)オブジェクトを使用すると、Google Play 開発者サービス ライブラリで提供されている Google API(Google ログイン、ゲーム、ドライブなど)にアクセスできます。Google API クライアントは、Google Play 開発者サービスへの共通のエントリ ポイントを提供し、ユーザーのデバイスと各 Google サービス間のネットワーク接続を管理します。
ただし、新しい GoogleApi
インターフェースとその実装は使いやすく、Play 開発者サービス API にアクセスする方法として推奨されます。Google API へのアクセスをご覧ください。
このガイドでは、次の方法について説明します。
- Google Play 開発者サービスへの接続を自動的に管理します。
- 任意の Google Play 開発者サービスに対して同期 API 呼び出しと非同期 API 呼び出しを実行します。
- まれに必要となる場合、Google Play 開発者サービスへの接続を手動で管理します。詳細については、手動で管理する接続をご覧ください。
使用を開始するには、まず Android SDK 用の Google Play 開発者サービス ライブラリ(リビジョン 15 以降)をインストールする必要があります。まだセットアップしていない場合は、Google Play 開発者サービス SDK のセットアップの手順に沿ってセットアップします。
自動管理接続を開始する
プロジェクトが Google Play 開発者サービス ライブラリにリンクされたら、アクティビティの 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()
に追加の呼び出しを追加することで、複数の API と複数のスコープを同じ GoogleApiClient
に追加できます。
重要: Wearable
API を他の API とともに GoogleApiClient
に追加する場合、Wear OS アプリがインストールされていないデバイスでクライアント接続エラーが発生することがあります。接続エラーを回避するには、addApiIfAvailable()
メソッドを呼び出して Wearable
API を渡し、クライアントが不足している API を正常に処理できるようにします。詳細については、Wearable API にアクセスするをご覧ください。
自動管理接続を開始するには、解決できない接続エラーを受け取る OnConnectionFailedListener
インターフェースの実装を指定する必要があります。自動管理の GoogleApiClient
インスタンスが Google APIs に接続しようとすると、解決可能な接続エラー(Google Play 開発者サービスの更新が必要な場合など)を修正しようとする UI が自動的に表示されます。解決できないエラーが発生した場合は、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 サービスと通信する
接続後、クライアントは、GoogleApiClient
インスタンスに追加した API とスコープで指定されているように、アプリが承認されているサービス固有の API を使用して読み取りと書き込みの呼び出しを行うことができます。
注: 特定の Google サービスを呼び出す前に、Google デベロッパー コンソールでアプリを登録する必要があります。手順については、使用している API(Google ドライブや Google ログインなど)の適切なスタートガイドをご覧ください。
GoogleApiClient
を使用して読み取りまたは書き込みリクエストを実行すると、API クライアントはリクエストを表す PendingResult
オブジェクトを返します。これは、アプリが呼び出す Google サービスにリクエストが送信される直前に行われます。
たとえば、PendingResult
オブジェクトを提供する Google ドライブからファイルを読み取るリクエストは次のとおりです。
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
など)で指定された適切なサブクラスのインスタンスとして配信されます。
同期呼び出しを使用する
1 つの呼び出しの結果が別の呼び出しの引数として必要な場合など、コードを厳密に定義された順序で実行する場合は、PendingResult
で await()
を呼び出してリクエストを同期にできます。これにより、スレッドがブロックされ、リクエストが完了すると Result
オブジェクトが返されます。このオブジェクトは、使用している API で指定された適切なサブクラスのインスタンスの形で返されます(例: DriveApi.MetadataBufferResult
)。
await()
を呼び出すと、結果が届くまでスレッドがブロックされるため、アプリで UI スレッドで Google API に同期リクエストを送信しないでください。アプリは AsyncTask
オブジェクトを使用して新しいスレッドを作成し、そのスレッドを使用して同期リクエストを行うことができます。
次の例は、Google ドライブへのファイル リクエストを同期呼び出しとして行う方法を示しています。
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 // ... } }
Wearable API にアクセスする
Wearable API は、ハンドヘルド デバイスとウェアラブル デバイスで実行されるアプリの通信チャネルを提供します。この API は、システムが送信および同期できる一連のデータ オブジェクトと、データレイヤを使用して重要なイベントをアプリに通知するリスナーで構成されています。Wearable API は、Android 4.3(API レベル 18)以降を搭載したデバイスで、ウェアラブル デバイスが接続され、Wear OS コンパニオン アプリがデバイスにインストールされている場合に使用できます。
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 } // ... }
他の Google API で Wearable API を使用する
アプリで他の Google API に加えて Wearable API を使用する場合は、addApiIfAvailable()
メソッドを呼び出して Wearable API を渡し、使用可能かどうかを確認します。このチェックを使用すると、API が使用できない場合のアプリの正常な処理に役立ちます。
次の例は、Drive API とともに Wearable 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();
上記の例では、Wearable API が使用できない場合でも、GoogleApiClient
は Google ドライブに正常に接続できます。GoogleApiClient
インスタンスを接続したら、API 呼び出しを行う前に Wearable API が使用可能であることを確認します。
boolean wearAvailable = mGoogleApiClient.hasConnectedApi(Wearable.API);
API 接続エラーを無視する
addApi()
を呼び出して、GoogleApiClient
がその API に正常に接続できない場合、そのクライアントの接続オペレーション全体が失敗し、onConnectionFailed()
コールバックがトリガーされます。
addApiIfAvailable()
を使用して、無視する API 接続エラーを登録できます。addApiIfAvailable()
で追加された API が、復元不可能なエラー(Wear の API_UNAVAILABLE
など)により接続に失敗した場合、その API は GoogleApiClient
から削除され、クライアントは他の API への接続に進みます。ただし、回復可能なエラー(OAuth 同意解決インテントなど)で API 接続が失敗した場合、クライアント接続オペレーションは失敗します。自動管理接続を使用する場合、GoogleApiClient
は可能であればこのようなエラーを解決しようとします。手動で管理する接続を使用する場合、解決インテントを含む ConnectionResult
が onConnectionFailed()
コールバックに配信されます。API 接続エラーが無視されるのは、エラーの解決策がなく、API が addApiIfAvailable()
で追加されている場合のみです。手動の接続エラー処理を実装する方法については、接続エラーを処理するをご覧ください。
addApiIfAvailable()
で追加された API が、接続された GoogleApiClient
インスタンスに常にあるとは限らないため、hasConnectedApi()
を使用してチェックを追加して、これらの API の呼び出しを保護する必要があります。クライアントの接続オペレーション全体が成功したときに特定の API が接続に失敗した理由を確認するには、getConnectionResult()
を呼び出して ConnectionResult
オブジェクトからエラーコードを取得します。クライアントがクライアントに接続していないときに API を呼び出すと、呼び出しは失敗し、ステータス コード API_NOT_AVAILABLE
が返されます。
addApiIfAvailable()
で追加する API に 1 つ以上のスコープが必要な場合は、addScope()
メソッドを使用するのではなく、addApiIfAvailable()
メソッド呼び出しのパラメータとしてそれらのスコープを追加します。この方法で追加されたスコープは、OAuth の同意を得る前に API 接続が失敗した場合、リクエストされない可能性があります。一方、addScope()
で追加されたスコープは常にリクエストされます。
手動で管理する接続
このガイドの大部分では、enableAutoManage
メソッドを使用して、自動的に解決されるエラーで自動管理接続を開始する方法について説明します。ほとんどの場合、これは Android アプリから Google API に接続する最も簡単で最適な方法です。ただし、アプリで Google API への手動管理接続を使用する必要がある場合もあります。
- アクティビティの外部から 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()
メソッドを呼び出す必要があります。アクティビティ コンテキストでは、アクティビティの onStart()
メソッドで connect()
を呼び出し、アクティビティの onStop()
メソッドで disconnect()
を呼び出すことをおすすめします。自動管理接続を使用すると、connect()
メソッドと disconnect()
メソッドが自動的に呼び出されます。
GoogleApiClient
を使用して、認証が必要な API(Google ドライブや Google Play Games など)に接続している場合、最初の接続試行が失敗し、ユーザー アカウントが指定されていないため、アプリに onConnectionFailed()
への呼び出しが SIGN_IN_REQUIRED
エラーとともに届く可能性があります。
接続エラーを処理する
アプリが onConnectionFailed()
コールバックの呼び出しを受信した場合は、指定された ConnectionResult
オブジェクトで hasResolution()
を呼び出す必要があります。true が返された場合は、ConnectionResult
オブジェクトで startResolutionForResult()
を呼び出して、ユーザーにエラーの解決のための即時対応をリクエストできます。この状況では、startResolutionForResult()
メソッドは startActivityForResult()
と同じように動作し、ユーザーがエラーを解決するのに役立つコンテキストに適したアクティビティを起動します(ユーザーがアカウントを選択するのに役立つアクティビティなど)。
hasResolution()
が false を返した場合、アプリは GoogleApiAvailability.getErrorDialog()
を呼び出して、エラーコードをこのメソッドに渡す必要があります。これにより、エラーに適した Google Play サービスが提供する Dialog
が返されます。ダイアログには、エラーを説明するメッセージが表示されるだけの場合もあれば、エラーを解決できるアクティビティを起動するアクションが表示される場合もあります(ユーザーが新しいバージョンの 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()
で提供されたメッセージを閉じると、アクティビティは 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
エラーの解決をユーザーがサポートできるようにアカウント選択ダイアログが表示されている間に、ユーザーが画面を回転することがあります。これによりアクティビティが再作成され、onStart()
メソッドが再び呼び出され、connect()
が再び呼び出されます。これにより startResolutionForResult()
が再度呼び出され、既存のアカウント選択ツールの前に別のアカウント選択ツールのダイアログが作成されます。
このブール値は、アクティビティ インスタンス間で保持されている場合にのみ、目的の目的を果たします。次のセクションでは、デバイスで発生する他のユーザー操作やイベントに関係なく、アプリのエラー処理状態を維持する方法について説明します。
エラーの解決中に状態を維持する
エラーの解決の試行が進行中である間に onConnectionFailed()
のコードが実行されないようにするには、アプリがすでにエラーの解決を試みているかどうかを追跡するブール値を保持する必要があります。
上記のコード例のように、アプリは startResolutionForResult()
を呼び出すたび、または GoogleApiAvailability.getErrorDialog()
からダイアログを表示するたびに、ブール値を true
に設定する必要があります。次に、アプリが onActivityResult()
コールバックで RESULT_OK
を受信したら、ブール値を false
に設定します。
アクティビティの再起動(ユーザーが画面を回転したときなど)でブール値を追跡するには、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 開発者サービスに手動で接続できるようになりました。