Como fazer a autenticação usando os serviços relacionados a jogos do Google Play com C++

Você pode usar os serviços do Google Play Games para fazer login de usuários em um jogo para Android criado no Firebase e escrito em C++. Para usar esse tipo de login com o Firebase, primeiro inicie a sessão do jogador no Google Play Games e solicite um código de autenticação OAuth 2.0. Em seguida, transmita o código de autenticação ao PlayGamesAuthProvider para gerar uma credencial do Firebase. Você pode usá-la para fazer autenticações com o Firebase.

Antes de começar

Adicionar o Firebase ao seu projeto do Android NDK

Para adicionar o Firebase ao seu projeto do Android NDK, siga as etapas do guia de configuração do SDK para C++ do Firebase.

Inclua o SDK para C++ do Firebase no makefile do código nativo do seu projeto:

CMake

No seu arquivo CMakeLists.txt de nível superior:

set(FIREBASE_CPP_SDK_DIR "/path/to/firebase_cpp_sdk")
string(REGEX REPLACE "(.*)_.*" "\\1" STL ${ANDROID_STL})

add_library(firebase_app STATIC IMPORTED)
set_target_properties(firebase_app PROPERTIES IMPORTED_LOCATION
    ${FIREBASE_CPP_SDK_DIR}/libs/android/${ANDROID_ABI}/${STL}/libapp.a)

add_library(firebase_auth STATIC IMPORTED)
set_target_properties(firebase_auth PROPERTIES IMPORTED_LOCATION
    ${FIREBASE_CPP_SDK_DIR}/libs/android/${ANDROID_ABI}/${STL}/libauth.a)

...

target_link_libraries(
    ...
    firebase_app
    firebase_auth)

ndk-build

No seu arquivo Android.mk:

STL := $(firstword $(subst _, ,$(APP_STL)))
FIREBASE_CPP_SDK_DIR := /path/to/frebase_cpp_sdk
FIREBASE_LIBRARY_PATH := \
    $(FIREBASE_CPP_SDK_DIR)/libs/android/$(TARGET_ARCH_ABI)/$(STL)

include $(CLEAR_VARS)
LOCAL_MODULE := firebase_app
LOCAL_SRC_FILES := $(FIREBASE_LIBRARY_PATH)/libapp.a
LOCAL_EXPORT_C_INCLUDES := $(FIREBASE_CPP_SDK_DIR)/include
include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := firebase_auth
LOCAL_SRC_FILES := $(FIREBASE_LIBRARY_PATH)/libauth.a
LOCAL_EXPORT_C_INCLUDES := $(FIREBASE_CPP_SDK_DIR)/include
include $(PREBUILT_STATIC_LIBRARY)

No seu arquivo build.gradle do nível do módulo, declare o Firebase como uma dependência:

dependencies {
    implementation 'com.google.firebase:firebase-auth:16.0.3'
    implementation 'com.google.android.gms:play-services-base:15.0.1'
    implementation 'com.google.android.gms:play-services-auth:16.0.0'
}

Configurar seu projeto do Firebase

  1. Configure a impressão digital SHA-1 do seu jogo na página Configurações do Firebase console.

    Consiga a impressão digital SHA-1 da sua chave com o comando keytool:

    keytool -exportcert -list -v \
        -alias YOUR-KEY-NAME -keystore PATH-TO-KEYSTORE

  2. Ative o Google Play Games como provedor de login:

    1. Encontre o código do cliente do servidor da Web e a chave secreta do cliente referente ao seu projeto. O código do cliente do servidor da Web identifica seu projeto do Firebase para os servidores de autenticação do Google Play.

      Para encontrar esses valores, faça o seguinte:

      1. Abra o projeto do Firebase na página de credenciais do Console de APIs do Google.
      2. Na seção de códigos do cliente OAuth 2.0, abra a página de detalhes do cliente da Web (criada automaticamente pelo serviço do Google). Nessa página, há uma lista com a chave secreta e o código do cliente do servidor da Web.
    2. Em seguida, abra a seção Autenticação no Console do Firebase.

    3. Na guia Método de login, ative o provedor de login do Play Games. Será necessário especificar o código do cliente do servidor da Web e a chave secreta do cliente referente ao seu projeto, que você localizou no Console de APIs.

  1. Abra o Google Play Console e clique em Serviços relacionados a jogos.
  2. Clique em Adicionar um novo jogo. Nessa caixa de diálogo, clique em Já utilizo APIs do Google em meu jogo e clique no nome do seu projeto do Firebase na lista. Selecione uma categoria de jogo e clique em Continuar para acessar a página de detalhes do jogo.
  3. No final dessa página, verifique se todas as APIs necessárias estão ativadas.
  4. Em seguida, abra a página Apps vinculados e clique em Android. Especifique o nome do pacote do seu jogo e clique em Salvar e continuar. O console exibirá seu código do cliente do Android. Você pode ignorar esse valor.
  5. Na página Teste, coloque na lista de permissões os endereços de e-mail de qualquer usuário que precise fazer login no seu jogo antes de liberá-lo na Play Store.

