Eseguire la migrazione a Play Games Services v2 (Unity)

Questo documento descrive come eseguire la migrazione dei giochi esistenti dall'SDK games v1 all'SDK games v2. Il plug-in Play Games per Unity, versioni 10 e precedenti, utilizza l'SDK games v1.

Prima di iniziare

  • Assicurati di aver già configurato Play Console e installato Unity Editor.

Scarica il plug-in Google Play Games per Unity

Per usufruire delle funzionalità più recenti di Play Games Services, scarica e installa l'ultima versione del plug-in. Scaricalo dal repository GitHub.

Rimuovi il vecchio plug-in

In Unity Editor, rimuovi le seguenti cartelle o i seguenti file.

Assets/GooglePlayGames

Assets/GeneratedLocalRepo/GooglePlayGames

Assets/Plugins/Android/GooglePlayGamesManifest.androidlib

Assets/Plugins/Android
Rimuovi le cartelle evidenziate nel progetto Unity.
Rimuovi le cartelle evidenziate nel progetto Unity (fai clic per ingrandire).

Importa il nuovo plug-in nel progetto Unity

Per importare il plug-in nel progetto Unity:

  1. Apri il progetto di gioco.
  2. In Unity Editor, fai clic su Assets > Import Package > Custom Package per importare il file unitypackage nelle risorse del progetto.
  3. Assicurati che la piattaforma di build corrente sia impostata su Android.

    1. Nel menu principale, fai clic su File > Build Settings (File > Impostazioni di build).

    2. Seleziona Android e fai clic su Switch Platform (Cambia piattaforma).

    3. Dovrebbe essere presente una nuova voce di menu in Window > Google Play Games (Finestra > Google Play Games). In caso contrario, aggiorna le risorse facendo clic su Assets > Refresh (Risorse > Aggiorna) e poi prova a impostare di nuovo la piattaforma di build.

  4. In Unity Editor, fai clic su File > Build Settings > Player Settings > Other Settings (File > Impostazioni di build > Impostazioni del giocatore > Altre impostazioni).

  5. Nella casella Target API level (Livello API target), seleziona una versione.

  6. Nella casella Scripting backend (Backend di scripting), inserisci IL2CPP.

  7. Nella casella Target architectures (Architetture target), seleziona un valore.

  8. Prendi nota del nome del pacchetto package_name.Puoi utilizzare queste informazioni in un secondo momento.

    Le impostazioni del player nel progetto Unity
    Le impostazioni del giocatore nel progetto Unity.
  9. Copia le risorse Android da Play Console

  10. Aggiungi le risorse Android al progetto Unity

Percorsi di migrazione

Il percorso di migrazione corretto per il tuo gioco dipende da come implementa i servizi per i giochi di Play v1 e gestisce l'identità del giocatore. Per garantire una transizione senza problemi ed evitare la perdita di dati dei giocatori, identifica lo scenario che corrisponde meglio alla configurazione esistente e segui i passaggi corrispondenti.

Opzione 1: per i giochi in cui l'IGA è associato all'ID giocatore di Play Games Services

Questo scenario si applica ai giochi che hanno utilizzato i Play Games Services Player ID come unico identificatore per un account di gioco (IGA) di un giocatore e non hanno richiesto o memorizzato in precedenza un OpenID. La sfida principale è collegare l'IGA esistente a un identificatore principale (l'OpenID) senza perdere la connessione ai progressi del giocatore.

