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

  • إضافة حزمة Firebase C++ SDK إلى مشروع C++‎

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

إعداد مشروع Firebase

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

    1. في Firebase console، انتقِل إلى Settings > General tab.

    2. انتقِل للأسفل إلى بطاقة Your apps (تطبيقاتك)، واختَر تطبيق Android، وأضِف الملف المرجعي SHA-1 في الحقل SHA certificate fingerprints (الملفات المرجعية لشهادة 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. في Console، افتح تطبيقك أو أنشئ تطبيقًا.Google PlayGoogle 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" إلى مشروع C++ على Android هي استخدام حزمة تطوير البرامج (SDK) لتسجيل الدخول باستخدام حساب Google بلغة C++.

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

  1. أنشئ نسخة طبق الأصل من مستودع المكوّن الإضافي Google Sign-in Unity أو نزِّله، وهو يحتوي أيضًا على حزمة C++‎ SDK.

  2. أنشئ المشروع الموجود في الدليل staging/native/ باستخدام "استوديو Android" أو 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-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.

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

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

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

    dependencies {
        implementation 'com.google.android.gms:play-services-auth:21.5.1'
        // 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

بعد أن يسجِّل اللاعب الدخول باستخدام "ألعاب 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());
      }
    }

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

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

auth->SignOut();