В этом документе описывается, как перенести существующие игры с SDK games v1 на SDK games v2 . Плагин Play Games для Unity, версий 10 и более ранних, использует SDK games v1.
Прежде чем начать
- Убедитесь, что вы уже настроили Play Console и установили редактор Unity.
Скачайте плагин Google Play Games для Unity.
Чтобы воспользоваться последними функциями сервисов Play Games, загрузите и установите последнюю версию плагина. Скачать его можно из репозитория GitHub .
Удалите старый плагин
В редакторе Unity удалите следующие папки или файлы.
Assets/GooglePlayGames Assets/GeneratedLocalRepo/GooglePlayGames Assets/Plugins/Android/GooglePlayGamesManifest.androidlib Assets/Plugins/Android

Импортируйте новый плагин в свой проект Unity.
Чтобы импортировать плагин в ваш проект Unity, выполните следующие шаги:
- Откройте свой игровой проект.
- В редакторе Unity нажмите Assets > Import Package > Custom Package, чтобы импортировать загруженный файл
unitypackageв ресурсы вашего проекта. Убедитесь, что в качестве текущей платформы сборки выбрана Android .
В главном меню нажмите Файл > Настройки сборки .
Выберите Android и нажмите «Переключить платформу» .
В меню «Окно» > «Google Play Games» должен появиться новый пункт. Если его нет, обновите ресурсы, нажав «Ресурсы» > «Обновить» , а затем попробуйте снова установить платформу сборки.
В редакторе Unity нажмите File > Build Settings > Player Settings > Other Settings .
В поле «Уровень целевого API» выберите версию.
В поле «Бэкенд скриптов» введите
IL2CPP.В поле «Целевые архитектуры» выберите значение.
Обратите внимание на имя пакета package_name . Эта информация пригодится вам позже.

