Autenticar usando los servicios de juegos de Google Play con C++

Puedes utilizar los servicios de Google Play Games para iniciar sesión como jugador en un juego de Android creado en Firebase y escrito en C++. Para utilizar los servicios de Google Play Games, inicie sesión con Firebase, primero inicie sesión en el reproductor con Google Play Games y solicite un código de autenticación OAuth 2.0 cuando lo haga. Luego, pase el código de autenticación a PlayGamesAuthProvider para generar una credencial de Firebase, que puede usar para autenticarse con Firebase.

Antes de que empieces

Antes de poder utilizar Firebase Authentication , debes:

  • Registre su proyecto C++ y configúrelo para usar Firebase.

    Si su proyecto de C++ ya usa Firebase, entonces ya está registrado y configurado para Firebase.

  • Agrega el SDK de Firebase C++ a tu proyecto de C++.

Tenga en cuenta que agregar Firebase a su proyecto de C++ implica tareas tanto en Firebase console como en su proyecto de C++ abierto (por ejemplo, descarga archivos de configuración de Firebase desde la consola y luego los mueve a su proyecto de C++).

Configura tu proyecto de Firebase

  1. Si aún no lo has hecho, configura la huella digital SHA-1 de tu juego en la página Configuración de Firebase console.

    Puede obtener el hash SHA de su certificado de firma con el comando Gradle signingReport :

    ./gradlew signingReport

  2. Habilite Google Play Games como proveedor de inicio de sesión:

    1. En Firebase console, abre la sección Autenticación .

    2. Genere y obtenga el ID de cliente del servidor web y el secreto de cliente de su proyecto:

      1. Dentro de la pestaña Método de inicio de sesión , habilite el proveedor de inicio de sesión de Google .

      2. Copie el ID del cliente del servidor web y el secreto del proveedor de inicio de sesión de Google .

    3. En la pestaña Método de inicio de sesión , habilite el proveedor de inicio de sesión de Play Games y especifique el ID de cliente del servidor web y el secreto de cliente de su proyecto, que obtuvo en el último paso.

Configura los servicios de Play Games con la información de tu aplicación Firebase

  1. En Google Play Console , abre tu aplicación Google Play o crea una.

  2. En la sección Crecer , haz clic en Servicios de Play Games > Configuración y administración > Configuración .

  3. Haz clic en Sí, mi juego ya usa las API de Google , selecciona tu proyecto de Firebase de la lista y luego haz clic en Usar .

  4. En la página de configuración de servicios de Play Games, haga clic en Agregar credencial .

    1. Seleccione el tipo de servidor de juegos .
    2. En el campo Cliente OAuth , seleccione el ID del cliente web de su proyecto. Asegúrate de que sea el mismo ID de cliente que especificaste cuando habilitaste el inicio de sesión en Play Games.
    3. Guarde sus cambios.
  5. Aún en la página de configuración de servicios de Play Games, haga clic en Agregar credencial nuevamente.

    1. Seleccione el tipo de Android .
    2. En el campo Cliente OAuth , seleccione el ID del cliente Android de su proyecto. (Si no ves tu ID de cliente de Android, asegúrate de configurar la huella digital SHA-1 de tu juego en la consola Firebase).
    3. Guarde sus cambios.
  6. En la página Probadores , agrega las direcciones de correo electrónico de cualquier usuario que necesite poder iniciar sesión en tu juego antes de lanzarlo en Play Store.

Integra el inicio de sesión de Play Games en tu juego

Antes de poder iniciar sesión en tu juego, debes integrar el inicio de sesión de Google Play Games.

La forma más sencilla y recomendada de agregar compatibilidad con el inicio de sesión de Play Games a un proyecto de Android en C++ es utilizar el SDK de C++ de inicio de sesión de Google .

