[この記事は Wolff Dobson、デベロッパーアドボケート による Android Developers Blog の記事 "Play Games Permissions are changing in 2016" を元に翻訳・加筆したものです。詳しくは元記事をご覧ください。]

私たちは、プレイヤーがサインインした際になぜか処理が円滑に進まなかったり、不必要にパーミッション要求を送信したりする頻度を減らすことができるように、段階を踏んで Games API を新しいモデルに移行する作業を進めています。新しい操作は次のようになります。
  • 一度端末上でサインインすれば、プレイするゲームごとに毎度サインインする必要はなくなります。
  • Google Play のゲーム サービスを利用する目的で、アカウントを Google+ へアップグレードする必要はなくなります。
  • 最初にサインインすれば、次に別のゲームをプレイするときに再びサインインする必要はありません。次のゲームへのサインインは、自動的に実行されます。
  • 注: Google Play の各ゲームアプリの設定で自動サインインをオフにすることもできます。
メリット:
  • ユーザーは最初にサインインすれば、原則として新しいゲームをプレイする際は、サインインの操作が不要になります。
  • 各ゲームでサインイン用の認証画面を用意する必要はありません。サインインはゲームの起動時に自動的に実行されます。

ユーザーのプライバシーを尊重し、本名が知られないように、プレイヤー ID の管理方法も、以下のとおり変更します。
  • 既存のプレイヤーの場合: Google+ ID でゲームにサインインしている場合は、その情報が引き継がれます(以前のドキュメントには「プレイヤー ID」と書かれている場合があります)。
  • 初めてゲームをプレイするプレイヤーの場合: ゲームは新規のプレイヤー ID を取得します。これは、以前使用していた ID とは別のものです。

発生する恐れのある問題

ゲームのサービスが中断したり、内容が変わったりすることはほとんどありません。ただしごくまれに、変更が必要なゲームもあります。

現時点で分かっている問題と、実際にその問題が発生した場合の解決策を以下に挙げます。

問題の一覧
  1. 不必要な Google+ のスコープの要求
    • 問題: ユーザーに確認を求める不要なポップアップ ウィンドウが表示される。
    • 解決策: どうしても必要にならない限り、スコープの追加を要求しない。
  2. Google Play のプレイヤー ID のゲーム以外の Google API への流用
    • 問題: 他のエンドポイントから有効なデータが返されない。
    • 解決策: Google Play のプレイヤー ID をゲーム以外の Google API に流用しない。
  3. サーバー上でのモバイル / クライアントのアクセス トークンの使用
    • 問題: アクセス トークンに必要な情報が含まれていない場合がある。
      • そもそも、このトークンは使用すべきではない。
    • 解決策: 新規の GetServerAuthCode API を使う。

以下で、各懸案事項について詳しく説明します。

問題: 不必要なスコープの要求

以前のバージョンのサンプルとドキュメントでは、次のように GoogleApiClient を作成していました。
 // Don’t do it this way!  
 GoogleApiClient gac = new GoogleApiClient.Builder(this, this, this)  
           .addApi(Games.API)  
           .addScope(Plus.SCOPE_PLUS_LOGIN) // The bad part  
           .build();  
 // Don’t do it this way!  

この場合、 plus.login スコープを個別にリクエストすることになります。 アプリが plus.login を要求すると、ユーザーに確認を求めるダイアログが表示されます。

解決策: 必要なスコープのみを要求する

GoogleApiClient を作成する処理から、不要なスコープと利用しない API を削除します。
 // This way you won’t get a consent screen  
 GoogleApiClient gac = new GoogleApiClient.Builder(this, this, this)  
           .addApi(Games.API)  
           .build();  
 // This way you won’t get a consent screen  

Google+ ユーザーの場合

各プレイヤーが実生活で使用している Google+ のソーシャル グラフ機能にアクセスする場合など、アプリで Google+ 固有の機能を使用する場合、新規ユーザーがゲームをプレイする際に Google+ のプロファイルが必要になります(サインインしている既存ユーザーが再度確認を求められることはありません)。

ゲームに Google+ アカウントが必要な場合は、そのゲームの Games.API 宣言部を以下のとおり変更します。
 .addApi(Games.API, new GamesOptions.Builder()  
                       .setRequireGooglePlus(true).build())  

この操作を実行すると、ゲームは必要なパーミッションまたはスコープを要求する処理を継続し、各プレイヤーが実生活で使用している Google+ のソーシャル グラフや実名のプロファイルも継続して使用できます。

問題: プレイヤー ID の別の ID への流用

Games.getCurrentPlayerId() API を呼び出すと、サインイン中のプレイヤーを識別するために使う識別子が返されます。

従来この値は、 Plus.PeopleApi.load などの他の API に渡すことができました。新しいモデルでは、この動作が変更され、 プレイヤー ID は、Games API のみで有効となります。


解決策: ID を流用しない

Games API( com.google.android.gms.games からアクセスするもの)は、すべてプレイヤー ID を使用します。また、このプレイヤー ID のみを使用している限り、新しく追加された ID に対する動作も保証されます。

