ตรวจสอบสิทธิ์โดยใช้บริการเกมของ Google Play ด้วย C++

คุณใช้บริการเกมของ Google Play เพื่อลงชื่อเข้าใช้เกม Android ที่สร้างบน Firebase และเขียนด้วยภาษา C++ ได้ หากต้องการใช้บริการ Google Play Games ลงชื่อเข้าใช้ด้วย Firebase ก่อนอื่นให้ลงชื่อเข้าใช้โปรแกรมเล่นด้วย Google Play Games แล้วขอรหัสการให้สิทธิ์ OAuth 2.0 จากนั้นส่งรหัสการตรวจสอบสิทธิ์ไปยัง PlayGamesAuthProvider เพื่อสร้างข้อมูลเข้าสู่ระบบ Firebase ซึ่งคุณจะใช้ตรวจสอบสิทธิ์กับ Firebase ได้

ก่อนเริ่มต้น

ก่อนที่จะใช้การตรวจสอบสิทธิ์ของ Firebase ได้ คุณต้องทำดังนี้

  • ลงทะเบียนโปรเจ็กต์ C++ และกําหนดค่าเพื่อใช้ Firebase

    หากโปรเจ็กต์ C++ ใช้ Firebase อยู่แล้ว แสดงว่าโปรเจ็กต์ได้รับการลงทะเบียนและกำหนดค่าสำหรับ Firebase แล้ว

  • เพิ่ม Firebase C++ SDK ในโปรเจ็กต์ C++

โปรดทราบว่าการเพิ่ม Firebase ในโปรเจ็กต์ C++ จะเกี่ยวข้องกับงานทั้งในคอนโซล Firebase และในโปรเจ็กต์ C++ ที่เปิดอยู่ (เช่น คุณดาวน์โหลดไฟล์การกำหนดค่า Firebase จากคอนโซล จากนั้นจึงย้ายไฟล์เหล่านั้นไปยังโปรเจ็กต์ C++)

สร้างโปรเจ็กต์ Firebase

  1. ตั้งค่าลายนิ้วมือ SHA-1 ของเกมในหน้าการตั้งค่าของคอนโซล Firebase หากยังไม่ได้ทำ

    คุณจะรับแฮช SHA ของใบรับรองที่มีการรับรองได้ด้วยคำสั่ง Gradle signingReport ซึ่งมีดังนี้

    ./gradlew signingReport

  2. เปิดใช้ Google Play Games เป็นผู้ให้บริการการลงชื่อเข้าใช้

    1. ในคอนโซล Firebase ให้เปิดส่วนการตรวจสอบสิทธิ์

    2. สร้างและรับรหัสไคลเอ็นต์เว็บเซิร์ฟเวอร์และรหัสลับไคลเอ็นต์ของโปรเจ็กต์:

      1. ในแท็บวิธีการลงชื่อเข้าใช้ ให้เปิดใช้ผู้ให้บริการการลงชื่อเข้าใช้ Google

      2. คัดลอกรหัสไคลเอ็นต์และข้อมูลลับของเว็บเซิร์ฟเวอร์จากผู้ให้บริการการลงชื่อเข้าใช้ Google

    3. ในแท็บวิธีการลงชื่อเข้าใช้ ให้เปิดใช้ผู้ให้บริการการลงชื่อเข้าใช้ Play Games และระบุรหัสไคลเอ็นต์เว็บเซิร์ฟเวอร์และรหัสลับไคลเอ็นต์ของโปรเจ็กต์ที่คุณได้รับในขั้นตอนสุดท้าย

กำหนดค่าบริการเกมของ Play ด้วยข้อมูลแอป Firebase ของคุณ

  1. ใน Google Play Console ให้เปิดแอป Google Play หรือสร้างแอป

  2. ในส่วนขยาย ให้คลิกบริการเกมของ Play > การตั้งค่าและการจัดการ > การกำหนดค่า

  3. คลิกใช่ เกมของฉันใช้ Google APIs อยู่แล้ว เลือกโปรเจ็กต์ Firebase จากรายการ แล้วคลิกใช้

  4. ในหน้าการกำหนดค่าบริการเกมของ Play ให้คลิกเพิ่มข้อมูลเข้าสู่ระบบ

    1. เลือกประเภทเซิร์ฟเวอร์เกม
    2. เลือกรหัสไคลเอ็นต์ของเว็บของโปรเจ็กต์ในช่องไคลเอ็นต์ OAuth ตรวจสอบว่านี่เป็นรหัสไคลเอ็นต์ที่คุณระบุไว้เมื่อเปิดใช้การลงชื่อเข้าใช้ Play Games
    3. บันทึกการเปลี่ยนแปลง
  5. ขณะยังอยู่ในหน้าการกำหนดค่าบริการเกมของ Play ให้คลิกเพิ่มข้อมูลเข้าสู่ระบบอีกครั้ง

    1. เลือกประเภท Android
    2. ในช่องไคลเอ็นต์ OAuth ให้เลือกรหัสไคลเอ็นต์ Android ของโปรเจ็กต์ (หากไม่เห็นรหัสไคลเอ็นต์ Android ให้ตรวจสอบว่าได้ตั้งค่าลายนิ้วมือ SHA-1 ของเกมในคอนโซล Firebase)
    3. บันทึกการเปลี่ยนแปลง
  6. ในหน้าผู้ทดสอบ ให้เพิ่มอีเมลของผู้ใช้ที่ต้องลงชื่อเข้าใช้เกมได้ก่อนที่จะเผยแพร่ใน Play Store

