透過 C++ 使用 Google Play 遊戲服務進行驗證

您可以使用 Google Play 遊戲服務讓玩家登入 Android 遊戲 建構而成如何使用 Google Play 遊戲服務登入功能 請先使用 Google Play 遊戲登入玩家,再要求接收 驗證 OAuth 2.0 驗證碼。接著,將驗證碼傳遞至 PlayGamesAuthProvider 產生 Firebase 憑證,您可以使用該憑證執行以下操作 進行驗證

事前準備

使用前 Firebase Authentication、 請完成下列操作:

  • 註冊 C++ 專案,並將其設為使用 Firebase。

    如果您的 C++ 專案已使用 Firebase,表示該專案已註冊, 設定 Firebase 專屬的容器

  • 在 C++ 專案中新增 Firebase C++ SDK

,瞭解如何調查及移除這項存取權。

請注意,將 Firebase 新增至 C++ 專案時,需要執行 Firebase 控制台,然後在開啟的 C++ 專案中 (例如,下載 控制台中的 Firebase 設定檔,然後將這些檔案移至 C++ 專案)。

設定 Firebase 專案

  1. 如果您尚未設定遊戲的 SHA-1 指紋,請先在 「設定」頁面 Firebase控制台中就能保留這項資訊

    您可以使用 Gradle 取得簽署憑證的 SHA 雜湊 signingReport 指令:

    ./gradlew signingReport

  2. Google Play Games 設為登入提供者:

    1. Firebase 控制台中,開啟 Authentication 專區

    2. 產生並取得專案的網路伺服器用戶端 ID 和用戶端 密鑰:

      1. 在「Sign in method」分頁中啟用 Google 登入功能 。

      2. 複製 Google 登入中的網路伺服器用戶端 ID 和密鑰 。

    3. 在「Sign in method」分頁中啟用 Play Games ,並指定專案的網路伺服器用戶端 ID,然後 用戶端密碼。

使用 Firebase 應用程式資訊設定 Play Games services

  1. Google Play 控制台, 請開啟或建立一個「Google Play」應用程式。

  2. 在「拓展」部分中,按一下 Play Games services >設定和管理 >設定

  3. 按一下「是,我的遊戲已在使用 Google API」,選取您的 Firebase 然後按一下「使用」

  4. Play Games services 設定頁面中按一下 新增憑證

    1. 選取「遊戲伺服器」類型。
    2. 在「OAuth 用戶端」欄位中,選取專案的網路用戶端 ID。成為 這是您啟用功能時指定的用戶端 ID 目前登入次數:Play Games
    3. 儲存變更。
  5. 在「Play Games services」設定頁面,按一下 重新新增憑證

    1. 選取「Android」類型。
    2. 在「OAuth 用戶端」欄位中,選取專案的 Android 用戶端 ID。 (如果找不到您的 Android 用戶端 ID,請確認您已設定遊戲的 Firebase 控制台中的 SHA-1 指紋)。
    3. 儲存變更。
  6. 在「測試人員」頁面中,為需要測試的使用者新增電子郵件地址 。 Play Store

將 Play 遊戲登入程序整合至遊戲

您必須先整合 Google Play,才能讓玩家登入遊戲 遊戲登入。

如要在 C++ 中新增 Play 遊戲登入支援功能,這是最簡單的建議方式 Android 專案是使用 Google 登入 C++ SDK

