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

يمكنك استخدام "خدمات ألعاب Google Play" لتسجيل دخول اللاعبين إلى لعبة Android تم إنشاؤها على Firebase ومكتوبة بلغة C++. لاستخدام ميزة تسجيل الدخول في "خدمات ألعاب Google Play" مع Firebase، عليك أولاً تسجيل دخول اللاعب باستخدام "خدمات ألعاب Google Play"، وطلب رمز التفويض OAuth 2.0 عند إجراء ذلك. بعد ذلك، مرِّر رمز التفويض إلى PlayGamesAuthProvider لإنشاء بيانات اعتماد Firebase، والتي يمكنك استخدامها للمصادقة مع Firebase.

قبل البدء

قبل أن تتمكّن من استخدام Firebase Authentication، عليك إجراء ما يلي:

  • سجِّل مشروع C++‎ الخاص بك وأعدَّه لاستخدام Firebase.

    إذا كان مشروع C++ يستخدم Firebase من قبل، يكون قد تم تسجيله وإعداده لاستخدام Firebase.

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

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

إعداد مشروع Firebase

  1. حدِّد بصمة SHA-1 لتطبيقك إذا لم يسبق لك إجراء ذلك.

    1. في وحدة تحكّم Firebase، انتقِل إلى علامة التبويب الإعدادات > عام.

    2. انتقِل للأسفل إلى بطاقة تطبيقاتك، واختَر تطبيق Android، وأضِف بصمة SHA-1 في حقل الملفات المرجعية لشهادة SHA.

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

    ./gradlew signingReport

    راجِع مصادقة العميل للحصول على تفاصيل حول كيفية الحصول على الملف المرجعي لشهادة SHA الخاصة بتطبيقك.

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

    1. في وحدة تحكّم Firebase، انتقِل إلى الأمان > المصادقة.

    2. إنشاء معرّف عميل وخادم ويب ورمز سري للعميل والحصول عليهما:

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

      2. انسخ معرّف العميل وسرّه من موفّر خدمة تسجيل الدخول Google.

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

ضبط Play Games services باستخدام معلومات تطبيق Firebase الخاص بك

  1. في Google Play Console، افتح تطبيق Google Play أو أنشئ تطبيقًا.

  2. في قسم النمو، انقر على Play Games services > الإعداد والإدارة > الإعدادات.

  3. انقر على نعم، تستخدم لعبتي حاليًا واجهات Google APIs، واختَر مشروع Firebase من القائمة، ثم انقر على استخدام.

  4. في صفحة إعدادات Play Games services، انقر على إضافة بيانات اعتماد.

    1. اختَر نوع خادم الألعاب.
    2. في حقل عميل OAuth، اختَر معرّف عميل الويب الخاص بمشروعك. تأكَّد من أنّ هذا المعرّف هو نفسه الذي حدّدته عند تفعيل تسجيل الدخول باستخدام Play Games.
    3. احفظ التغييرات.
  5. في صفحة إعدادات Play Games services، انقر على إضافة بيانات اعتماد مرة أخرى.

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

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

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

إنّ أسهل طريقة وأكثرها فعالية لإتاحة تسجيل الدخول باستخدام "خدمات ألعاب Play" في مشروع Android بلغة ++C هي استخدام حزمة تطوير البرامج (SDK) لتسجيل الدخول باستخدام Google بلغة ++C.

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

  1. أنشئ نسخة طبق الأصل من مستودع إضافة Unity لتسجيل الدخول باستخدام حساب Google أو نزِّله، والذي يحتوي أيضًا على حزمة تطوير البرامج (SDK) للغة C++.

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

    تنسخ عملية الإنشاء الناتج إلى دليل باسم google-signin-cpp.

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

    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++.

    لإجراء ذلك، أضِف دليل إخراج إصدار حزمة SDK كملف مستودع محلي في ملف build.gradle على مستوى المشروع:

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

    وفي ملف build.gradle على مستوى الوحدة، حدِّد المكوّن المساعد كعنصر تابع:

    dependencies {
        implementation 'com.google.android.gms:play-services-auth:22.0.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();
    

    عندما يتم حلّ 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

بعد أن يسجّل اللاعب الدخول باستخدام &quot;ألعاب Play&quot;، يمكنك استخدام رمز التفويض للمصادقة باستخدام Firebase.

  1. بعد أن يسجّل اللاعب الدخول بنجاح باستخدام &quot;ألعاب Play&quot;، احصل على رمز مصادقة لحساب اللاعب.

  2. بعد ذلك، استبدِل رمز التفويض من &quot;خدمات ألعاب Play&quot; ببيانات اعتماد 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());
      }
    }

    أو إذا كان برنامجك يعتمد على الأحداث، قد تفضّل تسجيل دالة ردّ الاتصال في Future.

تسجيل دالة معالجة عند اكتمال Future

تتضمّن بعض البرامج وظائف Update يتم استدعاؤها 30 أو 60 مرة في الثانية. على سبيل المثال، تتّبع العديد من الألعاب هذا النموذج. يمكن لهذه البرامج استدعاء دوال 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". يتم تخزين هذا الحساب الجديد كجزء من مشروعك على 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" أو للوصول إلى خدمات "ألعاب Play"، استخدِم واجهات برمجة التطبيقات التي يوفّرها حزمة تطوير البرامج (SDK) لخدمات ألعاب Google Play بلغة ++C.

لتسجيل خروج مستخدم، اتّبِع الخطوات التاليةSignOut():

auth->SignOut();