הפעלת גישה מצד השרת ל-Google Play Games Services

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

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

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

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

כדי לקבל גישה אופליין:

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

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

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

יצירת אפליקציית אינטרנט משויכת בצד השרת עבור המשחק שלך

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

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

  1. ליצור אפליקציית אינטרנט משויכת למשחק בקטע אפליקציות מקושרות ב-Google Play Console. חשוב לשים לב שהשדה launch_url לא משמש לתהליך הזה ואפשר להשאיר אותו ריק.
  2. כדי לקבל את פרטי הכניסה של האפליקציה:
    1. מתוך המשחק ב-Google Play Console, לוחצים על פרטי המשחק.
    2. גוללים למטה לקטע API Console Console ולוחצים על הקישור לפרויקט API API.
    3. במסך APIs & Services > Credentials [ממשקי API ושירותים > פרטי כניסה] ב-Google API Console, מורידים את הקובץ client_secret.json עבור אפליקציית האינטרנט ושומרים אותו במיקום שאליו השרת יכול לגשת. מתעדים את מזהה הלקוח של פרטי הכניסה לשימוש מאוחר יותר.
  3. מפעילים מחדש את האפליקציה בצד השרת כדי שהיא תהיה מוכנה לקבל בקשות מאפליקציית הלקוח של המשחק.

ביצוע כניסה ללקוח

הכיתה GoogleSignInClient היא נקודת הכניסה הראשית לאחזור החשבון של הנגן שמחובר עכשיו לחשבון, ולכניסה לחשבון אם המשתמש לא עשה זאת בעבר באפליקציה במכשיר.

כדי ליצור לקוח כניסה:

  1. ניתן ליצור לקוח לכניסה באמצעות האובייקט GoogleSignInOptions. בGoogleSignInOptions.Builder כדי להגדיר את הכניסה לחשבון, צריך לציין את GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN.
  2. כמו כן, עליכם לציין שהמשחק שלכם דורש קוד אימות עבור שרת הקצה העורפי, על ידי קריאה לשיטה GoogleSignInOptions.Builder.requestServerAuthCode() עם מזהה הלקוח של השרת בתור הפרמטר. מאחזרים את קוד האימות בשלב מאוחר יותר עבור אסימוני גישה בשרת הקצה העורפי, כפי שמתואר בקטע קבלת קוד האימות של השרת.
  3. מפעילים את השיטה GoogleSignIn.getClient() ומעבירים את האפשרויות שהגדרתם בעבר. אם השיחה תצליח, ה-API לכניסה באמצעות Google יחזיר מופע של GoogleSignInClient.
  4. אחרי שתקבלו את המכונה של GoogleSignInClient, תוכלו להמשיך להיכנס לחשבון בשקלול מהonResume() של הפעילות, כפי שמתואר בביצוע כניסה שקטה.

לדוגמה:

private static final int RC_SIGN_IN = 9001;
private GoogleSignInClient mGoogleSignInClient;

private void startSignInForAuthCode() {

  // Client ID for your backend server.
  String webClientId = getString(R.string.webclient_id);

  GoogleSignInOptions signInOption = new
      GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN)
      .requestServerAuthCode(webClientId)
      .build();

  GoogleSignInClient signInClient = GoogleSignIn.getClient(this, signInOption);
  Intent intent = signInClient.getSignInIntent();
  startActivityForResult(intent, RC_SIGN_IN);
}

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

כדי לאחזר קוד אימות של שרת שניתן להשתמש בו באסימוני גישה בשרת הקצה העורפי, צריך לקרוא לשיטה getServerAuthCode() ב-GoogleSignInAccount מכיוון שהכניסה ל-Google מחזירה כניסה מוצלחת לשחקן.

לדוגמה:


// Auth code to send to backend server.
private String mServerAuthCode;

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  super.onActivityResult(requestCode, resultCode, data);
  if (requestCode == RC_SIGN_IN) {
    GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
    if (result.isSuccess()) {
      mServerAuthCode = result.getSignInAccount().getServerAuthCode();
    } else {
      String message = result.getStatus().getStatusMessage();
      if (message == null || message.isEmpty()) {
        message = getString(R.string.signin_other_error);
      }
      new AlertDialog.Builder(this).setMessage(message)
          .setNeutralButton(android.R.string.ok, null).show();
    }
  }
}

החלפת קוד האימות של השרת לאסימון הגישה בשרת

שולחים את קוד האימות של השרת לשרת הקצה העורפי כדי להמיר אותם לאסימוני גישה ורענון. משתמשים באסימון הגישה כדי לקרוא ל-Google 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 should not 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;
}

מידע נוסף על הגישה ל-Google APIs משרת עורפי בשם נגן מחובר תוכלו למצוא במאמר הפעלת גישה בצד השרת.

טיפול ביציאת הנגן

כדי להוציא את השחקנים מהמשחק, יש לקרוא למתודה signOut() בGoogleSignInClient. למידע על קטע קוד לדוגמה, קראו את המאמר איך מוציאים את הנגן מהחשבון.

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

תוכלו למצוא תיאור מלא של קריאות ל-API במאמר REST APIs לשירותי Google Play Games.

דוגמאות לקריאות מועילות ל-API ל-REST:

שחקן

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

חברים

ודאו שאתם קוראים את המדריך חברים, שמסביר ביתר פירוט על החברים.

  • רוצה לאחזר את רשימת החברים של השחקן? יש להתקשר אל Players.list בשם 'friends_all' בתור collection.
  • רוצה לבדוק אם יש לך גישה לרשימת החברים? מתקשרים אל Players.get עבור me, ומעיינים בשדה profileSettings.friendsListVisibility בתשובה.

הישגים

כדאי לעיין במדריך הישגים, שכולל הסבר מפורט על הישגים.

  • רוצה לקבל רשימה של הישגים נוכחיים? אפשר להתקשר אל AchievementDefinitions.list.
  • שלבו את המידע הזה עם קריאה ל-Acquisitionments.list כדי לבדוק אילו משחקים השיגו השחקנים.
  • האם השחקן זכה בהישג? אפשר להשתמש ב-הישגים.unlock כדי לבטל את הנעילה!
  • האם השחקן התקדם להישג חלקי? להשתמש ב-הישגים.inrement כדי לדווח על ההתקדמות (ולגלות אם השחקן ביטל את הנעילה).
  • האם הפעלתם ניפוי באגים במשחק שעדיין לא נמצא בסביבת הייצור? נסו להתקשר ל-Acquisitionments.reset או ל-Achievements.resetAll מממשקי ה-API לניהול, כדי לאפס את המצב המקורי שלהם.

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

כדאי לעיין במדריך Leaderboards, שמסביר בפירוט את לוחות הלידרבורד.

  • רוצה לקבל רשימה של כל לוחות התוצאות במשחק? מתקשרים אל Leaderboards.
  • האם השחקן סיים לשחק? אתם יכולים לשלוח את הציון שלהן לכתובת Scores.submit ולבדוק אם זהו ציון גבוה חדש.
  • רוצה להציג Leaderboard? אפשר לקבל את הנתונים מ-Scores.list ולהציג אותם למשתמש.
  • משתמשים ב-Scores.listWindow כדי לחפש מגוון של ציונים הקרובים לדירוג הגבוה של המשתמש.
  • כדי לקבל מידע נוסף על הניקוד של השחקן בלידרבורד מסוים (לדוגמה, אם השחקן נמצא ב-12% המובילים מתוך כל השחקנים), צריך להתקשר ל-Scores.get.
  • ניפוי באגים במשחק? נסו להפעיל את Scores.reset מתוך ממשקי ה-API לניהול כדי לאפס את כל הניקוד של אותו שחקן בלידרבורד מסוים