登入 Android 遊戲

如果要存取 Google Play 遊戲服務功能,遊戲必須提供已登入玩家的帳戶。如果玩家未經驗證,遊戲可能會在呼叫 Google Play 遊戲服務 API 時發生錯誤。本文件說明如何在遊戲中實作順暢的登入體驗。

實作玩家登入

GoogleSignInClient 類別是擷取目前已登入的玩家帳戶的主要進入點,如果玩家尚未在裝置上登入應用程式,則可讓玩家登入。

如要建立登入用戶端,請按照下列步驟操作:

  1. 如以下程式碼片段所示,請透過 GoogleSignInOptions 物件建立登入用戶端。如要在 GoogleSignInOptions.Builder 中設定登入功能,您必須指定 GoogleSignInOptions.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() 傳回非空值,而 hasPermissions() 傳回 true,即使裝置處於離線狀態,您也可以安全地使用 getLastSignedInAccount() 傳回的帳戶。

執行自動登入

您可以呼叫 silentSignIn() 來擷取目前登入的玩家帳戶,並嘗試讓玩家登入,但不顯示使用者介面 (如果玩家已在其他裝置上成功登入您的應用程式)。

silentSignIn() 方法會傳回 Task<GoogleSignInAccount>。在工作完成後,您可以將先前宣告的 GoogleSignInAccount 欄位設為工作傳回的登入帳戶,或設為 null,表示沒有登入的使用者。

如果無訊息登入嘗試失敗,您可以選擇傳送登入意圖,顯示登入使用者介面,如「執行互動式登入」一節所述。

由於活動不在前景時,已登入的播放器狀態可能會變更,因此建議您從活動的 onResume() 方法呼叫 silentSignIn()

如要執行無聲登入作業,請按照下列步驟操作:

  1. GoogleSignInClient 呼叫 silentSignIn() 方法,啟動無訊息登入流程。 如果靜默登入成功,這個呼叫會傳回 Task<GoogleSignInAccount> 物件,其中包含 GoogleSignInAccount
  2. 覆寫 OnCompleteListener,處理玩家登入的成功或失敗情況。

下列程式碼片段說明應用程式如何執行無訊息登入:

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() 取得包含詳細狀態碼的 ApiExceptionCommonStatusCodes.SIGN_IN_REQUIRED 狀態碼表示玩家需要採取明確行動才能登入。在這種情況下,應用程式應啟動互動式登入流程,詳情請參閱下一節。

執行互動式登入

如要透過玩家互動登入,應用程式必須啟動登入意圖。如果成功,Google Sign-In API 會顯示使用者介面,提示玩家輸入登入憑證。這種做法可簡化應用程式開發作業,因為登入活動會代替應用程式處理需要更新 Google Play 服務或顯示同意提示的情況。結果會透過 onActivityResult 回呼傳回。

如要以互動方式登入,請按照下列步驟操作:

  1. GoogleSignInClient 上呼叫 getSigninIntent(),取得登入意圖,然後呼叫 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 登入 API 傳回的 GoogleSignInAccount 不含任何玩家資訊。如果您的遊戲使用玩家資訊 (例如玩家的顯示名稱和玩家 ID),您可以按照下列步驟擷取這些資訊。

  1. 呼叫 getPlayersClient() 方法,並將 GoogleSignInAccount 做為參數傳入,取得 PlayersClient 物件。
  2. 使用 PlayersClient 方法,以非同步方式載入含有玩家資訊的 Player 物件。舉例來說,您可以呼叫 getCurrentPlayer() 來載入目前登入的玩家。如果工作傳回 ApiException,狀態碼為 SIGN_IN_REQUIRED,表示玩家需要重新驗證。如要執行此操作,請呼叫 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(),進一步自訂彈出式視窗在畫面中顯示的位置。

登出播放器

您可以透過在 GoogleSignInClient 上呼叫 signOut() 方法,完成登出程序。

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.
        }
      });
}