問題: サーバー上でのモバイル / クライアントのアクセス トークンの使用

次のようなパターンが使われることがあります。
  • GoogleAuthUtil を使ってアクセス トークンを取得します。
  • このトークンをサーバーに送信します。
  • サーバー側で Google を呼び出し、認証を検証します。この処理で最もよく実行される方法は、https://www.googleapis.com/oauth2/v1/tokeninfo を呼び出して応答を待つことです。
そもそも、この処理を実行することは推奨されていません。また、スコープの変更後は、推奨の程度がさらに下がります。

上記の処理が推奨できない理由は次のとおりです。
  • アプリは、そのユーザーが現在使用しているアカウントを認識しなければならないので、GET_ACCOUNTS パーミッションを保持する必要があります。この仕様のために Android M (Marshmallow) では、アプリの実行時に連絡先へのアクセス許可を求められ、ユーザーは非常に煩わしい操作を強いられることになります。
  • tokeninfo エンドポイントの設計は、このユースケースにはあまり向いていません。本来はデバッグ用のツールとして設計されたもので、本番環境用の API ではありません。この API の使用には、将来的に制限が課せられる可能性があります。
  • 新しいモデルでは、トークンから user_id が返されない場合があります。たとえ 返された としても、その値は新しいプレイヤー ID と同じものではありません(上記の問題 2 を参照してください)。
  • トークンはいつ失効してもおかしくありません(アクセス トークンの失効時期は保証されていません)。
  • サーバー上でクライアント トークンを使う場合は、そのトークンが別のアプリケーションに授与されていないかどうかを確認するため、より多くの検証チェックが必要になります。

解決策: 新しく公開された GetServerAuthCode フローを使う

この解決策は広く知られており、基本的にはウェブでサーバー側の認証方式として推奨されているものと同じです。

  1. Google Play 開発者サービス SDK を最新バージョン(8.4.87 以降)にアップグレードします。
  2. サーバーのクライアント ID を作成していない場合は、作成します。
    1. Google デベロッパー コンソールにアクセスし、対象のプロジェクトを開きます。
    2. 左側のナビゲーションから [API Manager]、[Credentials] の順に選択します。
    3. [New Credentials]、[OAuth Client ID] の順に選択します。
    4. [Web Application] を選択し、このアプリケーションに覚えやすい名前を付けます。
    5. この時点で、このウェブ アプリケーションのクライアント ID には、サーバーのクライアント ID が割り当てられています。
  3. ゲーム側から、通常どおりの手順で GoogleApiClient に接続します。
  4. 接続の完了後、以下の API を呼び出します。
    1. Games.getGamesServerAuthCode(googleApiClient, “your_server_client_id”)
    2. もともと GoogleAuthUtil を使っていた場合は、おそらくバックグラウンドのスレッドで呼び出しているはずです。その場合、次のようなコードとなります。

 // Good way  
 {  
      GetServerAuthCodeResult result =   
           Games.getGamesServerAuthCode(gac, clientId).await();  
      if (result.isSuccess()) {  
           String authCode = result.getCode();  
            // Send code to server.  
   }  
 }  
 // Good way  


  1. 認証コードをサーバーに送信します。手順は以前とまったく同じです。
  2. サーバー上で、 https://www.googleapis.com/oauth2/v4/token への RPC を実行し、アクセス トークンの認証コードの受け渡しを行います。この処理には、 Google API クライアント ライブラリを使うことができます。
    1. サーバーのクライアント ID、サーバーのクライアント シークレット(サーバーのクライアント ID を作成したときにデベロッパー コンソールに表示されていたもの)、認証コードを送信する必要があります。
    2. 詳細はこちらをご覧ください。
    3. 実際には、  Google API クライアント ライブラリ を使えばこの処理を簡単に行うことができます。
  3. アクセス トークンの取得後、そのトークンを使って www.googleapis.com/games/v1/applications/<app_id>/verify/ を呼び出します。
    1. 認証トークンは、以下の形式でヘッダーに埋め込みます。
      1. "Authorization:OAuth <access_token>"
    2. この処理で返された値に、そのユーザーのプレイヤー ID が含まれています。このプレイヤー ID が正しい値です。
    3. このアクセス トークンは必要に応じて、サーバー間通信で利用することができます。
アクセス トークンが既にウェブ アプリに発行されている場合、この API はステータス コード「200」のみを返します。

まとめ

重要な点は、明示的に Google+ の機能に依存するゲームでない限り、何もする必要がないということです。API の機能に変更はなく、ただサインインの操作がよりスムーズになるだけです。

ただし、次の点は考慮する必要があります。
  • Google+ スコープを要求していながら実際には使用していない場合は、今後はその要求を中止することを推奨します。
  • クライアントのアクセス トークンをサーバーに送信している場合は、 getGamesServerAuthCode() を使うことを強く推奨します。
ありがとうございました。これからも面白いゲームを制作してください。

Posted by Yoshifumi Yamaguchi - Developer Relations Team