Integrar o login do Play Games ao seu jogo

Antes de permitir a conexão dos jogadores, é necessário integrar o login do Google Play Games ao seu jogo.

A maneira mais fácil e recomendável de adicionar a compatibilidade com o login do Play Games a um projeto do Android C++ é usar o SDK para C++ do Login do Google.

Para adicionar o login do Play Games ao seu jogo com o SDK para C++ do Login do Google, siga as seguintes etapas:

  1. Clone ou faça o download do repositório de plug-ins para Unity do Login do Google, que também contém o SDK para C ++.

  2. Compile o projeto contido no diretório staging/native/ com o Android Studio ou o gradlew build.

    A versão copia a própria saída para um diretório chamado google-signin-cpp.

  3. Inclua o SDK para C++ do Login do Google no makefile do código nativo do seu jogo:

    CMake

    No seu arquivo CMakeLists.txt de nível 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-build

    No seu arquivo 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. Em seguida, inclua o componente de ajuda do Java exigido pelo SDK para C++.

    Para isso, adicione o diretório de saída da versão do SDK como um repositório local no arquivo build.gradle do nível do projeto:

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

    No seu arquivo build.gradle do nível do módulo, declare o componente de ajuda como uma dependência:

    dependencies {
        implementation 'com.google.android.gms:play-services-auth:16.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. No seu jogo, configure um objeto GoogleSignIn para usar o login do Play Games e recuperar um código de autenticação do 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 fim, chame SignIn() para fazer o login do jogador no Play Games:

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

    Quando a classe Future retornada pelo SignIn() for resolvida, veja o código de autenticação do servidor no 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 no Firebase

Depois que o jogador fizer o login com o Play Games, você poderá usar o código desse processo para fazer a autenticação com o Firebase.

  1. Depois que o usuário fizer login usando o Play Games, você receberá um código de autenticação para a conta do jogador.

  2. Em seguida, troque o código de autenticação dos serviços do Play Games por uma credencial do Firebase que será usada para autenticar o jogador:

    firebase::auth::Credential credential =
        firebase::auth::PlayGamesAuthProvider::GetCredential(server_auth_code);
    firebase::Future<firebase::auth::User*> result =
        auth->SignInWithCredential(credential);
    
  3. Se o programa tiver uma rotina de atualização executada regularmente (30 ou 60 vezes por segundo), você poderá confirmar os resultados a cada atualização usando 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());
      }
    }

    Caso seu programa seja voltado para eventos, você poderá optar por registrar um retorno de chamada na classe Future.

Registrar um retorno de chamada em uma classe Future

Alguns programas têm funções Update que são chamadas 30 ou 60 vezes por segundo. Muitos jogos, por exemplo, seguem esse modelo. Esses programas podem chamar as funções LastResult para sondar chamadas assíncronas. No entanto, se seu programa for baseado em eventos, pode ser preferível registrar funções de retorno de chamada. Essas funções são chamadas na conclusão da classe 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);
}
Se você preferir, a função de retorno de chamada também pode ser um lambda.
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óximas etapas

Depois que um usuário faz login pela primeira vez, uma nova conta de usuário é criada e vinculada ao código do Play Games. Essa nova conta é armazenada como parte do seu projeto do Firebase e pode ser usada para identificar um usuário em cada app no seu projeto.

No seu jogo, você pode receber o UID do Firebase a partir do usuário do 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();
}

Nas regras de segurança do Firebase Realtime Database e do Cloud Storage, você pode usar a variável auth para encontrar o código de usuário único das pessoas que fizeram login. Use essa informação para controlar quais dados os usuários podem acessar.

Para ter acesso às informações do jogador do Play Games de um usuário ou para acessar os serviços do Google Play Games, use as APIs fornecidas pelo SDK dos serviços do Google Play Games para C++.

Para desconectar um usuário, chame SignOut():

auth->SignOut();

Enviar comentários sobre…

Precisa de ajuda? Acesse nossa página de suporte.