المصادقة باستخدام خدمات ألعاب Google Play مع C++

يمكنك استخدام خدمات ألعاب Google Play لتسجيل دخول اللاعبين إلى لعبة Android مبنية على Firebase ومكتوبة بلغة C ++. لاستخدام خدمات ألعاب Google Play ، قم بتسجيل الدخول باستخدام Firebase ، قم أولاً بتسجيل الدخول إلى المشغل باستخدام ألعاب Google Play ، واطلب رمز مصادقة 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 كموفر لتسجيل الدخول:

    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.
    3. احفظ التغييرات.
  5. لا يزال في صفحة تكوين خدمات ألعاب Play ، انقر فوق إضافة بيانات الاعتماد مرة أخرى.

    1. حدد نوع Android .
    2. في حقل عميل OAuth ، حدد معرّف عميل Android الخاص بمشروعك. (إذا كنت لا ترى معرّف عميل Android ، فتأكد من تعيين بصمة SHA-1 للعبة في وحدة تحكم Firebase.)
    3. احفظ التغييرات.
  6. في صفحة المختبرين ، أضف عناوين البريد الإلكتروني لأي مستخدم يحتاج إلى أن يكون قادرًا على تسجيل الدخول إلى لعبتك قبل إصدارها في متجر Play.

ادمج تسجيل الدخول إلى "ألعاب Play" في لعبتك

قبل أن تتمكن من تسجيل دخول اللاعبين إلى لعبتك ، يجب عليك دمج تسجيل الدخول إلى ألعاب Google Play.

الطريقة الأسهل والموصى بها لإضافة دعم تسجيل الدخول إلى ألعاب Play إلى مشروع C ++ Android هي استخدام Google Sign-in C ++ SDK .

لإضافة "ألعاب Play" ، قم بتسجيل الدخول إلى لعبتك باستخدام Google Sign-in C ++ SDK ، قم بما يلي:

  1. قم بنسخ أو تنزيل مستودع المكون الإضافي Google Sign-in Unity ، والذي يحتوي أيضًا على C ++ SDK.

  2. أنشئ المشروع المضمن في الدليل staging/native/ ، إما باستخدام Android Studio أو gradlew build .

    ينسخ الإصدار مخرجاته إلى دليل يسمى google-signin-cpp .

  3. قم بتضمين Google Sign-in 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)
    

  4. بعد ذلك ، قم بتضمين مكون Java helper ، المطلوب بواسطة 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: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')
    }
    
  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 Games:

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

    عندما يحل المستقبل الذي تم إرجاعه بواسطة 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" ، يمكنك استخدام رمز المصادقة للمصادقة باستخدام Firebase.

  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 مرة في الثانية) ، فيمكنك التحقق من النتائج مرة واحدة لكل تحديث باستخدام 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 لاستقصاء المكالمات غير المتزامنة. ومع ذلك ، إذا كان برنامجك مدفوعًا بالأحداث ، فقد تفضل تسجيل وظائف رد الاتصال. يتم استدعاء وظيفة رد الاتصال عند الانتهاء من المستقبل.
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 الخاص به. يتم تخزين هذا الحساب الجديد كجزء من مشروع 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();
}

في قاعدة بيانات Firebase Realtime وقواعد أمان التخزين السحابي ، يمكنك الحصول على معرف المستخدم الفريد للمستخدم الذي قام بتسجيل الدخول من متغير auth ، واستخدامه للتحكم في البيانات التي يمكن للمستخدم الوصول إليها.

للحصول على معلومات لاعب Play Games الخاص بالمستخدم أو للوصول إلى خدمات ألعاب Play ، استخدم واجهات برمجة التطبيقات التي توفرها خدمات ألعاب Google Play C ++ SDK .

لتسجيل خروج مستخدم ، اتصل بـ SignOut() :

auth->SignOut();