Настройки проигрывателя в вашем проекте Unity.
Миграционные пути
Правильный путь миграции для вашей игры зависит от того, как она реализует Play Games Services v1 и обрабатывает идентификацию игроков. Чтобы обеспечить плавный переход и предотвратить потерю данных игроков, определите сценарий, который лучше всего соответствует вашей существующей конфигурации, и выполните соответствующие шаги.
Вариант 1: Для игр, где IGA привязан к идентификатору игрока Play Games Services.
Этот сценарий применим к играм, которые использовали Player ID Play Games Services в качестве единственного идентификатора внутриигровой учетной записи (IGA) игрока и ранее не запрашивали и не сохраняли OpenID . Главная задача — связать существующую IGA с основным идентификатором ( OpenID ), не теряя связи с прогрессом игрока.
Процесс миграции включает следующие этапы:
- При запуске игры SDK Play Games Services v2 автоматически и незаметно выполняет аутентификацию платформы.
Игра отображает экран входа в систему. На этом экране должна быть кнопка «Войти через Google » (SiWG), заменяющая кнопку Google Play . Для интеграции:
Загрузите файл CredManBridge.java в свою папку. Этот Java-класс служит мостом между Unity и библиотекой
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"); } }); }
// --- РЕЖИМ 2: ИНТЕРАКТИВНЫЙ ВХОД (Вызывается при нажатии кнопки) --- // Принудительно отображает окно выбора учетной записи / «Добавить учетную запись». public static void signInInteractive(Context context, String webClientId) { CredentialManager credentialManager = CredentialManager.create(context); CancellationSignal cancellationSignal = new CancellationSignal(); Executor executor = Executors.newSingleThreadExecutor();
Log.d("CredMan", "Начало интерактивного входа в систему...");
GetGoogleIdOption interactiveOption = new GetGoogleIdOption.Builder() .setFilterByAuthorizedAccounts(false) // Показать ВСЕ учетные записи (и "Добавить учетную запись") .setServerClientId(webClientId) .setAutoSelectEnabled(false) // Принудительно отобразить пользовательский интерфейс .build();
GetCredentialRequest interactiveRequest = new GetCredentialRequest.Builder() .addCredentialOption(interactiveOption) .build();
credentialManager.getCredentialAsync( context, interactiveRequest, cancellationSignal, executor, new androidx.credentials.CredentialManagerCallback
() { @Override public void onResult(GetCredentialResponse result) { Log.d("CredMan", "Интерактивный вход выполнен успешно!"); handleSignInResult(context, result, webClientId); } @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()); } } }
Интеграция с менеджером учетных данных:
- Используйте
GetGoogleIdOptionсsetFilterByAuthorizedAccounts(true)для автоматического входа в систему, чтобы авторизовались только пользователи, ранее авторизовавшие приложение. - Используйте
setFilterByAuthorizedAccounts(false)для интерактивного входа в систему, чтобы позволить пользователям выбрать учетную запись или добавить новую.
- Используйте
Запрос на определение объема работ:
- После получения базовых учетных данных Google создается запрос
AuthorizationRequest, запрашивающий доступ к конкретной устаревшей области действия: https://www.googleapis.com/auth/games_lite . - Эта область действия имеет решающее значение, поскольку она предоставляет серверу разрешение на поиск устаревшего идентификатора игрока (PlayerID).
- После получения базовых учетных данных Google создается запрос
Обработка результатов:
- Если пользователь предоставляет разрешение (или предоставил его ранее), мост возвращает объект
ServerAuthCodeв Unity. - Если пользователь не предоставил разрешение (сценарий «Новый пользователь»), API возвращает
PendingIntent. В этом примере намерение отбрасывается, и пользователь рассматривается как новый пользователь для упрощения процесса.
- Если пользователь предоставляет разрешение (или предоставил его ранее), мост возвращает объект
Для поддержки служб Credential Manager и Google Identity убедитесь, что следующие зависимости добавлены в ваш файл конфигурации 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' }
- Менеджер учетных данных: отвечает за основную организацию управления идентификацией и пользовательский интерфейс для выбора учетных записей.
- Библиотека GoogleID: В частности, предоставляет
GetGoogleIdOptionдля получения токеновOpenIDConnect. - Аутентификация Play Services: необходима для обеспечения совместимости и запроса области действия
GAMES_LITEдля полученияPlayer IDиз старых версий.
Когда игрок нажимает кнопку SiWG и выбирает учетную запись Google, игра должна получить два различных идентификатора:
-
OpenID— основной идентификатор для привязки IGA. -
Player IDPlay Games Services, полученный с помощью области видимостиGAMES_LITE, используется для поиска IGA игрока в вашей серверной системе и выполнения привязки.
-
При последующих запусках игр игроки смогут получить доступ к своему IGA через поток SiWG, без необходимости использования
Player IDв качестве основного идентификатора.
Шаг 4 можно выполнить, используя клиентскую реализацию игры.
- Разработчик вызывает API Android Credential Manager для входа пользователя в систему с помощью учетной записи Google.
- После того, как пользователь завершит работу с SiwG и выберет учетную запись Google, разработчик получит объект результата, содержащий токен идентификатора и адрес электронной почты.
- Разработчик создает объект Account на основе адреса электронной почты.
- Разработчик вызывает API авторизации с областью действия
GAMES_LITEи учетной записью. - Если для учетной записи уже имеется разрешение в рамках области действия
GAMES_LITE, API авторизации возвращает токен непосредственно в объекте ответа.- Используйте токен ответа для обращения к серверам Play Games Services и получения
Player IDPlay Games Services. - Разработчик проверяет, был ли
Player IDPlay Games Services связан с внутриигровой учетной записью.- Разработчик знает, что это вернувшийся пользователь из Play Games Services v1.
- Разработчик может связать новый идентификатор gaia с предыдущей учетной записью Play Games Services v1.
- Используйте токен ответа для обращения к серверам Play Games Services и получения
- Или, если у учетной записи нет предварительно предоставленных прав доступа в области действия
GAMES_LITE, API авторизации возвращает объект PendingIntent.- Разработчик знает, что у пользователя нет существующей учетной записи в Play Games Services v1.
- Разработчик может спокойно отбросить PendingIntent, не отображая при этом никакой пользовательский интерфейс.
Вариант 2: Для игр, уже использующих привязку IGA к OpenID.
Разработчикам из этой группы предлагается наиболее простой путь миграции. Если внутриигровой аккаунт вашей игры уже в основном привязан к OpenID, вам нужно выполнить только стандартную техническую миграцию SDK с версии 1 на версию 2, как описано в шагах.
Обновить код автоматического входа
Замените класс инициализации PlayGamesClientConfiguration на класс PlayGamesPlatform.Instance.Authenticate() . Инициализация и активация PlayGamesPlatform не требуются. Вызов PlayGamesPlatform.Instance.Authenticate() получает результат автоматического входа в систему. Для получения дополнительной информации о рекомендуемом процессе аутентификации при интеграции с Play Games Services v2 см. Руководство по пользовательскому опыту для идеального процесса аутентификации .
C#
В редакторе Unity найдите файлы с классом 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();
}
И обновите его следующим образом:
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).
}
}
Выберите социальную платформу
Чтобы выбрать социальную платформу, см. раздел «Выбор социальной платформы» .
Получение кодов аутентификации сервера
Чтобы получить коды доступа на стороне сервера, см. раздел «Получение кодов аутентификации сервера» .
Удалить код выхода
Удалите код для выхода из системы. Сервисы Play Games больше не требуют кнопки выхода из игры.
Удалите код, показанный в следующем примере:
C#
// sign out
PlayGamesPlatform.Instance.SignOut();
Протестируйте свою игру
Убедитесь, что ваша игра работает так, как задумано, протестировав её. Тесты, которые вы будете проводить, зависят от особенностей вашей игры.
Ниже приведён список распространённых тестов, которые можно запустить.
Вход в систему пройден успешно .
Автоматический вход в систему работает. Пользователь должен быть авторизован в Play Games Services при запуске игры.
Отображается приветственное всплывающее окно.

