Android ゲームでのログイン

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

プレーヤーのログインの実装

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

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

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

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

    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 ログイン 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_REQUIRED のステータス コードで ApiException を返した場合、プレーヤーを再認証する必要があります。これを行うには、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 ゲームサービスでゲーム内のビュー内のポップアップを起動できるようにするには、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.
        }
      });
}