במאמר הזה מוסבר איך להעביר משחקים קיימים מ-games v1 SDK ל-games v2 SDK. הפלאגין Play Games ל-Unity, בגרסאות 10 ומטה, משתמש ב-SDK בגרסה Games v1.
לפני שמתחילים
- מוודאים שכבר הגדרתם את Play Console והתקנתם את Unity Editor.
הורדה של הפלאגין של Google Play Games ל-Unity
כדי ליהנות מהתכונות החדשות ביותר ב-Play Games Services, צריך להוריד ולהתקין את הגרסה האחרונה של הפלאגין. אפשר להוריד אותו ממאגר GitHub.
הסרת הפלאגין הישן
בעורך Unity, מסירים את התיקיות או הקבצים הבאים.
Assets/GooglePlayGames Assets/GeneratedLocalRepo/GooglePlayGames Assets/Plugins/Android/GooglePlayGamesManifest.androidlib Assets/Plugins/Android
ייבוא הפלאגין החדש לפרויקט Unity
כדי לייבא את הפלאגין לפרויקט Unity, פועלים לפי השלבים הבאים:
- פותחים את פרויקט המשחק.
- ב-Unity Editor, לוחצים על נכסים > ייבוא חבילה > חבילה מותאמת אישית כדי לייבא את הקובץ
unitypackageשהורד לנכסים של הפרויקט. מוודאים שפלטפורמת ה-build הנוכחית מוגדרת ל-Android.
בתפריט הראשי, לוחצים על קובץ > הגדרות Build.
בוחרים באפשרות Android ולוחצים על החלפת פלטפורמה.
פריט תפריט חדש אמור להופיע בקטע חלון > Google Play Games. אם לא, מרעננים את הנכסים. לוחצים על נכסים > רענון, ואז מנסים להגדיר שוב את פלטפורמת הפיתוח.
ב-Unity Editor, לוחצים על קובץ > הגדרות ה-Build > הגדרות המשחק > הגדרות נוספות.
בתיבה רמת ה-API לטרגוט, בוחרים גרסה.
בתיבה כתיבת סקריפט לבק אנד, מזינים
IL2CPP.בתיבה ארכיטקטורות יעד, בוחרים ערך.
חשוב לשים לב לשם החבילה package_name. אפשר להשתמש במידע הזה בהמשך.
הגדרות המשחק בפרויקט Unity.
מסלולי מעבר
נתיב ההעברה הנכון למשחק שלכם תלוי באופן ההטמעה של Play Games Services v1 ושל הטיפול בזהות השחקן. כדי להבטיח מעבר חלק ולמנוע אובדן של נתוני שחקנים, צריך לזהות את התרחיש שהכי מתאים להגדרה הקיימת ולפעול לפי השלבים המתאימים.
אפשרות 1: למשחקים שבהם IGA מקושר למזהה השחקן ב-Play Games Services
התרחיש הזה רלוונטי למשחקים שהשתמשו בשירותי Play Games Player ID כמזהה היחיד של חשבון במשחק (IGA) של שחקן, ולא ביקשו או שמרו בעבר OpenID. האתגר המרכזי הוא לקשר את מזהה הגיימר הקיים למזהה ראשי (OpenID) בלי לאבד את הקשר להתקדמות של השחקן.
תהליך ההעברה כולל את השלבים הבאים:
- כשהמשחק מופעל, Play Games Services v2 SDK מאמת את הפלטפורמה באופן אוטומטי ובשקט.
מסך הכניסה של המשחק מוצג. במסך הזה צריך להופיע לחצן כניסה באמצעות חשבון 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"); } }); }
// --- 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()); } } }
שילוב של Credential Manager:
- אפשר להשתמש ב-
GetGoogleIdOptionעםsetFilterByAuthorizedAccounts(true)לכניסות שקטות כדי להיכנס רק למשתמשים שאישרו בעבר את האפליקציה. - משתמשים ב-
setFilterByAuthorizedAccounts(false)לכניסות אינטראקטיביות כדי לאפשר למשתמשים לבחור חשבון או להוסיף חשבון חדש.
- אפשר להשתמש ב-
בקשה להרחבת היקף:
- אחרי קבלת פרטי הכניסה הבסיסיים של Google, המערכת יוצרת בקשה
AuthorizationRequestעם היקף ההרשאות הספציפי מדור קודם: https://www.googleapis.com/auth/games_lite. - ההיקף הזה חשוב מאוד כי הוא מעניק לשרת הרשאה לחפש את מזהה השחקן הקודם של המשתמש.
- אחרי קבלת פרטי הכניסה הבסיסיים של Google, המערכת יוצרת בקשה
טיפול בתוצאות:
- אם המשתמש מעניק הרשאה (או שכבר העניק אותה), ה-Bridge מחזיר את
ServerAuthCodeל-Unity. - אם המשתמש לא העניק הרשאה (תרחיש של משתמש חדש), ממשק ה-API מחזיר
PendingIntent. בדוגמה הזו, הכוונה נפסלת והמשתמש נחשב למשתמש חדש כדי לפשט את התהליך.
- אם המשתמש מעניק הרשאה (או שכבר העניק אותה), ה-Bridge מחזיר את
כדי לתמוך ב-Credential Manager ובשירותי הזהויות של Google, מוודאים שהתלויות הבאות נוספו להגדרת
mainTemplate.gradlegradle.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' }
- Credential Manager: מטפל בתיאום הזהויות ובממשק המשתמש לבחירת החשבון.
- GoogleID Library: מספקת באופן ספציפי את
GetGoogleIdOptionלאחזור אסימוני ConnectOpenID. - אימות של Play Services: נדרש כדי לשמור על תאימות ולבקש את היקף ההרשאות
GAMES_LITEלאחזור שלPlayer IDמדור קודם.
כשהשחקן מקיש על לחצן הכניסה באמצעות חשבון Google ובוחר חשבון Google, המשחק צריך לאחזר שני מזהים שונים:
-
OpenID, המזהה הראשי לקישור ה-IGA. - Play Games Services
Player ID, שאוחזר באמצעות היקףGAMES_LITE, כדי לחפש את מזהה הגיימר (IGA) של השחקן במערכת העורפית שלכם ולבצע את הקישור.
-
בהפעלות הבאות של המשחק, השחקנים יכולים לגשת למזהה הגיימר שלהם באמצעות תהליך SiWG, בלי שהמשחקים יידרשו להשתמש ב-
Player IDכמזהה ראשי.
אפשר לבצע את שלב 4 באמצעות הטמעה בצד הלקוח של משחק.
- המפתח קורא ל-Android Credential Manager API כדי להכניס את המשתמש לחשבון Google.
- אחרי שהמשתמש משלים את תהליך הכניסה באמצעות Google ובוחר חשבון Google, המפתח מקבל אובייקט תוצאה שמכיל את טוקן הזהות ואת כתובת האימייל.
- המפתח בונה אובייקט Account מכתובת האימייל.
- המפתח קורא ל-Authorization API עם ההיקף
GAMES_LITEוהחשבון. - אם בחשבון יש מענק קיים בהיקף
GAMES_LITE, ה-Authorization API מחזיר טוקן ישירות באובייקט התגובה.- משתמשים באסימון התגובה כדי להתקשר לשרתים של Play Games Services ולאחזר את
Player IDשל Play Games Services. - המפתח מאמת אם שירותי המשחקים של Play
Player IDקושרו לחשבון במשחק.- המפתח יודע שמדובר במשתמש חוזר מגרסה 1 של Play Games Services.
- המפתח יכול לקשר את מזהה GAIA החדש לחשבון הקודם ב-Play Games Services v1.
- משתמשים באסימון התגובה כדי להתקשר לשרתים של Play Games Services ולאחזר את
- לחלופין, אם לחשבון אין מענק קיים בהיקף
GAMES_LITE, Authorization API מחזיר PendingIntent.- המפתח יודע שלמשתמש אין חשבון קיים בגרסה 1 של Play Games Services.
- המפתח יכול לבטל את PendingIntent בלי להציג ממשק משתמש.
אפשרות 2: למשחקים שכבר מקשרים את IGA ל-OpenID
למפתחים בקבוצה הזו יש את נתיב ההעברה הכי פשוט. אם החשבון במשחק כבר מקושר בעיקר ל-OpenID, צריך רק לבצע את ההעברה הטכנית הרגילה של ה-SDK מגרסה 1 לגרסה 2, כמו שמתואר בשלבים.
עדכון קוד הכניסה האוטומטית
מחליפים את מחלקת האתחול PlayGamesClientConfiguration במחלקה PlayGamesPlatform.Instance.Authenticate().
אין צורך בהפעלה ובאתחול של PlayGamesPlatform. התקשרות אל PlayGamesPlatform.Instance.Authenticate() מאחזרת את התוצאה של כניסה אוטומטית.
מידע נוסף על זרימת האימות המומלצת בשילוב עם Play Games Services v2 זמין במאמר הנחיות לחוויית משתמש בנושא זרימת אימות אופטימלית.
C#
ב-Unity Editor, מאתרים את הקבצים עם המחלקה 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 Services.
מסירים את הקוד שמוצג בדוגמה הבאה:
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 Services.
מוודאים שאפשר לאחזר את מזהה השחקן, ואם רלוונטי, שהיכולות בצד השרת פועלות כמצופה.
אם המשחק משתמש באימות בצד השרת, צריך לבדוק היטב את התהליך
requestServerSideAccess. מוודאים שהשרת מקבל את קוד ההרשאה ויכול להחליף אותו באסימון גישה. בודקים תרחישים של הצלחה ושל כישלון לשגיאות ברשת, תרחישים לא חוקיים שלclient ID.
אם המשחק שלכם השתמש באחת מהתכונות הבאות, כדאי לבדוק אותן כדי לוודא שהן פועלות כמו לפני ההעברה:
- טבלאות מובילים: שליחת ציונים וצפייה בטבלאות מובילים. בדיקה שהדירוג נכון ושהשמות והציונים של השחקנים מוצגים.
- הישגים: ביטול נעילה של הישגים ואימות שהם נרשמים ומוצגים בצורה נכונה בממשק המשתמש של Play Games.
- משחקים שמורים: אם המשחק משתמש במשחקים שמורים, חשוב לוודא שהשמירה והטעינה של ההתקדמות במשחק פועלות בצורה חלקה. חשוב במיוחד לבדוק את זה בכמה מכשירים ואחרי עדכוני אפליקציה.
משימות אחרי ההעברה
אחרי שמעבירים את האפליקציה ל-SDK בגרסה Games v2, מבצעים את השלבים הבאים.