Пример всплывающего окна приветствия (нажмите для увеличения). Отображаются сообщения об успешном завершении операции. Выполните следующую команду в терминале:
adb logcat | grep com.google.android.
В следующем примере показано сообщение об успешном завершении операции:
[
$PlaylogGamesSignInAction$SignInPerformerSource@e1cdecc number=1 name=GAMES_SERVICE_BROKER>], returning true for shouldShowWelcomePopup. [CONTEXT service_id=1 ]
Обеспечьте согласованность компонентов пользовательского интерфейса .
Всплывающие окна, таблицы лидеров и достижения корректно и стабильно отображаются на экранах различных размеров и ориентаций в пользовательском интерфейсе Play Games Services.
Функция выхода из системы не отображается в пользовательском интерфейсе сервисов Play Games.
Убедитесь, что вы можете успешно получить идентификатор игрока, и, если применимо, серверные функции работают должным образом.
Если в игре используется аутентификация на стороне сервера, тщательно протестируйте поток
requestServerSideAccess. Убедитесь, что сервер получает код аутентификации и может обменять его на токен доступа. Протестируйте как успешные, так и неудачные сценарии на наличие сетевых ошибок и сценариев с недействительнымclient ID.
Если в вашей игре использовались какие-либо из следующих функций, протестируйте их, чтобы убедиться, что они работают так же, как и до миграции:
- Таблицы лидеров : Отправляйте результаты и просматривайте таблицы лидеров. Проверяйте правильность рейтинга и отображения имен игроков и результатов.
- Достижения : Разблокируйте достижения и убедитесь, что они корректно записаны и отображаются в пользовательском интерфейсе Play Games.
- Сохраненные игры : Если игра использует сохраненные игры, убедитесь, что сохранение и загрузка игрового прогресса работают безупречно. Это особенно важно проверить на разных устройствах и после обновления приложения.
Задачи после миграции
После перехода на SDK для игр версии 2 выполните следующие шаги.