Il flusso di migrazione include i seguenti passaggi:

  1. Quando il gioco viene avviato, l'SDK di Play Games Services v2 autentica automaticamente e in modo silenzioso la piattaforma.
  2. Il gioco mostra la schermata di accesso. Questa schermata deve includere un pulsante Accedi con Google (SiWG) che sostituisce il pulsante Google Play. Per l'integrazione:

    1. Scarica CredManBridge.java nella tua cartella. Questa classe Java funge da bridge tra Unity e la libreria androidx.credentials.

      CredManBridge.java
      
      package com.wickedcube.trivialkart;
      import android.accounts.Account;
      import android.content.Context;
      import android.util.Log;
      import android.os.CancellationSignal;
      import androidx.credentials.CredentialManager;
      import androidx.credentials.GetCredentialRequest;
      import androidx.credentials.GetCredentialResponse;
      import androidx.credentials.exceptions.GetCredentialException;
      import androidx.credentials.exceptions.NoCredentialException;
      import com.google.android.libraries.identity.googleid.GetGoogleIdOption;
      import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential;
      import com.google.android.gms.auth.api.identity.AuthorizationClient;
      import com.google.android.gms.auth.api.identity.AuthorizationRequest;
      import com.google.android.gms.auth.api.identity.AuthorizationResult;
      import com.google.android.gms.common.api.ApiException;
      import com.google.android.gms.auth.api.identity.Identity;
      import com.google.android.gms.common.api.Scope;
      import com.unity3d.player.UnityPlayer;
      import java.util.Collections;
      import java.util.List;
      import java.util.concurrent.Executor;
      import java.util.concurrent.Executors;

      public class CredManBridge {

      // --- MODE 1: SILENT SIGN-IN (Called on Awake) --- // Tries to auto-select an authorized account. If it fails, it does NOT show UI. public static void signInSilent(Context context, String webClientId) { CredentialManager credentialManager = CredentialManager.create(context); CancellationSignal cancellationSignal = new CancellationSignal(); Executor executor = Executors.newSingleThreadExecutor();

      Log.d("CredMan", "Attempting Silent Sign-In...");

      GetGoogleIdOption silentOption = new GetGoogleIdOption.Builder() .setFilterByAuthorizedAccounts(true) // Strict: Only authorized accounts .setServerClientId(webClientId) .setAutoSelectEnabled(true) // Auto-select if possible .build();

      GetCredentialRequest silentRequest = new GetCredentialRequest.Builder() .addCredentialOption(silentOption) .build();

      credentialManager.getCredentialAsync( context, silentRequest, cancellationSignal, executor, new androidx.credentials.CredentialManagerCallback<GetCredentialResponse, GetCredentialException>() { @Override public void onResult(GetCredentialResponse result) { Log.d("CredMan", "Silent Sign-In Successful!"); handleSignInResult(context, result, webClientId); }

          @Override
          public void onError(GetCredentialException e) {
              // Send a specific error code so Unity knows to just stay on the Start Screen
              Log.d("CredMan", "Silent sign-in failed. Keeping UI hidden.");
              UnityPlayer.UnitySendMessage("AuthManager", "OnSignInError", "SilentFailed");
          }
      }
      

      ); }

      // --- MODE 2: INTERACTIVE SIGN-IN (Called on Button Click) --- // Forces the Account Selection / "Add Account" sheet to appear. public static void signInInteractive(Context context, String webClientId) { CredentialManager credentialManager = CredentialManager.create(context); CancellationSignal cancellationSignal = new CancellationSignal(); Executor executor = Executors.newSingleThreadExecutor();

      Log.d("CredMan", "Starting Interactive Sign-In...");

      GetGoogleIdOption interactiveOption = new GetGoogleIdOption.Builder() .setFilterByAuthorizedAccounts(false) // Show ALL accounts (and "Add Account") .setServerClientId(webClientId) .setAutoSelectEnabled(false) // Force the UI to show .build();

      GetCredentialRequest interactiveRequest = new GetCredentialRequest.Builder() .addCredentialOption(interactiveOption) .build();

      credentialManager.getCredentialAsync( context, interactiveRequest, cancellationSignal, executor, new androidx.credentials.CredentialManagerCallback<getcredentialresponse, getcredentialexception="">() { @Override public void onResult(GetCredentialResponse result) { Log.d("CredMan", "Interactive Sign-In Successful!"); handleSignInResult(context, result, webClientId); }</getcredentialresponse,>

          @Override
          public void onError(GetCredentialException e) {
              Log.e("CredMan", "Interactive Sign-In Canceled or Failed", e);
              UnityPlayer.UnitySendMessage("AuthManager", "OnSignInError", "Canceled");
          }
      }
      

      ); }

      private static void handleSignInResult(Context context, GetCredentialResponse result, String webClientId) { try { GoogleIdTokenCredential credential = GoogleIdTokenCredential.createFrom(result.getCredential().getData()); String email = credential.getId();

      Account account = new Account(email, "com.google");
      // Requesting GAMES_LITE scope to check for pre-existing V1 grants
      List<Scope> requestedScopes = Collections.singletonList(new Scope("https://www.googleapis.com/auth/games_lite"));
      
      AuthorizationRequest authRequest = new AuthorizationRequest.Builder()
          .setRequestedScopes(requestedScopes)
          .setAccount(account)
          .requestOfflineAccess(webClientId)
          .build();
      
      AuthorizationClient authClient = Identity.getAuthorizationClient(context);
      
      authClient.authorize(authRequest)
          .addOnSuccessListener(authorizationResult -> {
              if (authorizationResult.getServerAuthCode() != null) {
                  // CASE 1: RETURNING USER (Success)
                  // The user has already granted GAMES_LITE in the past.
                  // We got the code directly without showing UI.
                  Log.i("CredMan", "PGS v1: Existing grant found. Returning user detected. Auth Code retrieved.");
                  UnityPlayer.UnitySendMessage("AuthManager", "OnSignInSuccess", authorizationResult.getServerAuthCode());
              }
              else if (authorizationResult.hasResolution()) {
                  // CASE 2: NEW USER (PendingIntent)
                  // The user has NOT granted GAMES_LITE before. The API returned a PendingIntent
                  // (authorizationResult.getPendingIntent()) to show the consent screen.
                  // As per your flow, we DISCARD this intent and do not show UI.
                  Log.i("CredMan", "PGS v1: No existing grant (PendingIntent returned). This is a NEW user or they revoked access.");
                  Log.i("CredMan", "PGS v1: Discarding PendingIntent. Proceeding as New User.");
      
                  // Notify Unity that this is a "New User" so it can trigger V2 logic instead of failing
                  UnityPlayer.UnitySendMessage("AuthManager", "OnSignInError", "NewUser_NoGrant");
              }
              else {
                  // Edge Case: No code and no resolution?
                  Log.e("CredMan", "PGS v1: Authorization success but no Auth Code or Resolution returned.");
                  UnityPlayer.UnitySendMessage("AuthManager", "OnSignInError", "No Auth Code returned");
              }
          })
          .addOnFailureListener(e -> {
              // CASE 3: GENERIC FAILURE
              Log.e("CredMan", "PGS v1: Authorization failed completely.", e);
              UnityPlayer.UnitySendMessage("AuthManager", "OnSignInError", "Authorization Failed: " + e.getMessage());
          });
      

      } catch (Exception e) { UnityPlayer.UnitySendMessage("AuthManager", "OnSignInError", "Parsing Error: " + e.getMessage()); } } }

    2. Integrazione di Gestore delle credenziali:

      • Utilizza GetGoogleIdOption con setFilterByAuthorizedAccounts(true) per gli accessi silenziosi in modo da consentire l'accesso solo agli utenti che hanno autorizzato l'app in precedenza.
      • Utilizza setFilterByAuthorizedAccounts(false) per gli accessi interattivi in modo da consentire agli utenti di selezionare un account o aggiungerne uno nuovo.
    3. Richiesta di ambito:

      • Dopo aver ottenuto la credenziale Google di base, crea un AuthorizationRequest che richiede l'ambito legacy specifico: https://www.googleapis.com/auth/games_lite.
      • Questo ambito è fondamentale perché concede al server l'autorizzazione a cercare l'ID giocatore legacy dell'utente.
    4. Gestione dei risultati:

      • Se l'utente concede l'autorizzazione (o l'ha concessa in precedenza), il bridge restituisce il ServerAuthCode a Unity.
      • Se l'utente non ha concesso l'autorizzazione (scenario per i nuovi utenti), l'API restituisce un PendingIntent. In questo esempio, l'intent viene ignorato e l'utente viene trattato come un nuovo utente per semplificare il flusso.
  3. Per supportare Gestore delle credenziali e i servizi di identità Google, assicurati che le seguenti dipendenze siano aggiunte alla configurazione Gradle mainTemplate.gradle.

    dependencies {
    // Standard Unity dependencies
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    
    // Credential Manager and Identity Libraries
    implementation 'androidx.credentials:credentials:1.3.0'
    implementation 'androidx.credentials:credentials-play-services-auth:1.3.0'
    implementation 'com.google.android.libraries.identity.googleid:googleid:1.1.1'
    
    // Play Services Auth for legacy scope handling
    implementation 'com.google.android.gms:play-services-auth:21.2.0'
    }
    • Gestore delle credenziali: gestisce l'orchestrazione dell'identità principale e l'interfaccia utente per la selezione dell'account.
    • Libreria GoogleID: fornisce in modo specifico GetGoogleIdOption per recuperare i token OpenID Connect.
    • Autenticazione di Play Services: necessaria per mantenere la compatibilità e richiedere l'ambito GAMES_LITE per il recupero dell'Player ID legacy.
  4. Quando il giocatore tocca il pulsante SiWG e seleziona un Account Google, il gioco deve recuperare due identificatori distinti:

    • L'OpenID, l'identificatore principale per l'associazione dell'IGA.
    • I Play Games Services Player ID, recuperati utilizzando l'ambito GAMES_LITE, per cercare l'IGA del giocatore nel sistema di backend ed eseguire l'associazione.
  5. Nei successivi avvii del gioco, i giocatori possono accedere al proprio IGA tramite il flusso SiWG, senza che i giochi debbano utilizzare Player ID come identificatore principale.

Puoi eseguire il passaggio 4 utilizzando un'implementazione lato client del gioco.

  1. Lo sviluppatore chiama l'API Android Credential Manager per consentire all'utente di accedere con un Account Google.
  2. Dopo che l'utente ha completato SiWG e selezionato un Account Google, lo sviluppatore riceve un oggetto risultato contenente il token ID e l'indirizzo email.
  3. Lo sviluppatore crea un oggetto Account dall'indirizzo email.
  4. Lo sviluppatore chiama l'API Authorization con l'ambito GAMES_LITE e l'Account.
  5. Se l'account ha una concessione preesistente nell'ambito GAMES_LITE, l'API Authorization restituisce un token direttamente nell'oggetto della risposta.
    1. Utilizza il token di risposta per chiamare i server di Play Games Services e recuperare i Play Games Services Player ID.
    2. Lo sviluppatore verifica se i Play Games Services Player ID sono stati collegati a un account di gioco.
      1. Lo sviluppatore sa che si tratta di un utente di ritorno da Play Games Services v1.
    3. Lo sviluppatore può collegare il nuovo ID GAIA all'account precedente di Play Games Services v1.
  6. In alternativa, se l'account non ha una concessione preesistente nell'ambito GAMES_LITE, l'API Authorization restituisce un PendingIntent.
    1. Lo sviluppatore sa che l'utente non ha un account esistente da Play Games Services v1.
    2. Lo sviluppatore può ignorare in sicurezza il PendingIntent senza mostrare alcuna UI.

Opzione 2: per i giochi che già associano l'IGA all'OpenID

Gli sviluppatori di questo gruppo hanno il percorso di migrazione più semplice. Se l'account di gioco del tuo gioco è già associato principalmente all'OpenID, devi solo eseguire la migrazione tecnica standard dell'SDK dalla v1 alla v2, come descritto nei passaggi.

Aggiorna il codice di accesso automatico

Sostituisci la classe di inizializzazione PlayGamesClientConfiguration con la classe PlayGamesPlatform.Instance.Authenticate(). Non è richiesta l'inizializzazione e l'attivazione di PlayGamesPlatform. La chiamata a PlayGamesPlatform.Instance.Authenticate() recupera il risultato dell'accesso automatico. Per ulteriori informazioni sul flusso di autenticazione consigliato con l'integrazione di Play Games Services v2, consulta la sezione Linee guida per l'esperienza utente per il flusso di autenticazione ideale.

C#

In Unity Editor, individua i file con la classe PlayGamesClientConfiguration.

using GooglePlayGames;
using GooglePlayGames.BasicApi;
using UnityEngine.SocialPlatforms;

public void Start() {
    PlayGamesClientConfiguration config =
        new PlayGamesClientConfiguration.Builder()
    // Enables saving game progress
    .EnableSavedGames()
    // Requests the email address of the player be available
    // will bring up a prompt for consent
    .RequestEmail()
    // Requests a server auth code be generated so it can be passed to an
    // associated backend server application and exchanged for an OAuth token
    .RequestServerAuthCode(false)
    // Requests an ID token be generated. This OAuth token can be used to
    // identify the player to other services such as Firebase.
    .RequestIdToken()
    .Build();

    PlayGamesPlatform.InitializeInstance(config);
    // recommended for debugging:
    PlayGamesPlatform.DebugLogEnabled = true;
    // Activate the Google Play Games platform
    PlayGamesPlatform.Activate();
}

Aggiornali come segue:

using GooglePlayGames;

public void Start() {
    PlayGamesPlatform.Instance.Authenticate(ProcessAuthentication);
}

internal void ProcessAuthentication(SignInStatus status) {
    if (status == SignInStatus.Success) {
        // Continue with Play Games Services
    } else {
        // Disable your integration with Play Games Services or show a login
        // button to ask users to sign-in. Clicking it should call
        // PlayGamesPlatform.Instance.ManuallyAuthenticate(ProcessAuthentication).
    }
}

Scegli una piattaforma social

Per scegliere una piattaforma social, consulta la sezione Scegliere una piattaforma social.

Recupera i codici di autenticazione server

Per ottenere i codici di accesso lato server, consulta la sezione Recuperare i codici di autenticazione server.

Rimuovi il codice di disconnessione

Rimuovi il codice per la disconnessione. Play Games Services non richiede più un pulsante di disconnessione in-game.

Rimuovi il codice mostrato nell'esempio seguente:

C#

// sign out
PlayGamesPlatform.Instance.SignOut();

Testare il gioco

Assicurati che il gioco funzioni come previsto testandolo. I test che esegui dipendono dalle funzionalità del gioco.

Di seguito è riportato un elenco di test comuni da eseguire.

  1. Accesso riuscito.

    1. L'accesso automatico funziona. L'utente deve aver eseguito l'accesso a Play Games Services all'avvio del gioco.

    2. Viene visualizzato il popup di benvenuto.

      Esempio di popup di benvenuto.
      Esempio di popup di benvenuto (fai clic per ingrandire).

    3. Vengono visualizzati i messaggi di log di operazione riuscita. Esegui questo comando nel terminale:

      adb logcat | grep com.google.android.

      Nell'esempio seguente viene mostrato un messaggio di log di operazione riuscita:

      [$PlaylogGamesSignInAction$SignInPerformerSource@e1cdecc
      number=1 name=GAMES_SERVICE_BROKER>], returning true for shouldShowWelcomePopup.
      [CONTEXT service_id=1 ]
  2. Assicurati della coerenza dei componenti dell'UI.

    1. I popup, le classifiche e gli obiettivi vengono visualizzati correttamente e in modo coerente su varie dimensioni e orientamenti dello schermo nell'interfaccia utente (UI) dei servizi per i giochi di Play.

    2. L'opzione di disconnessione non è visibile nell'UI di Play Games Services.

    3. Assicurati di poter recuperare correttamente l'ID giocatore e, se applicabile, che le funzionalità lato server funzionino come previsto.

    4. Se il gioco utilizza l'autenticazione lato server, testa attentamente il flusso requestServerSideAccess. Assicurati che il server riceva il codice di autorizzazione e possa scambiarlo con un token di accesso. Testa gli scenari di successo e di errore per gli errori di rete e gli scenari non validi client ID.

Se il tuo gioco utilizzava una delle seguenti funzionalità, testale per assicurarti che funzionino come prima della migrazione:

  • Classifiche: invia i punteggi e visualizza le classifiche. Verifica la corretta classificazione e visualizzazione dei nomi e dei punteggi dei giocatori.
  • Obiettivi: sblocca gli obiettivi e verifica che vengano registrati correttamente e visualizzati nell'UI di Play Games.
  • Partite salvate: se il gioco utilizza le partite salvate, assicurati che il salvataggio e il caricamento dei progressi del gioco funzionino perfettamente. È particolarmente importante eseguire il test su più dispositivi e dopo gli aggiornamenti dell'app.

Attività post-migrazione

Completa i seguenti passaggi dopo aver eseguito la migrazione all'SDK games v2.

  1. Utilizzare la firma dell'app di Google Play

  2. Creare un file AAB

  3. Crea release di test interno

  4. Verifica le credenziali di firma dell'app