S'authentifier à l'aide des services de jeux Google Play avec C++

Vous pouvez utiliser les services de jeux Google Play pour connecter les joueurs à un jeu Android créé sur Firebase et écrit en C++. Pour utiliser la connexion aux services de jeux Google Play avec Firebase, connectez d'abord le joueur avec Google Play Jeux, puis demandez un code d'autorisation OAuth 2.0. Ensuite, transmettez le code d'autorisation à PlayGamesAuthProvider pour générer un identifiant Firebase, que vous pouvez utiliser pour vous authentifier auprès de Firebase.

Avant de commencer

Avant de pouvoir utiliser Firebase Authentication, vous devez :

  • Enregistrez votre projet C++ et configurez-le pour utiliser Firebase.

    Si votre projet C++ utilise déjà Firebase, il est déjà enregistré et configuré pour Firebase.

  • Ajoutez le SDK Firebase C++ à votre projet C++.

Notez que l'ajout de Firebase à votre projet C++ implique des tâches à la fois dans la console Firebase et dans votre projet C++ ouvert (par exemple, vous téléchargez les fichiers de configuration Firebase depuis la console, puis vous les déplacez dans votre projet C++).

Configurer votre projet Firebase

  1. Spécifiez l'empreinte SHA-1 de votre application, si ce n'est pas déjà fait.

    1. Dans la consoleFirebase, accédez à Paramètres > onglet Général.

    2. Faites défiler la page jusqu'à la fiche Vos applications, sélectionnez votre application Android et ajoutez votre empreinte SHA-1 dans le champ Empreintes de certificat SHA.

    Vous pouvez obtenir le hachage SHA de votre certificat de signature avec la commande gradle signingReport :

    ./gradlew signingReport

    Pour savoir comment obtenir l'empreinte SHA de votre application, consultez Authentifier votre client.

  2. Activer Google Play Games comme fournisseur de connexion :

    1. Dans la console Firebase, accédez à Sécurité > Authentification.

    2. Générez et obtenez l'ID client et le code secret du client du serveur Web de votre projet :

      1. Dans l'onglet Méthode de connexion, activez le fournisseur de connexion Google.

      2. Copiez l'ID client et le code secret du serveur Web à partir du fournisseur de connexion Google.

    3. Dans l'onglet Méthode de connexion, activez le fournisseur de connexion Play Games, puis spécifiez l'ID client et le code secret du client du serveur Web de votre projet, que vous avez obtenus à la dernière étape.

Configurer Play Games services avec les informations de votre application Firebase

  1. Dans la console Google Play, ouvrez votre application Google Play ou créez-en une.

  2. Dans la section Croissance, cliquez sur Play Games services > Configuration et gestion > Configuration.

  3. Cliquez sur Oui, mon jeu utilise déjà des API Google, sélectionnez votre projet Firebase dans la liste, puis cliquez sur Utiliser.

  4. Sur la page de configuration Play Games services, cliquez sur Ajouter un identifiant.

    1. Sélectionnez le type Serveur de jeu.
    2. Dans le champ Client OAuth, sélectionnez l'ID client Web de votre projet. Assurez-vous qu'il s'agit du même ID client que celui que vous avez spécifié lorsque vous avez activé la connexion Play Games.
    3. Enregistrez les modifications.
  5. Toujours sur la page de configuration Play Games services, cliquez de nouveau sur Ajouter des identifiants.

    1. Sélectionnez le type Android.
    2. Dans le champ Client OAuth, sélectionnez l'ID client Android de votre projet. (Si votre ID client Android ne s'affiche pas, assurez-vous d'avoir défini l'empreinte SHA-1 de votre jeu dans la console Firebase.)
    3. Enregistrez les modifications.
  6. Sur la page Testeurs, ajoutez les adresses e-mail des utilisateurs qui doivent pouvoir se connecter à votre jeu avant sa sortie sur Play Store.

Intégrer la connexion à Play Jeux dans votre jeu

Avant de pouvoir connecter les joueurs à votre jeu, vous devez intégrer la connexion Google Play Jeux.