如要使用 Google 登入 C++ SDK 將 Play 遊戲登入機制新增至遊戲,請 包括:

  1. 複製或下載 Google 登入 Unity 外掛程式存放區。 其中也包含 C++ SDK

  2. 使用以下方法建立 staging/native/ 目錄中包含的專案: Android Studio 或 gradlew build

    建構作業會將輸出內容複製到名為 google-signin-cpp 的目錄。

  3. 在遊戲的原生程式碼 make 檔案中加入 Google 登入 C++ SDK:

    CMake

    在頂層 CMakeLists.txt 檔案中:

    set(GSI_PACKAGE_DIR "/path/to/google-signin-cpp")
    add_library(lib-google-signin-cpp STATIC IMPORTED) set_target_properties(lib-google-signin-cpp PROPERTIES IMPORTED_LOCATION     ${GSI_PACKAGE_DIR}/lib/${ANDROID_ABI}/libgoogle-signin-cpp.a )
    ...
    target_link_libraries(     ...     lib-google-signin-cpp)

    ndk-build

    Android.mk 檔案中:

    include $(CLEAR_VARS)
    LOCAL_MODULE := google-signin-cpp
    GSI_SDK_DIR := /path/to/google-signin-cpp
    LOCAL_SRC_FILES := $(GSI_SDK_DIR)/lib/$(TARGET_ARCH_ABI)/libgoogle-signin-cpp.a
    LOCAL_EXPORT_C_INCLUDES := $(GSI_SDK_DIR)/include
    include $(PREBUILT_STATIC_LIBRARY)
    

  4. 接下來,請加入 Java 輔助元件,這是 C++ SDK 的必要元件。

    方法是在專案層級的 build.gradle 檔案中新增 SDK 版本 做為本機存放區使用:

    allprojects {
        repositories {
            // ...
            flatDir {
                dirs 'path/to/google-signin-cpp'
            }
        }
    }
    

    接著,在模組層級 build.gradle 檔案中宣告輔助元件 做為依附元件:

    dependencies {
        implementation 'com.google.android.gms:play-services-auth:21.2.0'
        // Depend on the AAR built with the Google Sign-in SDK in order to add
        // the Java helper classes, which are used by the C++ library.
        compile(name:'google-signin-cpp-release', ext:'aar')
    }
    
  5. 然後,在遊戲中設定 GoogleSignIn 物件以使用 Play 遊戲 登入以及擷取伺服器驗證碼:

    #include "google_signin.h"
    #include "future.h"
    
    using namespace google::signin;
    
    // ...
    
    GoogleSignIn::Configuration config = {};
    config.web_client_id = "YOUR_WEB_CLIENT_ID_HERE";
    config.request_id_token = false;
    config.use_game_signin = true;
    config.request_auth_code = true;
    
    GoogleSignIn gsi = GoogleSignIn(GetActivity(), GetJavaVM());
    gsi.Configure(config);
    
  6. 最後,呼叫 SignIn() 以簽署玩家的 Play 遊戲:

    Future<GoogleSignIn::SignInResult> &future = gsi.SignIn();
    

    解析 SignIn() 傳回的 Future 後,您就可以取得伺服器驗證 傳回的結果:

    if (!future.Pending()) {
        const GoogleSignIn::StatusCode status =
                static_cast<GoogleSignIn::StatusCode>(future.Status());
        if (status == GoogleSignIn::kStatusCodeSuccess) {
            // Player successfully signed in to Google Play! Get auth code to
            //   pass to Firebase
            const GoogleSignIn::SignInResult result =
                    static_cast<GoogleSignIn::SignInResult>(future.Result());
            const char* server_auth_code = result.User.GetServerAuthCode();
        }
    }
    

透過 Firebase 驗證

玩家登入 Play 遊戲後,您可以使用這組驗證碼 進行驗證

  1. 玩家成功使用 Play 遊戲登入後,取得驗證 代碼。

  2. 接著,使用 Play 遊戲服務交換驗證碼以供 Firebase 使用 憑證,並使用 Firebase 憑證驗證玩家:

    firebase::auth::Credential credential =
        firebase::auth::PlayGamesAuthProvider::GetCredential(server_auth_code);
    firebase::Future<firebase::auth::AuthResult> result =
        auth->SignInAndRetrieveDataWithCredential(credential);
    
  3. 如果您的程式有定期執行的更新迴圈 (例如 30 或 60) 每秒可執行 1 次 Auth::SignInAndRetrieveDataWithCredentialLastResult:

    firebase::Future<firebase::auth::AuthResult> result =
        auth->SignInAndRetrieveDataWithCredentialLastResult();
    if (result.status() == firebase::kFutureStatusComplete) {
      if (result.error() == firebase::auth::kAuthErrorNone) {
        firebase::auth::AuthResult auth_result = *result.result();
        printf("Sign in succeeded for `%s`\n",
               auth_result.user.display_name().c_str());
      } else {
        printf("Sign in failed with error '%s'\n", result.error_message());
      }
    }

    或者,如果您的計畫是依據事件推動,建議您 在 Future 註冊回呼

