גישה מצד השרת אל Google Play Games Services

מומלץ לאמת את השחקנים ולהעביר את הזהות שלהם לשרת הקצה העורפי באופן מאובטח. כך המשחק יכול לאחזר באופן מאובטח את הזהות של השחקן ונתונים אחרים, בלי להיות חשוף לזיופים פוטנציאליים במהלך המעבר במכשיר.

בתרחיש הזה, אחרי שהשחקן נכנס לחשבון, אפשר לבקש קוד מיוחד לשימוש חד-פעמי (שנקרא קוד אימות השרת) מ-Play Games Services v2 SDK, והלקוח מעביר את הקוד לשרת. לאחר מכן, בשרת, מחליפים את קוד האימות של השרת באסימון OAuth 2.0 שהשרת יכול להשתמש בו כדי לבצע קריאות ל-Google Play Games Services API.

לקבלת הנחיות נוספות על הוספת כניסה למשחקים, אפשר לעיין במאמר כניסה למשחקים ל-Android.

כדי לגשת לנתונים במצב אופליין, צריך לבצע את השלבים הבאים:

  1. ב-Google Play Console: יוצרים פרטי כניסה לשרת המשחק. סוג לקוח ה-OAuth של פרטי הכניסה יהיה 'אינטרנט'.
  2. באפליקציה ל-Android: כחלק מהכניסה, מבקשים קוד אימות לשרת עבור פרטי הכניסה של השרת ומעבירים אותו לשרת.
  3. בשרת המשחק: מחליפים את קוד האימות של השרת באסימון גישה של OAuth באמצעות שירותי האימות של Google, ולאחר מכן משתמשים בו כדי לבצע קריאה לממשקי ה-API ל-REST של Play Games Services.

לפני שמתחילים

קודם כול צריך להוסיף את המשחק ל-Google Play Console, כפי שמתואר במאמר הגדרת Google Play Games Services, ולשלב את הכניסה באמצעות Play Games Services במשחק.

יצירת אפליקציית אינטרנט בצד השרת

שירות המשחקים של Google Play Services לא מספק תמיכה לקצה העורפי של משחקים באינטרנט. עם זאת, הוא מספק תמיכה בשרתים לקצה העורפי של השרת של המשחק ל-Android.

כדי להשתמש בממשקי ה-API ל-REST של שירותי Google Play Games באפליקציה בצד השרת, צריך לפעול לפי השלבים הבאים:

  1. ב-Google Play Console, בוחרים משחק.
  2. עוברים אל Play Games Services > הגדרה וניהול > הגדרה.
  3. בוחרים באפשרות Add credential (הוספת פרטי כניסה) כדי לעבור אל Add credential page (הוספת דף פרטי כניסה). בוחרים באפשרות שרת משחקים בתור סוג פרטי הכניסה וממשיכים לקטע הרשאה.
    1. אם לשרת המשחקים כבר יש מזהה לקוח OAuth, בוחרים אותו בתפריט הנפתח. אחרי שמירת השינויים, עוברים אל הקטע הבא.
    2. אם אין לכם מזהה לקוח OAuth קיים לשרת המשחק, תוכלו ליצור אחד.
      1. לוחצים על Create OAuth client ופועלים לפי ההוראות בקישור Create OAuth Client ID.
      2. תועברו לדף Create OAuth Client ID ב-Google Cloud Platform של הפרויקט המשויך למשחק.
      3. ממלאים את הטופס בדף ולוחצים על 'יצירה'. חשוב להגדיר את Application type בתור Web application.
      4. חוזרים לקטע Authorization בדף Add credential, בוחרים את לקוח ה-OAuth החדש שנוצר ושומרים את השינויים.

קבלת קוד האימות של השרת

