אימות באמצעות Google Play Games Services עם C++

אתם יכולים להשתמש בשירותי Google Play Games כדי לאפשר לשחקנים להיכנס למשחק ל-Android שנבנה ב-Firebase ונכתב ב-C++. כדי להשתמש בכניסה באמצעות שירותי Google Play Games ב-Firebase, קודם צריך להיכנס עם השחקן באמצעות Google Play Games ולבקש קוד אימות של OAuth 2.0. לאחר מכן, מעבירים את קוד האימות אל PlayGamesAuthProvider כדי ליצור פרטי כניסה ל-Firebase, שבהם אפשר להשתמש כדי לבצע אימות באמצעות Firebase.

לפני שמתחילים

לפני שמשתמשים Firebase Authentication, צריך:

  • רושמים את פרויקט C++ ומגדירים אותו לשימוש ב-Firebase.

    אם כבר משתמשים ב-Firebase בפרויקט C++‎, הוא כבר רשום ב-Firebase ועבר הגדרה.

  • מוסיפים את Firebase C++ SDK לפרויקט ב-C++.

שימו לב שהוספת Firebase לפרויקט C++ כוללת משימות גם במסוף Firebase ובפרויקט C++ הפתוח (לדוגמה, אפשר להוריד קובצי תצורה של Firebase מהמסוף, ואז מעבירים אותם לפרויקט C++ .

הגדרת פרויקט Firebase

  1. אם עדיין לא עשית זאת, עליך להגדיר את טביעת האצבע SHA-1 של המשחק הדף הגדרות במסוף Firebase.

    אפשר להשתמש בגרד הפקודה signingReport:

    ./gradlew signingReport

  2. מפעילים את Google Play Games כספק כניסה:

    1. במסוף Firebase, פותחים את הקטע Authentication.

    2. יצירה והשגת מזהה הלקוח והלקוח של שרת האינטרנט של הפרויקט Secret:

      1. בכרטיסייה שיטת כניסה, מפעילים את פרטי הכניסה של Google. ספק.

      2. מעתיקים את מזהה הלקוח והמפתח הסודי של שרת האינטרנט מהספק של Google לכניסה.

    3. בכרטיסייה שיטת כניסה, מפעילים את האפשרות Play Games. ספק הכניסה, ולציין את מזהה הלקוח של שרת האינטרנט של הפרויקט סוד לקוח, שקיבלתם בשלב האחרון.

הגדרת Play Games services עם פרטי האפליקציה מ-Firebase

  1. ב מסוף Google Play, אפשר לפתוח את אפליקציית Google Play או ליצור אפליקציה חדשה.

  2. בקטע צמיחה לוחצים על Play Games services > הגדרה ו ניהול > הגדרה.

  3. לוחצים על כן, המשחק שלי כבר משתמש ב-Google APIs ובוחרים את Firebase בפרויקט ברשימה, ואז לוחצים על Use.

  4. בדף ההגדרה של Play Games services, לוחצים על Add Credential.

    1. בוחרים בסוג שרת המשחקים.
    2. בשדה לקוח OAuth, בוחרים את מזהה הלקוח באינטרנט של הפרויקט. חשוב לוודא שזהו אותו מזהה לקוח שציינתם כשהפעלתם את הכניסה באמצעות Play Games.
    3. שומרים את השינויים.
  5. עדיין בדף ההגדרה של Play Games services, לוחצים על Add Credential (הוספת פרטי כניסה) מחדש.

    1. בוחרים בסוג Android.
    2. בשדה לקוח OAuth, בוחרים את מזהה הלקוח של Android של הפרויקט. (אם מזהה הלקוח ב-Android לא מופיע, חשוב לוודא שהגדרתם את טביעת האצבע של המשחק מסוג SHA-1 במסוף Firebase).
    3. שומרים את השינויים.
  6. בדף בודקים, מוסיפים את כתובות האימייל של המשתמשים שצריכים את המידע להיות מסוגלים להיכנס למשחק שלכם לפני הפרסום שלו Play Store.

שילוב הכניסה ל-Play Games במשחק

כדי לאפשר לשחקנים להיכנס לחשבון במשחק, עליכם לשלב את הכניסה ל-Google Play Games.

הדרך הקלה והמומלצת ביותר להוסיף תמיכה בכניסה ל-Play Games עבור אפליקציית C++ פרויקט Android צריך להשתמש ב-SDK של C++ לכניסה באמצעות חשבון Google.

כדי להוסיף את הכניסה ל-Play Games למשחק באמצעות ה-SDK של C++ לכניסה באמצעות חשבון Google, צריך לבצע את הפעולות הבאות: הבאים:

  1. משכפלים או מורידים את מאגר יישומי הפלאגין של Unity לכניסה באמצעות חשבון Google שמכיל גם את C++ SDK.

  2. יוצרים את הפרויקט שמכילה הספרייה staging/native/ באמצעות Android Studio או gradlew build.

    הפלט של ה-build מועתק לספרייה בשם google-signin-cpp.

  3. כוללים את ה-SDK של Google Sign-in ל-C++ בקובץ ה-make של הקוד המקורי של המשחק:

    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, שנחוץ ל-SDK של C++‎.

    כדי לעשות זאת, צריך להוסיף את ה-build של ה-SDK בקובץ build.gradle ברמת הפרויקט ספריית פלט כמאגר מקומי:

    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 Games כדי להיכנס ולאחזר את קוד ההרשאה של השרת:

    #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 Games:

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

    כשה-Future שהוחזר על ידי SignIn() יתקבל, תוכלו לקבל את קוד האימות של השרת מהתוצאה:

    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.

  1. אחרי שהשחקן נכנס לחשבון באמצעות Play Games, מקבלים אימות לקוד החשבון של השחקן.

  2. לאחר מכן, מחליפים את קוד האימות משירותי Play Games בפרטי כניסה ל-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) פעמים בשנייה), אפשר לבדוק את התוצאות פעם אחת בכל עדכון 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());
      }
    }

    לחלופין, אם התוכנית מבוססת על אירועים, ייתכן שתעדיפו לרשום קריאה חוזרת (callback) בעתיד.

רישום של שיחה חוזרת ב-Future‏

בחלק מהתוכניות יש פונקציות Update שנקראות 30 או 60 פעמים בשנייה. לדוגמה, יש הרבה משחקים שמבוססים על המודל הזה. התוכניות האלה יכולות לקרוא לLastResult לדגום קריאות אסינכרוניות. עם זאת, אם התוכנית שלכם מבוססת על אירועים, יכול להיות שתעדיפו לרשום פונקציות קריאה חוזרת (callback). מתבצעת קריאה לפונקציית קריאה חוזרת (callback) לאחר השלמת העתיד.
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 Games. החשבון החדש הזה מאוחסן כחלק מפרויקט Firebase, וניתן להשתמש בו כדי לזהות משתמש בכל האפליקציות בפרויקט.

במשחק שלכם אפשר לקבל את ה-UID של המשתמש ב-Firebase אובייקט 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, ולהשתמש בו כדי לקבוע לאילו נתונים המשתמש יכול לגשת.

כדי לקבל את פרטי הנגן של המשתמש ב-Play Games או כדי לגשת לשירותי Play Games: להשתמש בממשקי ה-API שמסופקים על ידי Google Play Games Services C++ SDK.

כדי לצאת ממשתמש, צריך להתקשר אל SignOut():

auth->SignOut();