Migracja do wersji 2 usług gier Play (Unity)

W tym dokumencie opisujemy, jak przeprowadzić migrację dotychczasowych gier z pakietu SDK dla gier w wersji 1 do pakietu SDK dla gier w wersji 2. Wtyczka Gry Play do silnika Unity w wersji 10 i starszych korzysta z pakietu SDK dla gier w wersji 1.

Zanim zaczniesz

  • Upewnij się, że masz już skonfigurowaną Konsolę Play i zainstalowany edytor Unity.

Pobieranie wtyczki Gry Google Play do silnika Unity

Aby korzystać z najnowszych funkcji usług gier Play, pobierz i zainstaluj najnowszą wersję wtyczki. Pobierz ją z repozytorium GitHub.

Usuwanie starej wtyczki

W edytorze Unity usuń te foldery lub pliki.

Assets/GooglePlayGames

Assets/GeneratedLocalRepo/GooglePlayGames

Assets/Plugins/Android/GooglePlayGamesManifest.androidlib

Assets/Plugins/Android
Usuń wyróżnione foldery w projekcie Unity.
Usuń wyróżnione foldery w projekcie Unity (kliknij, aby powiększyć).

Importowanie nowej wtyczki do projektu Unity

Aby zaimportować wtyczkę do projektu Unity, wykonaj te czynności:

  1. Otwórz projekt gry.
  2. W edytorze Unity kliknij Assets > Import Package > Custom Package, aby zaimportować pobrany unitypackage plik do zasobów projektu.
  3. Upewnij się, że bieżąca platforma kompilacji jest ustawiona na Android.

    1. W menu głównym kliknij File > Build Settings (Plik > Ustawienia kompilacji).

    2. Wybierz Android i kliknij Switch Platform (Zmień platformę).

    3. W menu Window > Google Play Games (Okno > Gry Google Play) powinna się pojawić nowa pozycja. Jeśli jej nie ma, odśwież zasoby, klikając Assets > Refresh (Zasoby > Odśwież), a potem ponownie ustaw platformę kompilacji.

  4. W edytorze Unity kliknij File > Build Settings > Player Settings > Other Settings (Plik > Ustawienia kompilacji > Ustawienia odtwarzacza > Inne ustawienia).

  5. W polu Target API level (Docelowy poziom interfejsu API) wybierz wersję.

  6. W polu Scripting backend (Backend skryptów) wpisz IL2CPP.

  7. W polu Target architectures (Docelowe architektury) wybierz wartość.

  8. Zanotuj nazwę pakietu package_name.Te informacje mogą się przydać później.

    Ustawienia odtwarzacza w projekcie Unity
    Ustawienia odtwarzacza w projekcie Unity.
  9. Skopiuj zasoby Androida z Konsoli Play.

  10. Dodaj zasoby Androida do projektu Unity.

Ścieżki migracji

Prawidłowa ścieżka migracji w przypadku Twojej gry zależy od tego, jak implementuje ona usługi gier Play w wersji 1 i jak obsługuje tożsamość gracza. Aby zapewnić płynne przejście i zapobiec utracie danych gracza, określ scenariusz, który najlepiej pasuje do Twojej obecnej konfiguracji, i wykonaj odpowiednie czynności.

Opcja 1. W przypadku gier, w których konto w grze jest powiązane z identyfikatorem gracza w usługach gier Play

Ten scenariusz dotyczy gier, które używają identyfikatora Player ID usług gier Play jako jedynego identyfikatora konta w grze i nie prosiły wcześniej o OpenID ani go nie przechowywały. Głównym wyzwaniem jest powiązanie istniejącego konta w grze z identyfikatorem podstawowym (OpenID) bez utraty połączenia z postępami gracza.