כדי לאחזר קוד אימות שרת שאפשר להשתמש בו במשחק לאסימוני גישה בשרת הקצה העורפי:

  1. קוראים ל-requestServerSideAccess מהלקוח.

    1. חשוב לוודא שאתם משתמשים במזהה הלקוח ב-OAuth שרשום לשרת המשחק ולא במזהה הלקוח ב-OAuth של אפליקציית Android.
    2. (אופציונלי) אם שרת המשחקים שלכם דורש גישה אופליין (גישה לטווח ארוך באמצעות אסימון רענון) ל-Play Games Services, תוכלו להגדיר את הפרמטר forceRefreshToken לערך true.
    GamesSignInClient gamesSignInClient = PlayGames.getGamesSignInClient(this);
    gamesSignInClient
      .requestServerSideAccess(OAUTH_2_WEB_CLIENT_ID, /* forceRefreshToken= */ false)
      .addOnCompleteListener( task -> {
        if (task.isSuccessful()) {
          String serverAuthToken = task.getResult();
          // Send authentication code to the backend game server to be
          // exchanged for an access token and used to verify the player
          // via the Play Games Services REST APIs.
        } else {
          // Failed to retrieve authentication code.
        }
    });
    
  2. שולחים את אסימון קוד האימות של OAuth לשרת הקצה העורפי כדי שניתן יהיה להמיר אותו, מאשרים את מזהה השחקן באמצעות ממשקי ה-API ל-REST של Play Games Services ואז מאמתים אותו במשחק.

שליחת קוד האימות של השרת

שולחים את קוד האימות של השרת לשרת הקצה העורפי כדי להמיר אותו לאסימוני גישה ואסימוני רענון. משתמשים באסימון הגישה כדי לקרוא ל-API של Play Games Services בשם השחקן, ואפשר גם לשמור את אסימון הרענון כדי לקבל אסימון גישה חדש כשפג התוקף של אסימון הגישה.

קטע הקוד הבא מראה איך אפשר ליישם את הקוד בצד השרת בשפת התכנות Java כדי להחליף את קוד האימות של השרת באסימוני גישה. הוא משתמש באפליקציית הדוגמה clientserverskeleton.

/**
 * Exchanges the authcode for an access token credential.  The credential
 * is the associated with the given player.
 *
 * @param authCode - the non-null authcode passed from the client.
 * @param player   - the player object which the given authcode is
 *                 associated with.
 * @return the HTTP response code indicating the outcome of the exchange.
 */
private int exchangeAuthCode(String authCode, Player player) {
try {

    // The client_secret.json file is downloaded from the Google API
    // console.  This is used to identify your web application.  The
    // contents of this file shouldn't be shared.
    //
    File secretFile = new File("client_secret.json");

    // If we don't have the file, we can't access any APIs, so return
    // an error.
    if (!secretFile.exists()) {
        log("Secret file : " + secretFile
                .getAbsolutePath() + "  does not exist!");
        return HttpServletResponse.SC_FORBIDDEN;
    }

    GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(
            JacksonFactory.getDefaultInstance(), new
            FileReader(secretFile));

    // Extract the application id of the game from the client id.
    String applicationId = extractApplicationId(clientSecrets
            .getDetails().getClientId());

    GoogleTokenResponse tokenResponse =
            new GoogleAuthorizationCodeTokenRequest(
            HTTPTransport,
            JacksonFactory.getDefaultInstance(),
            "https://oauth2.googleapis.com/token",
            clientSecrets.getDetails().getClientId(),
            clientSecrets.getDetails().getClientSecret(),
            authCode,
            "")
            .execute();

    log("hasRefresh == " + (tokenResponse.getRefreshToken() != null));
    log("Exchanging authCode: " + authCode + " for token");
    Credential credential = new Credential
            .Builder(BearerToken.authorizationHeaderAccessMethod())
            .setJsonFactory(JacksonFactory.getDefaultInstance())
            .setTransport(HTTPTransport)
            .setTokenServerEncodedUrl("https://www.googleapis.com/oauth2/v4/token")
            .setClientAuthentication(new HttpExecuteInterceptor() {
                @Override
                public void intercept(HttpRequest request)
                        throws IOException {
                        }
            })
            .build()
            .setFromTokenResponse(tokenResponse);

    player.setCredential(credential);

    // Now that we have a credential, we can access the Games API.
    PlayGamesAPI api = new PlayGamesAPI(player, applicationId,
            HTTPTransport, JacksonFactory.getDefaultInstance());

    // Call the verify method, which checks that the access token has
    // access to the Games API, and that the Player ID used by the
    // client matches the playerId associated with the accessToken.
    boolean ok = api.verifyPlayer();

    // Call a Games API on the server.
    if (ok) {
        ok = api.updatePlayerInfo();
        if (ok) {
            // persist the player.
            savePlayer(api.getPlayer());
        }
    }

    return ok ? HttpServletResponse.SC_OK :
            HttpServletResponse.SC_INTERNAL_SERVER_ERROR;

  } catch (IOException e) {
    e.printStackTrace();
  }
  return HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
}

