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

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

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

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

  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 Games в свою игру

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

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

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

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

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

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

  3. Включите Google Sign-in C++ SDK в файл 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:20.7.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 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();
        }
    }
    

Авторизоваться с помощью 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 .

Зарегистрируйте обратный вызов на 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 Realtime Database и Cloud Storage вы можете получить уникальный идентификатор вошедшего пользователя из переменной auth и использовать его для управления тем, к каким данным пользователь может получить доступ.

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

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

auth->SignOut();