Аутентификация с использованием игровых сервисов Google Play с C++

Вы можете использовать сервисы Google Play Games для входа игроков в игру для Android, созданную на базе Firebase и написанную на C++. Чтобы использовать вход в сервисы Google Play Games с помощью Firebase, сначала войдите в плеер с помощью Google Play Games и при этом запросите код аутентификации OAuth 2.0. Затем передайте код аутентификации PlayGamesAuthProvider , чтобы сгенерировать учетные данные Firebase, которые вы можете использовать для аутентификации в Firebase.

Прежде чем вы начнете

Прежде чем вы сможете использовать Firebase Authentication , вам необходимо:

  • Зарегистрируйте свой проект C++ и настройте его для использования Firebase.

    Если ваш проект C++ уже использует Firebase, значит, он уже зарегистрирован и настроен для Firebase.

  • Добавьте Firebase C++ SDK в свой проект C++.

Обратите внимание, что добавление Firebase в ваш проект C++ включает в себя задачи как в консоли Firebase , так и в вашем открытом проекте C++ (например, вы загружаете файлы конфигурации Firebase из консоли, а затем перемещаете их в свой проект C++).

Настройте свой проект Firebase

  1. Если вы еще этого не сделали, установите отпечаток SHA-1 вашей игры на странице настроек консоли Firebase.

    Вы можете получить хэш SHA вашего сертификата подписи с помощью команды gradle signingReport :

    ./gradlew signingReport

  2. Включите Google Play Games в качестве поставщика услуг входа:

    1. В консоли Firebase откройте раздел Аутентификация .

    2. Создайте и получите идентификатор клиента веб-сервера и секрет клиента:

      1. На вкладке «Метод входа» включите поставщика входа в систему Google .

      2. Скопируйте идентификатор и секрет клиента веб-сервера от поставщика услуг входа в Google .

    3. На вкладке «Метод входа» включите поставщика входа в Play Игры и укажите идентификатор клиента веб-сервера вашего проекта и секрет клиента, которые вы получили на последнем шаге.

Настройте сервисы Play Games, используя информацию о вашем приложении Firebase.

  1. В консоли Google Play откройте приложение Google Play или создайте его.

  2. В разделе «Развитие» нажмите «Сервисы Play Games» > «Настройка и управление» > «Конфигурация» .

  3. Нажмите «Да, моя игра уже использует Google API» , выберите свой проект Firebase из списка и нажмите «Использовать» .

  4. На странице конфигурации сервисов Play Games нажмите «Добавить учетные данные» .

    1. Выберите тип игрового сервера .
    2. В поле «Клиент OAuth» выберите идентификатор веб-клиента вашего проекта. Убедитесь, что это тот же идентификатор клиента, который вы указали при включении входа в Play Игры.
    3. Сохраните изменения.
  5. На странице конфигурации сервисов Play Games еще раз нажмите «Добавить учетные данные» .

    1. Выберите тип Android .
    2. В поле «Клиент OAuth» выберите идентификатор клиента Android вашего проекта. (Если вы не видите свой идентификатор клиента Android, убедитесь, что вы установили отпечаток SHA-1 своей игры в консоли Firebase.)
    3. Сохраните изменения.
  6. На странице «Тестеры» добавьте адреса электронной почты всех пользователей, которым необходимо иметь возможность войти в вашу игру, прежде чем вы опубликуете ее в магазине Play.

Интегрируйте вход в Play Игры в свою игру

Прежде чем вы сможете авторизовать игроков в своей игре, вам необходимо интегрировать вход в Google Play Games.

Самый простой и рекомендуемый способ добавить поддержку входа в Play Игры в проект C++ Android — использовать C++ SDK для входа в Google .

Чтобы добавить вход в Play Игры в свою игру с помощью Google Sign-in C++ SDK, выполните следующие действия:

  1. Клонируйте или загрузите репозиторий подключаемого модуля Google Sign-in Unity , который также содержит C++ SDK.

  2. Создайте проект, содержащийся в каталоге staging/native/ , с помощью Android Studio или gradlew build .

    Сборка копирует выходные данные в каталог с именем google-signin-cpp .

  3. Включите C++ SDK для входа в Google в файл make-файла собственного кода вашей игры:

    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-сборка

    В вашем файле 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 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();
        }
    }
    

Аутентификация с помощью Firebase

После того как игрок войдет в систему с помощью 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 .

Зарегистрируйте обратный вызов на будущее

В некоторых программах есть функции 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 Games. Эта новая учетная запись хранится как часть вашего проекта 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 вы можете получить уникальный идентификатор пользователя, вошедшего в систему, из переменной auth и использовать его для управления тем, к каким данным пользователь может получить доступ.

Чтобы получить информацию об игроке Play Games пользователя или получить доступ к сервисам Play Games, используйте API, предоставляемые C++ SDK сервисов Google Play Games .

Чтобы выйти из системы, вызовите SignOut() :

auth->SignOut();