您可以使用 Google Play 遊戲服務讓玩家登錄基於 Firebase 構建並用 C++ 編寫的 Android 遊戲。要使用 Google Play 遊戲服務登錄 Firebase,首先使用 Google Play 遊戲登錄播放器,然後在執行此操作時請求 OAuth 2.0 授權代碼。然後,將授權代碼傳遞給PlayGamesAuthProvider
以生成 Firebase 憑據,您可以使用該憑據向 Firebase 進行身份驗證。
在你開始之前
在使用Firebase Authentication之前,您需要:
註冊您的 C++ 項目並將其配置為使用 Firebase。
如果您的 C++ 項目已經使用 Firebase,那麼它已經針對 Firebase 進行了註冊和配置。
將Firebase C++ SDK添加到您的 C++ 項目。
請注意,將 Firebase 添加到您的 C++ 項目涉及Firebase 控制台和您打開的 C++ 項目中的任務(例如,您從控制台下載 Firebase 配置文件,然後將它們移動到您的 C++ 項目中)。
設置您的 Firebase 項目
如果您還沒有,請在 Firebase 控制台的“設置”頁面中設置遊戲的 SHA-1 指紋。
您可以使用 gradle
signingReport
命令獲取簽名證書的 SHA 哈希值:./gradlew signingReport
啟用 Google Play 遊戲作為登錄提供商:
在 Firebase 控制台中,打開身份驗證部分。
生成並獲取項目的 Web 服務器客戶端 ID 和客戶端密碼:
在登錄方法選項卡中,啟用Google登錄提供程序。
從Google登錄提供商處複製網絡服務器客戶端 ID 和密碼。
在登錄方法選項卡中,啟用Play 遊戲登錄提供程序,並指定您在上一步中獲得的項目的 Web 服務器客戶端 ID 和客戶端密碼。
使用您的 Firebase 應用信息配置 Play 遊戲服務
在Google Play Console中,打開您的 Google Play 應用或創建一個。
在發展部分,點擊Play 遊戲服務 > 設置和管理 > 配置。
點擊Yes, my game already uses Google APIs ,從列表中選擇您的 Firebase 項目,然後點擊Use 。
在 Play 遊戲服務配置頁面上,單擊添加憑據。
- 選擇遊戲服務器類型。
- 在OAuth 客戶端字段中,選擇您項目的 Web 客戶端 ID。請確保這與您在啟用 Play 遊戲登錄時指定的客戶端 ID 相同。
- 保存您的更改。
仍然在 Play 遊戲服務配置頁面上,再次單擊添加憑據。
- 選擇安卓類型。
- 在OAuth 客戶端字段中,選擇您項目的 Android 客戶端 ID。 (如果您沒有看到您的 Android 客戶端 ID,請確保您在 Firebase 控制台中設置了您遊戲的 SHA-1 指紋。)
- 保存您的更改。
在測試人員頁面上,添加需要在您的遊戲發佈到 Play 商店之前能夠登錄您的遊戲的任何用戶的電子郵件地址。
將 Play 遊戲登錄集成到您的遊戲中
在您可以讓玩家登錄到您的遊戲之前,您必須集成 Google Play 遊戲登錄。
向 C++ Android 項目添加對 Play 遊戲登錄的支持的最簡單且推薦的方法是使用Google 登錄 C++ SDK 。
要使用 Google 登錄 C++ SDK 將 Play 遊戲登錄添加到您的遊戲中,請執行以下操作:
克隆或下載Google Sign-in Unity 插件存儲庫,其中還包含 C++ SDK。
使用 Android Studio 或
gradlew build
構建包含在staging/native/
目錄中的項目。該構建將其輸出複製到名為
google-signin-cpp
的目錄。在遊戲的本機代碼生成文件中包含 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構建
在你的
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)
接下來,包含 C++ SDK 所需的 Java 幫助程序組件。
為此,在您的項目級
build.gradle
文件中,將 SDK 構建輸出目錄添加為本地存儲庫:allprojects { repositories { // ... flatDir { dirs 'path/to/google-signin-cpp' } } }
並且,在您的模塊級
build.gradle
文件中,將輔助組件聲明為依賴項:dependencies { implementation 'com.google.android.gms:play-services-auth:20.7.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') }
然後,在您的遊戲中,配置
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);
最後,調用
SignIn()
讓玩家登錄 Play Games: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 Games 登錄後,您可以使用授權碼向 Firebase 進行身份驗證。
玩家使用 Play Games 成功登錄後,獲取玩家帳戶的授權碼。
然後,將 Play 遊戲服務中的授權代碼換成 Firebase 憑證,並使用 Firebase 憑證對玩家進行身份驗證:
firebase::auth::Credential credential = firebase::auth::PlayGamesAuthProvider::GetCredential(server_auth_code); firebase::Future<firebase::auth::AuthResult> result = auth->SignInAndRetrieveDataWithCredential(credential);
如果您的程序有一個定期運行的更新循環(比如每秒 30 或 60 次),您可以使用
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); }
下一步
用戶首次登錄後,系統會創建一個新用戶帳戶並將其鏈接到他們的 Play 遊戲 ID。這個新帳戶存儲為您的 Firebase 項目的一部分,可用於在您項目中的每個應用程序中識別用戶。
在您的遊戲中,您可以從firebase::auth::User
對象獲取用戶的 Firebase UID:
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 實時數據庫和雲存儲安全規則中,您可以從auth
變量中獲取登錄用戶的唯一用戶 ID,並使用它來控制用戶可以訪問的數據。
要獲取用戶的 Play 遊戲玩家信息或訪問 Play 遊戲服務,請使用Google Play 遊戲服務 C++ SDK提供的 API。
要註銷用戶,請調用SignOut()
:
auth->SignOut();