Proces migracji obejmuje te kroki:

  1. Gdy gra się uruchamia, pakiet SDK usług gier Play w wersji 2 automatycznie i bez interakcji z użytkownikiem uwierzytelnia platformę.
  2. Gra wyświetla ekran logowania. Na tym ekranie musi się znajdować przycisk Zaloguj się przez Google (SiWG) , który zastępuje przycisk Google Play. Aby zintegrować:

    1. Pobierz CredManBridge.java do swojego folderu. Ta klasa Java działa jako pomost między Unity a biblioteką 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. Integracja Menedżera danych logowania:

      • Użyj GetGoogleIdOption z setFilterByAuthorizedAccounts(true) w przypadku logowania automatycznego, aby logować tylko użytkowników, którzy wcześniej autoryzowali aplikację.
      • Użyj setFilterByAuthorizedAccounts(false) w przypadku logowania interaktywnego, aby umożliwić użytkownikom wybranie konta lub dodanie nowego.
    3. Prośba o zakres:

      • Po uzyskaniu podstawowych danych logowania Google tworzy AuthorizationRequest prosząc o konkretny starszy zakres: https://www.googleapis.com/auth/games_lite.
      • Ten zakres jest niezbędny, ponieważ przyznaje serwerowi uprawnienia do wyszukiwania starszego identyfikatora PlayerID użytkownika.
    4. Obsługa wyników:

      • Jeśli użytkownik przyzna uprawnienia (lub przyznał je wcześniej), pomost zwróci do Unity ServerAuthCode.
      • Jeśli użytkownik nie przyznał uprawnień (scenariusz nowego użytkownika), interfejs API zwróci PendingIntent. W tym przykładzie intencja jest odrzucana, a użytkownik jest traktowany jako nowy użytkownik, aby uprościć proces.
  3. Aby obsługiwać Menedżera danych logowania i usługi Google Identity, dodaj te zależności do konfiguracji 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'
    }
    • Menedżer danych logowania: obsługuje podstawową koordynację tożsamości i interfejs użytkownika do wybierania konta.
    • Biblioteka GoogleID: udostępnia GetGoogleIdOption do pobierania tokenów OpenID Connect.
    • Uwierzytelnianie w Usługach Google Play: wymagane do zachowania zgodności i wysyłania prośby o zakres GAMES_LITE w celu pobrania starszego identyfikatora Player ID.
  4. Gdy gracz kliknie przycisk SiWG i wybierze konto Google, gra musi pobrać 2 różne identyfikatory:

    • OpenID, czyli identyfikator podstawowy do powiązania konta w grze.
    • Usługi gier Play Player ID, pobrane za pomocą zakresu GAMES_LITE, aby wyszukać identyfikator IGA gracza w systemie backendu i przeprowadzić powiązanie.
  5. Przy kolejnych uruchomieniach gry gracze mogą uzyskiwać dostęp do swojego konta w grze za pomocą procesu SiWG bez konieczności używania identyfikatora Player ID jako identyfikatora podstawowego.

Krok 4 możesz wykonać za pomocą implementacji po stronie klienta gry.

  1. Deweloper wywołuje interfejs Android Credential Manager API, aby zalogować użytkownika za pomocą konta Google.
  2. Gdy użytkownik zakończy proces SiWG i wybierze konto Google, deweloper otrzyma obiekt wyniku zawierający token identyfikatora i adres e-mail.
  3. Deweloper tworzy obiekt konta na podstawie adresu e-mail.
  4. Deweloper wywołuje interfejs Authorization API z zakresem GAMES_LITE i kontem.
  5. Jeśli konto ma już przyznany zakres GAMES_LITE, interfejs Authorization API zwraca token bezpośrednio w obiekcie odpowiedzi.
    1. Użyj tokena odpowiedzi, aby wywołać serwery usług gier Play i pobrać identyfikator Player ID usług gier Play.
    2. Deweloper sprawdza, czy identyfikator Player ID usług gier Play został powiązany z kontem w grze.
      1. Deweloper wie, że jest to powracający użytkownik usług gier Play w wersji 1.
    3. Deweloper może powiązać nowy identyfikator Gaia z poprzednim kontem usług gier Play w wersji 1.
  6. Jeśli konto nie ma przyznanego zakresu GAMES_LITE, interfejs Authorization API zwraca PendingIntent.
    1. Deweloper wie, że użytkownik nie ma konta w usługach gier Play w wersji 1.
    2. Deweloper może bezpiecznie odrzucić PendingIntent bez wyświetlania interfejsu.

Opcja 2. W przypadku gier, które już wiążą konto w grze z OpenID

Deweloperzy w tej grupie mają najprostszą ścieżkę migracji. Jeśli konto w grze jest już powiązane głównie z OpenID, musisz tylko przeprowadzić standardową techniczną migrację pakietu SDK z wersji 1 do wersji 2 zgodnie z instrukcjami.

Aktualizowanie kodu logowania automatycznego

