Android ゲームにログインする

Google Play Games サービスの機能にアクセスするには、ログイン済みプレーヤーのアカウントをゲームから提供する必要があります。プレーヤーが認証されていない場合、Google Play Games 開発者サービスの API を呼び出すときにゲームでエラーが発生することがあります。このドキュメントでは、ゲームにシームレスなログイン エクスペリエンスを実装する方法について説明します。

プレーヤーのログインを実装する

GoogleSignInClient クラスは、現在ログインしているプレーヤーのアカウントを取得し、デバイス上のアプリでプレーヤーがログインしていない場合はログインするためのメイン エントリ ポイントです。

ログイン クライアントを作成する手順は次のとおりです。

  1. 次のコード スニペットに示すように、GoogleSignInOptions オブジェクトを使用してログイン クライアントを作成します。ログインを構成するには、GoogleSignInOptions.BuilderGoogleSignInOptions.DEFAULT_GAMES_SIGN_IN を指定する必要があります。

    GoogleSignInOptions signInOptions = GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN;
  2. SnapshotsClient を使用する場合は、次のコード スニペットに示すように、GoogleSignInOptions.Builder.requestScopes(Games.SCOPE_GAMES_SNAPSHOTS) を追加します。

    GoogleSignInOptions  signInOptions =
        new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN)
            .requestScopes(Games.SCOPE_GAMES_SNAPSHOTS)
            .build();
  3. GoogleSignIn.getClient() メソッドを呼び出し、前の手順で構成したオプションを渡します。呼び出しが成功すると、Google Sign-In API は GoogleSignInClient のインスタンスを返します。

プレーヤーがすでにログインしているかどうかを確認する

現在のデバイスでアカウントがすでにログインしているかどうかは GoogleSignIn.getLastSignedInAccount() で確認できます。また、このアカウントに必要な権限がすでに付与されているかどうかは GoogleSignIn.hasPermissions() で確認できます。両方の条件が true の場合(つまり、getLastSignedInAccount() が null 以外の値を返して hasPermissions()true を返す場合)、デバイスがオフラインの場合でも、getLastSignedInAccount() から返されたアカウントを安全に使用できます。

サイレント ログインを実行する

silentSignIn() を呼び出して、現在ログインしているプレーヤーのアカウントを取得し、別のデバイスでアプリに正常にログインしている場合は、ユーザー インターフェースを表示せずにプレーヤーのログインを試すことができます。

silentSignIn() メソッドは Task<GoogleSignInAccount> を返します。タスクが完了したら、前に宣言した GoogleSignInAccount フィールドを、タスクが結果として返すログイン アカウントに設定するか、ログイン ユーザーがいないことを示す null に設定します。

サイレント ログインが失敗した場合は、必要に応じてログイン インテントを送信してログイン ユーザー インターフェースを表示できます。詳しくは、インタラクティブなログインを実行するをご覧ください。

アクティビティがフォアグラウンドにない場合、ログイン済みプレーヤーの状態が変更される可能性があるため、アクティビティの onResume() メソッドから silentSignIn() を呼び出すことをおすすめします。

サイレント ログインを実行する手順は次のとおりです。

  1. GoogleSignInClientsilentSignIn() メソッドを呼び出して、サイレント ログインフローを開始します。この呼び出しは、サイレント ログインが成功した場合に、GoogleSignInAccount を含む Task<GoogleSignInAccount> オブジェクトを返します。
  2. OnCompleteListener をオーバーライドして、プレーヤーのログインの成功または失敗を処理します。
    • ログイン タスクが成功した場合は、getResult() を呼び出して GoogleSignInAccount オブジェクトを取得します。
    • ログインに失敗した場合は、ログイン インテントを送信して、インタラクティブなログイン フローを開始できます。使用できるその他のコールバック リスナーの一覧については、Tasks API デベロッパー ガイドTask API リファレンスをご覧ください。

次のコード スニペットは、アプリがサイレント ログインを実行する方法を示しています。

private void signInSilently() {
  GoogleSignInOptions signInOptions = GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN;
  GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(this);
  if (GoogleSignIn.hasPermissions(account, signInOptions.getScopeArray())) {
    // Already signed in.
    // The signed in account is stored in the 'account' variable.
    GoogleSignInAccount signedInAccount = account;
  } else {
    // Haven't been signed-in before. Try the silent sign-in first.
    GoogleSignInClient signInClient = GoogleSignIn.getClient(this, signInOptions);
    signInClient
        .silentSignIn()
        .addOnCompleteListener(
            this,
            new OnCompleteListener<GoogleSignInAccount>() {
              @Override
              public void onComplete(@NonNull Task<GoogleSignInAccount> task) {
                if (task.isSuccessful()) {
                  // The signed in account is stored in the task's result.
                  GoogleSignInAccount signedInAccount = task.getResult();
                } else {
                  // Player will need to sign-in explicitly using via UI.
                  // See [sign-in best practices](http://developers.google.com/games/services/checklist) for guidance on how and when to implement Interactive Sign-in,
                  // and [Performing Interactive Sign-in](http://developers.google.com/games/services/android/signin#performing_interactive_sign-in) for details on how to implement
                  // Interactive Sign-in.
                }
              }
            });
  }
}

@Override
protected void onResume() {
  super.onResume();
  signInSilently();
}

サイレント ログインが失敗した場合は、getException() を呼び出して、詳細なステータス コードを含む ApiException を取得できます。ステータス コード CommonStatusCodes.SIGN_IN_REQUIRED は、プレーヤーがログインするために明示的な操作を行う必要があることを示します。この場合、アプリは次のセクションで説明するように、インタラクティブなログインフローを開始する必要があります。

