גישה מצד השרת אל 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. ממלאים את הטופס בדף ולוחצים על 'יצירה'. הקפידו להגדיר את סוג האפליקציה ל-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 ואז מאמתים אותו במשחק.

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

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

קטע הקוד הבא מראה איך מטמיעים את הקוד בצד השרת בשפת התכנות 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 מסוים.