احراز هویت بااستفاده از «خدمات بازی‌های 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++ را به پروژه 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 استفاده از کیت توسعه نرم‌افزار ++C ورود به سیستم Google است.

برای افزودن ورود به سیستم «بازی‌های Play» به بازی‌تان بااستفاده از «کیت توسعه نرم‌افزار ورود به سیستم با Google به زبان ++C»، کارهای زیر را انجام دهید:

  1. مخزن افزایه Unity «ورود به سیستم با Google» را همسانه‌سازی یا بارگیری کنید، که حاوی کیت توسعه نرم‌افزار C++ نیز هست.

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

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

  3. «کیت توسعه نرم‌افزار 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 را که کیت توسعه نرم‌افزار C++ به آن نیاز دارد اضافه کنید.

    برای این کار، در فایل build.gradle سطح پروژه، فهرست راهنمای برونداد ساخت SDK را به‌عنوان مخزن محلی اضافه کنید:

    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. درنهایت، برای وارد کردن بازیکن به سیستم «بازی‌های Play»، با SignIn() تماس بگیرید:

    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. اگر برنامه شما حلقه به‌روزرسانی دارد که به‌طور منظم اجرا می‌شود (مثلاً ۳۰ یا ۶۰ بار در ثانیه)، می‌توانید نتایج را یک‌بار در هر به‌روزرسانی با 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 کارکرد دارند که در هر ثانیه ۳۰ یا ۶۰ بار فراخوانده می‌شوند. برای مثال، بسیاری از بازی‌ها از این مدل پیروی می‌کنند. این برنامه‌ها می‌توانند توابع 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 شما ذخیره می‌شود و می‌توان از آن برای شناسایی کاربر در همه برنامه‌های پروژه استفاده کرد.

در بازی‌تان، می‌توانید 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 Realtime Database و Cloud Storage، می‌توانید شناسه کاربر یکتای کاربر واردشده به سیستم را از متغیر auth دریافت کنید و از آن برای کنترل داده‌هایی که کاربر می‌تواند به آن‌ها دسترسی داشته باشد استفاده کنید.

برای دریافت اطلاعات بازیکن «بازی‌های Play» کاربر یا دسترسی به خدمات «بازی‌های Play»، از میاناهای برنامه‌سازی کاربردی ارائه‌شده توسط کیت توسعه نرم‌افزار C++ خدمات «بازی‌های Google Play» استفاده کنید.

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

auth->SignOut();