Para agregar el inicio de sesión de Play Games a tu juego usando el SDK de C++ de inicio de sesión de Google, haz lo siguiente:

  1. Clone o descargue el repositorio de complementos de Unity de inicio de sesión de Google , que también contiene el SDK de C++.

  2. Compile el proyecto contenido en el directorio staging/native/ , ya sea usando Android Studio o gradlew build .

    La compilación copia su resultado en un directorio llamado google-signin-cpp .

  3. Incluye el SDK de C++ de inicio de sesión de Google en el archivo de creación de código nativo de tu juego:

    Chacer

    En su archivo CMakeLists.txt de nivel superior:

    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-construcción

    En su archivo 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. A continuación, incluya el componente auxiliar de Java, que requiere el SDK de C++.

    Para hacerlo, en su archivo build.gradle a nivel de proyecto, agregue el directorio de salida de compilación del SDK como repositorio local:

    allprojects {
        repositories {
            // ...
            flatDir {
                dirs 'path/to/google-signin-cpp'
            }
        }
    }
    

    Y, en su archivo build.gradle a nivel de módulo, declare el componente auxiliar como una dependencia:

    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. Luego, en tu juego, configura un objeto GoogleSignIn para usar el inicio de sesión de Play Games y recuperar un código de autenticación del servidor:

    #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. Finalmente, llama SignIn() para iniciar sesión en Play Games:

    Future<GoogleSignIn::SignInResult> &future = gsi.SignIn();
    

    Cuando se resuelva el futuro devuelto por SignIn() , podrá obtener el código de autenticación del servidor del resultado:

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

Autenticar con Firebase

Después de que el jugador inicie sesión en Play Games, puede usar el código de autenticación para autenticarse con Firebase.

  1. Una vez que el jugador haya iniciado sesión correctamente con Play Games, obtenga un código de autenticación para la cuenta del jugador.

  2. Luego, intercambia el código de autenticación de los servicios de Play Games por una credencial de Firebase y usa la credencial de Firebase para autenticar al jugador:

    firebase::auth::Credential credential =
        firebase::auth::PlayGamesAuthProvider::GetCredential(server_auth_code);
    firebase::Future<firebase::auth::AuthResult> result =
        auth->SignInAndRetrieveDataWithCredential(credential);
    
  3. Si su programa tiene un ciclo de actualización que se ejecuta regularmente (digamos, 30 o 60 veces por segundo), puede verificar los resultados una vez por actualización con 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());
      }
    }

    O, si su programa se basa en eventos, es posible que prefiera registrar una devolución de llamada en Future .

Registrar una devolución de llamada en un futuro

Algunos programas tienen funciones Update que se llaman 30 o 60 veces por segundo. Por ejemplo, muchos juegos siguen este modelo. Estos programas pueden llamar a las funciones LastResult para sondear llamadas asincrónicas. Sin embargo, si su programa está controlado por eventos, es posible que prefiera registrar funciones de devolución de llamada. Se llama a una función de devolución de llamada al finalizar el futuro.
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);
}
La función de devolución de llamada también puede ser una lambda, si lo prefiere.
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);
}

Próximos pasos

Después de que un usuario inicia sesión por primera vez, se crea una nueva cuenta de usuario y se vincula a su ID de Play Games. Esta nueva cuenta se almacena como parte de su proyecto de Firebase y se puede usar para identificar a un usuario en cada aplicación de su proyecto.

En tu juego, puedes obtener el UID de Firebase del usuario desde el objeto 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();
}

En las reglas de seguridad de Firebase Realtime Database y Cloud Storage, puede obtener el ID de usuario único del usuario que inició sesión a partir de la variable auth y usarlo para controlar a qué datos puede acceder un usuario.

Para obtener la información del jugador de Play Games de un usuario o acceder a los servicios de Play Games, utilice las API proporcionadas por el SDK de C++ de los servicios de Google Play Games .

Para cerrar la sesión de un usuario, llame a SignOut() :

auth->SignOut();