Zastąp klasę inicjującą PlayGamesClientConfiguration klasą PlayGamesPlatform.Instance.Authenticate(). Inicjowanie i aktywowanie PlayGamesPlatform nie jest wymagane. Wywołanie PlayGamesPlatform.Instance.Authenticate() pobiera wynik logowania automatycznego. Więcej informacji o zalecanym procesie uwierzytelniania w przypadku integracji z usługami gier Play w wersji 2 znajdziesz w artykule Wskazówki dotyczące optymalnego procesu uwierzytelniania.

C#

W edytorze Unity znajdź pliki z klasą 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();
}

Zaktualizuj je do tej postaci:

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

Wybieranie platformy społecznościowej

Aby wybrać platformę społecznościową, przeczytaj artykuł Wybieranie platformy społecznościowej.

Pobieranie kodów uwierzytelniania serwera

Aby uzyskać kody dostępu po stronie serwera, przeczytaj artykuł Pobieranie kodów uwierzytelniania serwera.

Usuwanie kodu wylogowania

Usuń kod wylogowania. Usługi gier Play nie wymagają już przycisku wylogowania w grze.

Usuń kod pokazany w tym przykładzie:

C#

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

Testowanie gry

Przetestuj grę, aby sprawdzić, czy działa zgodnie z założeniami. Testy, które wykonasz, zależą od funkcji gry.

Oto lista typowych testów, które należy przeprowadzić.

  1. Pomyślne logowanie.

    1. Logowanie automatyczne działa. Po uruchomieniu gry użytkownik powinien być zalogowany w usługach gier Play.

    2. Wyświetla się wyskakujące okienko powitania.

      Przykładowe wyskakujące okienko powitalne.
      Przykładowe wyskakujące okienko powitania (kliknij, aby powiększyć).

    3. Wyświetlają się komunikaty o pomyślnym logowaniu. Uruchom w terminalu to polecenie:

      adb logcat | grep com.google.android.

      W tym przykładzie pokazany jest komunikat logu o pomyślnym logowaniu:

      [$PlaylogGamesSignInAction$SignInPerformerSource@e1cdecc
      number=1 name=GAMES_SERVICE_BROKER>], returning true for shouldShowWelcomePopup.
      [CONTEXT service_id=1 ]
  2. Zapewnij spójność komponentów interfejsu użytkownika.

    1. Wyskakujące okienka, tabele wyników i osiągnięcia wyświetlają się prawidłowo i spójnie w różnych rozmiarach i orientacjach ekranu w interfejsie usług gier Play.

    2. Opcja wylogowania nie jest widoczna w interfejsie usług gier Play.

    3. Upewnij się, że możesz prawidłowo pobrać identyfikator PlayerID, a jeśli to możliwe, funkcje po stronie serwera działają zgodnie z oczekiwaniami.

    4. Jeśli gra korzysta z uwierzytelniania po stronie serwera, dokładnie przetestuj proces requestServerSideAccess. Upewnij się, że serwer otrzymuje kod autoryzacji i może go wymienić na token dostępu. Przetestuj scenariusze powodzenia i niepowodzenia w przypadku błędów sieci i nieprawidłowego identyfikatora client ID.

Jeśli Twoja gra korzystała z którejś z tych funkcji, przetestuj je, aby sprawdzić, czy działają tak samo jak przed migracją:

  • Tabele wyników: przesyłaj wyniki i wyświetlaj tabele wyników. Sprawdź, czy ranking jest prawidłowy oraz czy nazwy graczy i wyniki są wyświetlane poprawnie.
  • Osiągnięcia: odblokowuj osiągnięcia i sprawdzaj, czy są prawidłowo rejestrowane i wyświetlane w interfejsie usług gier Play.
  • Zapisane gry: jeśli gra korzysta z zapisanych gier, upewnij się, że zapisywanie i wczytywanie postępów w grze działa bez zarzutu. Jest to szczególnie ważne w przypadku testowania na wielu urządzeniach i po aktualizacjach aplikacji.

Zadania po migracji

Po przeprowadzeniu migracji do pakietu SDK dla gier w wersji 2 wykonaj te czynności.

  1. Używaj podpisywania aplikacji przez Google Play.

  2. Utwórz plik AAB.

  3. Utwórz wewnętrzną wersję testową.

  4. Sprawdź dane logowania do podpisywania aplikacji.