Autentica con los Servicios de juego de Google Play con C++

Puedes usar los Servicios de juego de Google Play para controlar el acceso de usuarios a un juego de Android compilado en Firebase y escrito en C++. Para usar el acceso de los Servicios de juego de Google Play con Firebase, haz que el jugador acceda a Google Play Juegos y solicita un código de autorización OAuth 2.0 durante el proceso. Después, pasa el código de Auth a PlayGamesAuthProvider para generar una credencial de Firebase que podrás usar para autenticar con la plataforma.

Antes de comenzar

Para poder usar Firebase Authentication, debes realizar los siguientes pasos:

  • Registra tu proyecto de C++ y configúralo para usar Firebase.

    Si el proyecto de C++ ya usa Firebase, significa que ya está registrado y configurado para esa plataforma.

  • En el archivo build.gradle de nivel de proyecto, asegúrate de incluir el repositorio Maven de Google en las secciones buildscript y allprojects.

  • Agrega el SDK de Firebase C++ al proyecto de C++.

Ten en cuenta que, para agregar Firebase a tu proyecto de C++, debes realizar tareas tanto en Firebase console como en tu proyecto abierto de C++ (por ejemplo, descargar los archivos de configuración de Firebase desde la consola y transferirlos a tu proyecto de C++).

Configura el 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.

    Para obtener el hash SHA de tu certificado de firma con el comando signingReport de Gradle, haz lo siguiente:

    ./gradlew signingReport

  2. Habilita Google Play Juegos como proveedor de acceso:

    1. Encuentra el secreto de cliente y el ID de cliente del servidor web del proyecto. El ID de cliente del servidor web identifica tu proyecto de Firebase en los servidores de autenticación de Google Play.

      Sigue estos pasos para encontrar esos valores:

      1. Abre el proyecto de Firebase en la página de credenciales de la Consola de API de Google.
      2. En la sección ID de cliente de OAuth 2.0, abre la página de detalles Cliente web (creado automáticamente por el servicio de Google). Esta página muestra el ID y el secreto de cliente del servidor web.
    2. Luego, en Firebase console, abre la sección Authentication.

    3. En la pestaña Método de acceso, habilita el proveedor de acceso Play Juegos. Deberás especificar el secreto de cliente y el ID de cliente del servidor web del proyecto, que obtuviste de la Consola de API.

  1. Abre Google Play Console y haz clic en Servicios de juego.
  2. Haz clic en Agregar juego nuevo. En el diálogo de juego nuevo, haz clic en Ya utilizo las API de Google en mi juego y haz clic en el nombre de tu proyecto de Firebase en la lista. Selecciona una categoría de juego y haz clic en Continuar para ir a la página de detalles del juego.
  3. Asegúrate de que todas las API necesarias estén habilitadas al final de la página de detalles del juego.
  4. Luego, abre la página Apps vinculadas y haz clic en Android. Especifica el nombre del paquete de tu juego y haz clic en Guardar y continuar. La consola mostrará tu ID de cliente de Android. Puedes ignorar este valor.
  5. En la página Pruebas, incluye en la lista blanca las direcciones de correo electrónico de los usuarios que deben poder acceder a tu juego antes de su lanzamiento en Play Store.

Integra el acceso a Play Juegos en tu juego

Antes de hacer que los usuarios accedan a tu juego, debes integrar el acceso con Google Play Juegos.

Usar el SDK de C++ de Acceso con Google es la manera recomendada y más sencilla de agregar compatibilidad para el acceso con Play Juegos a un proyecto de Android C++.

Para agregar el acceso a tu juego con Play Juegos mediante el SDK de C++ de Acceso con Google, haz lo siguiente:

  1. Clona o descarga el repositorio del complemento de Unity de Acceso con Google, que también contiene el SDK de C++.

  2. Compila el proyecto contenido en el directorio staging/native/ con Android Studio o gradlew build.

    La compilación copia los resultados en un directorio llamado google-signin-cpp.

  3. Incluye el SDK de C++ de Acceso con Google en el archivo de construcción de código nativo del juego:

    CMake

    En el archivo CMakeLists.txt de nivel superior, incluye lo siguiente:

    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

    En el archivo Android.mk, incluye lo siguiente:

    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, incluye el componente auxiliar de Java, que necesita el SDK de C++.

    Para ello, en el archivo build.gradle de nivel de proyecto, agrega el directorio de resultados de compilación del SDK como repositorio local:

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

    Y, en el archivo build.gradle de nivel de módulo, declara el componente auxiliar como dependencia:

    dependencies {
        implementation 'com.google.android.gms:play-services-auth:18.1.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. A continuación, en tu juego, configura un objeto GoogleSignIn para usar el acceso a Play Juegos y recuperar un código de Auth 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. Por último, llama a SignIn() para hacer que el usuario acceda a Play Juegos:

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

    Cuando se resuelva el valor Future generado con SignIn(), podrás obtener del resultado el código de Auth del servidor:

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

Autentica con Firebase

Después de que el jugador acceda con Play Juegos, puedes usar el código Auth para realizar la autenticación con Firebase.

  1. Después de que el jugador acceda correctamente mediante Play Juegos, obtén un código de Auth para la cuenta del jugador:

  2. Luego, intercambia el código de Auth de los servicios de Play Juegos por una credencial de Firebase. Luego, usa esa credencial para autenticar al jugador de la siguiente manera:

    firebase::auth::Credential credential =
        firebase::auth::PlayGamesAuthProvider::GetCredential(server_auth_code);
    firebase::Future<firebase::auth::User*> result =
        auth->SignInWithCredential(credential);
    
  3. Si el programa tiene un bucle de actualización que se ejecuta con regularidad (por ejemplo, 30 o 60 veces por segundo), puedes verificar los resultados una vez por actualización con Auth::SignInWithCredentialLastResult:

    firebase::Future<firebase::auth::User*> result =
        auth->SignInWithCredentialLastResult();
    if (result.status() == firebase::kFutureStatusComplete) {
      if (result.error() == firebase::auth::kAuthErrorNone) {
        firebase::auth::User* user = *result.result();
        printf("Sign in succeeded for `%s`\n", user->display_name().c_str());
      } else {
        printf("Sign in failed with error '%s'\n", result.error_message());
      }
    }

    Si tu programa es controlado por eventos, te recomendamos que registres una devolución de llamada en Future.

Registra una devolución de llamada en Future

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 las llamadas asíncronas. Sin embargo, si tu programa es controlado por eventos, tal vez sea mejor que registres funciones de devolución de llamada. Se solicita una función de devolución de llamada una vez que se complete 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::User*> 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 lambda, si así lo prefieres.
void CreateUserUsingLambda(firebase::auth::Auth* auth) {
  // Callbacks work the same for any firebase::Future.
  firebase::Future<firebase::auth::User*> 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

Cuando un usuario accede por primera vez, se crea una nueva cuenta de usuario que se vincula a su ID de Play Juegos. Esta cuenta nueva se almacena como parte de tu proyecto de Firebase y puede usarse para identificar a un usuario en todas las apps del 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 != nullptr) {
  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 tus reglas de seguridad de Firebase Realtime Database y Cloud Storage, puedes obtener el ID del usuario único que accedió a partir de la variable auth y usarlo para controlar a qué datos podrá acceder.

Para obtener la información de un usuario en Play Juegos o acceder a los servicios de Play Juegos, usa las API incluidas en el SDK de C++ de Servicios de juego de Google Play.

Para salir de la sesión de un usuario, llama a SignOut():

auth->SignOut();