Le moyen le plus simple et recommandé d'ajouter la connexion à Play Jeux à un projet Android C++ consiste à utiliser le SDK Google Sign-In C++.

Pour ajouter la connexion Play Jeux à votre jeu à l'aide du SDK Google Sign-in C++, procédez comme suit :

  1. Clonez ou téléchargez le dépôt du plug-in Google Sign-In Unity, qui contient également le SDK C++.

  2. Créez le projet contenu dans le répertoire staging/native/, soit à l'aide d'Android Studio, soit à l'aide de gradlew build.

    La compilation copie sa sortie dans un répertoire nommé google-signin-cpp.

  3. Incluez le SDK Google Sign-In C++ dans le fichier make du code natif de votre jeu :

    CMake

    Dans votre fichier CMakeLists.txt de premier niveau :

    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

    Dans votre fichier 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. Ensuite, incluez le composant d'assistance Java, qui est requis par le SDK C++.

    Pour ce faire, dans le fichier build.gradle au niveau du projet, ajoutez le répertoire de sortie de compilation du SDK en tant que dépôt local :

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

    Ensuite, dans le fichier build.gradle au niveau du module, déclarez le composant d'assistance comme dépendance :

    dependencies {
        implementation 'com.google.android.gms:play-services-auth:22.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. Ensuite, dans votre jeu, configurez un objet GoogleSignIn pour utiliser la connexion à Play Jeux et récupérer un code d'autorisation de serveur :

    #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. Enfin, appelez SignIn() pour connecter le joueur aux services de jeux Play :

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

    Lorsque le Future renvoyé par SignIn() est résolu, vous pouvez obtenir le code d'authentification du serveur à partir du résultat :

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

S'authentifier avec Firebase

Une fois que le joueur s'est connecté à Play Jeux, vous pouvez utiliser le code d'authentification pour vous authentifier auprès de Firebase.

  1. Une fois que le joueur s'est connecté à l'aide de Play Jeux, obtenez un code d'authentification pour son compte.

  2. Échangez ensuite le code d'autorisation des services de jeux Play contre un identifiant Firebase, puis utilisez cet identifiant pour authentifier le joueur :

    firebase::auth::Credential credential =
        firebase::auth::PlayGamesAuthProvider::GetCredential(server_auth_code);
    firebase::Future<firebase::auth::AuthResult> result =
        auth->SignInAndRetrieveDataWithCredential(credential);
    
  3. Si votre programme comporte une boucle de mise à jour qui s'exécute régulièrement (par exemple, 30 ou 60 fois par seconde), vous pouvez vérifier les résultats une fois par mise à jour avec 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 votre programme est axé sur les événements, vous pouvez également enregistrer un rappel sur l'avenir.

Enregistrer un rappel sur un Future

Certains programmes comportent des fonctions Update qui sont appelées 30 ou 60 fois par seconde. Par exemple, de nombreux jeux suivent ce modèle. Ces programmes peuvent appeler les fonctions LastResult pour interroger les appels asynchrones. Toutefois, si votre programme est axé sur les événements, vous préférerez peut-être enregistrer des fonctions de rappel. Une fonction de rappel est appelée à la fin de l'objet 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 fonction de rappel peut également être un lambda, si vous le préférez.
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);
}

Étapes suivantes

Lorsqu'un utilisateur se connecte pour la première fois, un compte utilisateur est créé et associé à son ID Play Jeux. Ce nouveau compte est stocké dans votre projet Firebase et peut être utilisé pour identifier un utilisateur dans toutes les applications de votre projet.

Dans votre jeu, vous pouvez obtenir l'UID Firebase de l'utilisateur à partir de l'objet 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();
}

Dans vos règles de sécurité Firebase Realtime Database et Cloud Storage, vous pouvez obtenir l'ID utilisateur unique de l'utilisateur connecté à partir de la variable auth et l'utiliser pour contrôler les données auxquelles un utilisateur peut accéder.

Pour obtenir les informations d'un joueur Play Jeux ou accéder aux services Play Games, utilisez les API fournies par le SDK C++ des services Google Play Games.

Pour déconnecter un utilisateur, appelez SignOut() :

auth->SignOut();