インタラクティブなログインを実行する

プレーヤーの操作でログインするには、アプリでログイン インテントを起動する必要があります。成功すると、Google Sign-In API によってユーザー インターフェースが表示され、ログインするための認証情報を入力するようプレーヤーに求めるメッセージが表示されます。このアプローチでは、ログイン アクティビティがアプリに代わって、Google Play 開発者サービスの更新が必要になった場合や同意プロンプトを表示する必要がある場合などのシナリオを処理するため、アプリの開発が簡素化されます。結果は onActivityResult コールバックを介して返されます。

インタラクティブにログインするには、次の手順を行います。

  1. GoogleSignInClientgetSigninIntent() を呼び出してログイン インテントを取得し、startActivity() を呼び出してそのインテントを渡します。次のコード スニペットは、アプリでインタラクティブなログイン フローを起動する方法を示しています。

    private void startSignInIntent() {
      GoogleSignInClient signInClient = GoogleSignIn.getClient(this,
          GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN);
      Intent intent = signInClient.getSignInIntent();
      startActivityForResult(intent, RC_SIGN_IN);
    }
  2. onActivityResult() コールバックで、返されたインテントの結果を処理します。

    • ログイン結果が成功した場合は、GoogleSignInResult から GoogleSignInAccount オブジェクトを取得します。
    • ログイン結果が成功しなかった場合は、ログイン エラーを処理する必要があります(たとえば、アラートにエラー メッセージを表示するなど)。次のコード スニペットは、アプリがプレーヤーのログイン結果を処理する方法を示しています。
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
      super.onActivityResult(requestCode, resultCode, data);
      if (requestCode == RC_SIGN_IN) {
        GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
        if (result.isSuccess()) {
          // The signed in account is stored in the result.
          GoogleSignInAccount signedInAccount = result.getSignInAccount();
        } else {
          String message = result.getStatus().getStatusMessage();
          if (message == null || message.isEmpty()) {
            message = getString(R.string.signin_other_error);
          }
          new AlertDialog.Builder(this).setMessage(message)
              .setNeutralButton(android.R.string.ok, null).show();
        }
      }
    }

プレーヤー情報を取得する

Google Sign-In API から返される GoogleSignInAccount には、プレーヤー情報は含まれません。ゲームでプレーヤーの表示名やプレーヤー ID などのプレーヤー情報を使用している場合は、次の手順でその情報を取得できます。

  1. getPlayersClient() メソッドを呼び出し、パラメータとして GoogleSignInAccount を渡して PlayersClient オブジェクトを取得します。
  2. PlayersClient メソッドを使用して、プレーヤーの情報を含む Player オブジェクトを非同期で読み込みます。たとえば、getCurrentPlayer() を呼び出して、現在ログインしているプレーヤーを読み込むことができます。タスクがステータス コード SIGN_IN_REQUIREDApiException を返す場合、プレーヤーの再認証が必要であることを示します。これを行うには、GoogleSignInClient.getSignInIntent() を呼び出して、プレーヤーをインタラクティブにログインさせます。
  3. タスクが Player オブジェクトを正常に返した場合は、Player オブジェクトのメソッドを呼び出して、特定のプレーヤーの詳細(getDisplayName()getPlayerId() など)を取得できます。

ログインボタンを表示する

ゲームに標準の Google ログインボタンを表示するには、次のいずれかの方法を使用します。

ユーザーがログインボタンをクリックすると、インタラクティブなログインを実行するで説明されているように、ゲームはログイン インテントを送信してログインフローを開始する必要があります。

次のコード スニペットは、アクティビティの onCreate() メソッドにログイン ボタンを追加する方法を示しています。

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_sign_in);
  findViewById(R.id.sign_in_button).setOnClickListener(this);
  findViewById(R.id.sign_out_button).setOnClickListener(this);
}

次のコード スニペットは、ユーザーがログインボタンをクリックしたときにログイン インテントを送信する方法を示しています。

@Override
public void onClick(View view) {
  if (view.getId() == R.id.sign_in_button) {
    // start the asynchronous sign in flow
    startSignInIntent();
  } else if (view.getId() == R.id.sign_out_button) {
    // sign out.
    signOut();
    // show sign-in button, hide the sign-out button
    findViewById(R.id.sign_in_button).setVisibility(View.VISIBLE);
    findViewById(R.id.sign_out_button).setVisibility(View.GONE);
  }
}

ゲームのポップアップを表示する

ゲームにポップアップ ビューを表示するには、GamesClient クラスを使用します。たとえば、ゲームで「ようこそ」や「実績をアンロックしました」というポップアップを表示できます。Google Play Games サービスがゲームのビューでポップアップを起動できるようにするには、setViewForPopups() メソッドを呼び出します。setGravityForPopups() を呼び出すと、ポップアップを画面のどこに表示するかをさらにカスタマイズできます。

プレーヤーをログアウトする

ログアウトは、GoogleSignInClientsignOut() メソッドを呼び出すことによって行われます。

private void signOut() {
  GoogleSignInClient signInClient = GoogleSignIn.getClient(this,
      GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN);
  signInClient.signOut().addOnCompleteListener(this,
      new OnCompleteListener<Void>() {
        @Override
        public void onComplete(@NonNull Task<Void> task) {
          // at this point, the user is signed out.
        }
      });
}