קריאה לממשקי API ל-REST מהשרת

תיאור מלא של קריאות ה-API הזמינות זמין במאמר ממשקי API ל-REST לשירותי Google Play Games.

דוגמאות לקריאות ל-API ל-REST שעשויות להועיל לכם:

שחקן

רוצים לקבל את המזהה ואת נתוני הפרופיל של השחקן שנכנס לחשבון? קוראים ל-Players.get עם 'me' בתור המזהה.

חברים

פרטים נוספים זמינים במדריך בנושא חברים.

  • כדי לאחזר את רשימת החברים של השחקן, צריך להפעיל את Players.list עם friends_all כ-collection.

  • כדי לבדוק אם יש לכם גישה לרשימת חברים, צריך להפעיל את Players.get עם הערך me כ-playerID, ולעיין בשדה profileSettings.friendsListVisibility בתגובה.

הישגים

פרטים נוספים זמינים במדריך בנושא הישגים.

  • כדי לקבל רשימה של ההישגים הנוכחיים, צריך להפעיל את AchievementDefinitions.list.

  • אפשר לשלב את הפונקציה הזו עם קריאה לפונקציה Achievements.list כדי לבדוק אילו הישגים השחקן פתח.

  • כדי לפתוח הישג של שחקן, צריך להפעיל את Achievements.unlock.

  • קוראים ל-Achievements.increment כדי לדווח על ההתקדמות בהשגת הישג ולבדוק אם השחקן פתח אותו.

  • אם אתם מנסים לנפות באגים במשחק שעדיין לא הגיע לסביבת הייצור, תוכלו להפעיל את Achievements.reset או את Achievements.resetAll מ-Management APIs כדי לאפס את ההישגים למצב המקורי שלהם.

לוחות לידרבורד

פרטים נוספים זמינים במדריך בנושא לוחות מנהיגות.

  • רוצים לקבל רשימה של כל לוחות התוצאות במשחק? מריצים את הפונקציה Leaderboards.list.

  • אם שחקן סיים משחק, אפשר לשלוח את התוצאה שלו אל Scores.submit ולבדוק אם זו תוצאה גבוהה חדשה.

  • כדי להציג לוח מנהיגים, מקבלים את הנתונים מ-Scores.list ומציגים אותם למשתמש.

  • אפשר להשתמש ב-Scores.listWindow כדי למצוא מבחר של ציונים שקרובים לציון הגבוה של המשתמש.

  • כדי לקבל מידע נוסף על הציון של השחקן בלוח מודעות מסוים (לדוגמה, אם השחקן נמצא ב-12% העליונים מבין כל השחקנים), צריך להפעיל את Scores.get.

  • אם אתם מבצעים ניפוי באגים במשחק, תוכלו להפעיל את Scores.reset מ-Management APIs כדי לאפס את כל הנקודות של השחקן הזה מ-leaderboard מסוים.