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

Antes de poder usar Firebase Authentication, tendrás que hacer lo siguiente:

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

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

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

Ten en cuenta que agregar Firebase a un proyecto de C++ implica realizar tareas en Firebase console y en el proyecto abierto de C++ (por ejemplo, descargar archivos de configuración de Firebase desde la consola y transferirlos al 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 Games como proveedor de acceso:

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

    2. Genera y obtén el secreto de cliente y el ID de cliente del servidor web de tu proyecto:

      1. En la pestaña Sign in method, habilita el proveedor de acceso de Google.

      2. Copia el ID y el secreto de cliente del servidor web del proveedor de acceso de Google.

    3. En la pestaña Método de acceso, habilita el proveedor de acceso de Play Games y especifica el ID y el secreto de cliente del servidor web de tu proyecto, que obtuviste en el paso anterior.

Configura Play Games services con la información de tu app de Firebase

  1. En Google Play Console, abre tu app de Google Play o crea una.

  2. En la sección Crecimiento, haz clic en Play Games services > Configuración y administración > Configuración.

  3. Haz clic en Sí, mi juego ya usa las APIs 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 Play Games services, haz clic en Agregar credencial.

    1. Selecciona el tipo Servidor de juegos.
    2. En el campo Cliente de OAuth, selecciona el ID de cliente web de tu proyecto. Asegúrate de que sea el mismo ID de cliente que especificaste cuando habilitaste el acceso con Play Games.
    3. Guarda los cambios.
  5. En la página de configuración de Play Games services, vuelve a hacer clic en Agregar credencial.

    1. Selecciona el tipo Android.
    2. En el campo Cliente de OAuth, selecciona el ID de cliente de Android de tu proyecto. Si no ves tu ID de cliente de Android, asegúrate de establecer la huella digital SHA-1 de tu juego en Firebase console.
    3. Guarda los cambios.
  6. En la página Verificadores, incluye 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 que incorpores jugadores en tu juego, debes integrar el acceso a 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 a 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:21.2.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 desde los Servicios de juego de Play para obtener 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::AuthResult> result =
        auth->SignInAndRetrieveDataWithCredential(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::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());
      }
    }

    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::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 lambda, si así lo prefieres.
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

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

A fin de obtener la información de jugador de Play Juegos de un usuario o para acceder a los servicios de Play Juegos, usa las API que proporcionó 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();