با استفاده از خدمات بازی های Google Play با C++ احراز هویت

شما می‌توانید از سرویس‌های بازی‌های گوگل پلی برای ورود بازیکنان به یک بازی اندروید که بر روی فایربیس ساخته شده و با زبان سی‌پلاس‌پلاس نوشته شده است، استفاده کنید. برای استفاده از ورود به سیستم سرویس‌های بازی‌های گوگل پلی با فایربیس، ابتدا بازیکن را با گوگل پلی گیمز وارد سیستم کنید و هنگام انجام این کار، کد احراز هویت OAuth 2.0 را درخواست کنید. سپس، کد احراز هویت را به PlayGamesAuthProvider ارسال کنید تا یک اعتبارنامه فایربیس ایجاد شود که می‌توانید از آن برای احراز هویت با فایربیس استفاده کنید.

قبل از اینکه شروع کنی

قبل از اینکه بتوانید Firebase Authentication استفاده کنید، باید:

  • پروژه ++C خود را ثبت کنید و آن را برای استفاده از Firebase پیکربندی کنید.

    اگر پروژه ++C شما از قبل از Firebase استفاده می‌کند، پس از قبل برای Firebase ثبت و پیکربندی شده است.

  • کیت توسعه نرم‌افزاری Firebase C++ را به پروژه C++ خود اضافه کنید.

توجه داشته باشید که اضافه کردن Firebase به پروژه C++ شما شامل وظایفی هم در کنسول Firebase و هم در پروژه C++ باز شما می‌شود (برای مثال، شما فایل‌های پیکربندی Firebase را از کنسول دانلود می‌کنید، سپس آنها را به پروژه C++ خود منتقل می‌کنید).

پروژه Firebase خود را تنظیم کنید

  1. اگر قبلاً اثر انگشت SHA-1 برنامه خود را مشخص نکرده‌اید، آن را مشخص کنید.

    1. در کنسول Firebase ، به مسیر زیر بروید: > برگه عمومی .

    2. به پایین صفحه و قسمت «برنامه‌های شما» بروید، برنامه اندروید خود را انتخاب کنید و اثر انگشت SHA-1 خود را در قسمت «اثر انگشت گواهی SHA» اضافه کنید.

    شما می‌توانید هش SHA گواهی امضای خود را با دستور gradle signingReport دریافت کنید:

    ./gradlew signingReport

    برای جزئیات بیشتر در مورد نحوه دریافت اثر انگشت SHA برنامه خود، به بخش احراز هویت کلاینت خود مراجعه کنید.

  2. فعال کردن Google Play Games به عنوان ارائه‌دهنده‌ی ورود:

    1. در کنسول Firebase ، به بخش امنیت > احراز هویت بروید.

    2. شناسه کلاینت وب سرور و رمز کلاینت پروژه خود را ایجاد و دریافت کنید:

      1. در برگه «روش ورود» ، ارائه‌دهنده ورود به سیستم گوگل را فعال کنید.

      2. شناسه و رمز کلاینت وب سرور را از ارائه دهنده ورود به سیستم گوگل کپی کنید.

    3. در برگه «روش ورود» ، ارائه‌دهنده ورود به سیستم Play Games را فعال کنید و شناسه کلاینت وب سرور پروژه و رمز کلاینت خود را که در مرحله قبل دریافت کردید، مشخص کنید.

Play Games services با اطلاعات برنامه Firebase خود پیکربندی کنید

  1. در کنسول Google Play ، برنامه Google Play خود را باز کنید یا یکی ایجاد کنید.

  2. در بخش «رشد» ، Play Games services > راه‌اندازی و مدیریت > پیکربندی کلیک کنید.

  3. روی «بله، بازی من از قبل از APIهای گوگل استفاده می‌کند» کلیک کنید، پروژه Firebase خود را از لیست انتخاب کنید و سپس روی «استفاده» کلیک کنید.

  4. در صفحه پیکربندی Play Games services ، روی «افزودن اعتبارنامه» کلیک کنید.

    1. نوع سرور بازی را انتخاب کنید.
    2. در فیلد کلاینت OAuth ، شناسه کلاینت وب پروژه خود را انتخاب کنید. مطمئن شوید که این همان شناسه کلاینتی است که هنگام فعال کردن ورود به سیستم Play Games مشخص کرده‌اید.
    3. تغییرات خود را ذخیره کنید.
  5. همچنان در صفحه پیکربندی Play Games services هستید، دوباره روی Add Credential کلیک کنید.

    1. نوع اندروید را انتخاب کنید.
    2. در فیلد OAuth client ، شناسه کلاینت اندروید پروژه خود را انتخاب کنید. (اگر شناسه کلاینت اندروید خود را نمی‌بینید، مطمئن شوید که اثر انگشت SHA-1 بازی خود را در کنسول Firebase تنظیم کرده‌اید.)
    3. تغییرات خود را ذخیره کنید.
  6. در صفحه آزمایش‌کنندگان ، آدرس‌های ایمیل هر کاربری را که باید قبل از انتشار بازی در Play Store بتوانند به سیستم وارد شوند، اضافه کنید.

ورود به سیستم Play Games را در بازی خود ادغام کنید

قبل از اینکه بتوانید بازیکنان را به بازی خود وارد کنید، باید ورود به سیستم Google Play Games را فعال کنید.

ساده‌ترین و توصیه‌شده‌ترین راه برای افزودن پشتیبانی از ورود به سیستم Play Games به یک پروژه C++ Android، استفاده از Google Sign-in C++ SDK است.

برای افزودن ورود به سیستم Play Games به بازی خود با استفاده از Google Sign-in C++ SDK، موارد زیر را انجام دهید:

  1. مخزن افزونه Google Sign-in Unity را که شامل C++ SDK نیز می‌شود، کلون یا دانلود کنید.

  2. پروژه موجود در دایرکتوری staging/native/ را با استفاده از اندروید استودیو یا gradlew build بسازید.

    این نسخه، خروجی خود را در دایرکتوری به نام google-signin-cpp کپی می‌کند.

  3. کیت توسعه نرم‌افزار C++ مربوط به ورود به سیستم گوگل (Google Sign-in) را در فایل ساخت کد بومی بازی خود قرار دهید:

    سی‌میک

    در فایل سطح بالای 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. در مرحله بعد، کامپوننت کمکی جاوا را که برای 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 Games و بازیابی کد احراز هویت سرور پیکربندی کنید:

    #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();
    

    وقتی 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();
        }
    }
    

احراز هویت با فایربیس

پس از ورود بازیکن با Play Games، می‌توانید از کد احراز هویت برای تأیید اعتبار با Firebase استفاده کنید.

  1. پس از اینکه بازیکن با موفقیت با استفاده از Play Games وارد سیستم شد، یک کد تأیید برای حساب بازیکن دریافت کنید.

  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 ثبت کنید .

ثبت تماس مجدد در 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);
}
تابع فراخوانی (callback) در صورت تمایل می‌تواند یک لامبدا نیز باشد.
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 Realtime، می‌توانید شناسه کاربری منحصر به فرد کاربر وارد شده را از متغیر auth دریافت کنید و از آن برای کنترل داده‌هایی که کاربر می‌تواند به آنها دسترسی داشته باشد، استفاده کنید.

برای دریافت اطلاعات بازیکن Play Games کاربر یا دسترسی به سرویس‌های Play Games، از APIهای ارائه شده توسط C++ SDK سرویس‌های Google Play Games استفاده کنید.

برای خروج کاربر، تابع SignOut() فراخوانی کنید:

auth->SignOut();