المصادقة باستخدام "خدمات ألعاب 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.

  • أضِف حزمة تطوير البرامج (SDK) لـ Firebase C++ إلى مشروع C++.

تجدر الإشارة إلى أنّ إضافة Firebase إلى مشروع C++ تتضمّن مهامًا في وحدة تحكُّم Firebase وفي مشروع C++ المفتوح (على سبيل المثال، يمكنك تنزيل ملفات إعداد Firebase من وحدة التحكّم، ثم نقلها إلى مشروع C++ ).

إعداد مشروع Firebase

  1. يجب ضبط الملف المرجعي لخوارزمية SHA-1 للعبتك في صفحة الإعدادات على "وحدة تحكُّم Firebase"، إذا لم يسبق لك إجراء ذلك.

    يمكنك الحصول على تجزئة SHA لشهادة التوقيع باستخدام الأمر signingReport Gradle:

    ./gradlew signingReport

  2. تفعيل "ألعاب Google Play" كموفِّر لتسجيل الدخول:

    1. في وحدة تحكُّم Firebase، افتح قسم المصادقة.

    2. أنشئ واحصل على معرّف عميل خادم الويب وسر العميل لمشروعك:

      1. ضمن علامة التبويب طريقة تسجيل الدخول، فعِّل خيار موفِّر خدمة تسجيل الدخول إلى Google.

      2. انسخ معرِّف عميل خادم الويب وسره من موفّر تسجيل الدخول إلى Google.

    3. ضمن علامة التبويب طريقة تسجيل الدخول، فعِّل موفّر تسجيل الدخول إلى ألعاب Play، وحدِّد معرِّف عميل خادم الويب وسر العميل لمشروعك، والذي حصلت عليه في الخطوة الأخيرة.

إعداد خدمات ألعاب 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 هي استخدام حزمة تطوير البرامج (SDK) لـ C++ لتسجيل الدخول بحساب Google.

لإضافة بيانات تسجيل الدخول إلى ألعاب Play إلى لعبتك باستخدام حزمة تطوير البرامج (SDK) لـ C++ لتسجيل الدخول إلى Google، يمكنك اتّباع الخطوات التالية:

  1. استنسِخ أو نزِّل مستودع مكوّنات Unity الإضافية لتسجيل الدخول إلى Google الذي يحتوي أيضًا على حزمة C++ SDK.

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

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

  3. يُرجى تضمين حزمة تطوير البرامج (SDK) لـ C++ لتسجيل الدخول بحساب Google في ملف إنشاء الرمز الأصلي للعبتك:

    إنشاء فيديوهات Shorts

    في ملف 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 على مستوى الوحدة، يمكنك تحديد المكوِّن المساعد باعتباره تبعية:

    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()، يمكنك الحصول على رمز مصادقة الخادم من النتيجة:

    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 للمستخدم من كائن 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" أو الوصول إلى "خدمات ألعاب Play"، يمكنك استخدام واجهات برمجة التطبيقات المتوفّرة من خلال حزمة SDK الخاصة بـ C++ ضمن "خدمات ألعاب Google Play".

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

auth->SignOut();