在 Future 上註冊回呼

某些程式包含可呼叫每秒 30 或 60 次的 Update 函式。 舉例來說,許多遊戲都採用這個模型。這些程式可以呼叫 LastResult 函式來輪詢非同步呼叫。 不過,如果您的程式是以事件驅動,建議您註冊回呼函式。 Future 完成後,會呼叫回呼函式。
void OnCreateCallback(const firebase::Future<firebase::auth::User*>& result,
                      void* user_data) {
  // The callback is called when the Future enters the `complete` state.
  assert(result.status() == firebase::kFutureStatusComplete);

  // Use `user_data` to pass-in program context, if you like.
  MyProgramContext* program_context = static_cast<MyProgramContext*>(user_data);

  // Important to handle both success and failure situations.
  if (result.error() == firebase::auth::kAuthErrorNone) {
    firebase::auth::User* user = *result.result();
    printf("Create user succeeded for email %s\n", user->email().c_str());

    // Perform other actions on User, if you like.
    firebase::auth::User::UserProfile profile;
    profile.display_name = program_context->display_name;
    user->UpdateUserProfile(profile);

  } else {
    printf("Created user failed with error '%s'\n", result.error_message());
  }
}

void CreateUser(firebase::auth::Auth* auth) {
  // Callbacks work the same for any firebase::Future.
  firebase::Future<firebase::auth::AuthResult> result =
      auth->CreateUserWithEmailAndPasswordLastResult();

  // `&my_program_context` is passed verbatim to OnCreateCallback().
  result.OnCompletion(OnCreateCallback, &my_program_context);
}
如有需要,回呼函式也可以是 lambda。
void CreateUserUsingLambda(firebase::auth::Auth* auth) {
  // Callbacks work the same for any firebase::Future.
  firebase::Future<firebase::auth::AuthResult> result =
      auth->CreateUserWithEmailAndPasswordLastResult();

  // The lambda has the same signature as the callback function.
  result.OnCompletion(
      [](const firebase::Future<firebase::auth::User*>& result,
         void* user_data) {
        // `user_data` is the same as &my_program_context, below.
        // Note that we can't capture this value in the [] because std::function
        // is not supported by our minimum compiler spec (which is pre C++11).
        MyProgramContext* program_context =
            static_cast<MyProgramContext*>(user_data);

        // Process create user result...
        (void)program_context;
      },
      &my_program_context);
}

後續步驟

使用者首次登入後,系統會建立新的使用者帳戶 連結 Google Play 遊戲。這個新帳戶會儲存在您的 Firebase 專案的專用 ID,可用來識別應用程式內所有應用程式的使用者 專案。

在遊戲中,您可以透過 firebase::auth::User 物件:

firebase::auth::User user = auth->current_user();
if (user.is_valid()) {
  std::string playerName = user.displayName();

  // The user's ID, unique to the Firebase project.
  // Do NOT use this value to authenticate with your backend server,
  // if you have one. Use firebase::auth::User::Token() instead.
  std::string uid = user.uid();
}

在 Firebase 即時資料庫和 Cloud Storage 安全性規則中,您可以 已登入使用者在 auth 變數中的不重複使用者 ID,並使用該 ID 來 控制使用者可以存取哪些資料

如要取得使用者的 Play 遊戲玩家資訊或存取 Play 遊戲服務, 使用 Google Play 遊戲服務 C++ SDK 提供的 API。

如要將使用者登出,請呼叫 SignOut()

auth->SignOut();