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

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

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

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

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

الطريقة الأسهل والموصى بها لإضافة دعم لتسجيل الدخول إلى Play Games إلى مشروع 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-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.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();
    

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

تسجيل رد الاتصال على المستقبل

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

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

auth->SignOut();