ผสานรวมการลงชื่อเข้าใช้ Play Games เข้ากับเกมของคุณ

ก่อนที่จะลงชื่อเข้าใช้ให้ผู้เล่นในเกมได้ คุณต้องผสานรวมการลงชื่อเข้าใช้ Google Play Games

วิธีที่ง่ายที่สุดในการแนะนำและเพิ่มการรองรับการลงชื่อเข้าใช้ Play Games ในโครงการ C++ สำหรับ Android คือการใช้ Google Sign-In C++ SDK

หากต้องการเพิ่มการลงชื่อเข้าใช้ Play Games ในเกมของคุณโดยใช้ Google Sign-In C++ SDK ให้ทำตามขั้นตอนต่อไปนี้

  1. โคลนหรือดาวน์โหลดที่เก็บปลั๊กอิน Google Sign-in Unity ซึ่งมี C++ SDK ด้วย

  2. สร้างโปรเจ็กต์ที่อยู่ในไดเรกทอรี staging/native/ โดยใช้ Android Studio หรือ gradlew build

    บิลด์จะคัดลอกเอาต์พุตไปยังไดเรกทอรีชื่อ google-signin-cpp

  3. รวม C++ SDK ของ Google Sign-In ไว้ในไฟล์สร้างโค้ดดั้งเดิมของเกม

    ผู้ผลิต

    ในไฟล์ 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 จำเป็นต้องใช้

    วิธีการคือเพิ่มไดเรกทอรีเอาต์พุตของบิลด์ SDK เป็นที่เก็บภายในเครื่องในไฟล์ build.gradle ระดับโปรเจ็กต์ ดังนี้

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

    และในไฟล์ build.gradle ระดับโมดูล ให้ประกาศคอมโพเนนต์ตัวช่วยเป็นทรัพยากร Dependency ดังนี้

    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 ครั้งต่อวินาที) คุณจะตรวจสอบผลลัพธ์ได้ 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());
      }
    }

    หรือหากโปรแกรมของคุณมีการจัดกิจกรรม คุณอาจต้องลงทะเบียนการโทรกลับในอนาคต

ลงทะเบียนติดต่อกลับในอนาคต

บางโปรแกรมมีฟังก์ชัน Update ที่เรียกว่า 30 หรือ 60 ครั้งต่อวินาที ตัวอย่างเช่น เกมจำนวนมากทำตามแบบจำลองนี้ โปรแกรมเหล่านี้จะเรียกใช้ฟังก์ชัน LastResult เพื่อโพลการเรียกแบบไม่พร้อมกันได้ อย่างไรก็ตาม หากโปรแกรมของคุณมีการขับเคลื่อนด้วยเหตุการณ์ คุณอาจต้องการลงทะเบียนฟังก์ชัน Callback ระบบจะเรียกใช้ฟังก์ชัน Callback เมื่อเสร็จสิ้นการดำเนินการ 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);
}
ฟังก์ชัน Callback อาจเป็น 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 และสามารถใช้เพื่อระบุผู้ใช้ในทุกแอปในโปรเจ็กต์ได้

ในเกม คุณจะรับ Firebase UID ของผู้ใช้ได้จากออบเจ็กต์ 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();
}

คุณจะได้รับรหัสผู้ใช้ที่ไม่ซ้ำของผู้ใช้ที่ลงชื่อเข้าใช้จากตัวแปร auth และใช้รหัสดังกล่าวเพื่อควบคุมข้อมูลที่ผู้ใช้เข้าถึงได้ในกฎการรักษาความปลอดภัยของ Firebase และ Cloud Storage

หากต้องการรับข้อมูลโปรแกรมเล่น Play Games ของผู้ใช้หรือเข้าถึงบริการเกมของ Play ให้ใช้ API จาก C++ SDK ของบริการเกมของ Google Play

หากต้องการนำผู้ใช้ออกจากระบบ โปรดโทรหา SignOut()

auth->SignOut();