الوصول من جهة الخادم إلى "خدمات ألعاب Google Play"

ننصحك باستخدام GamesSignInClient لمصادقة اللاعبين ونقل هوية اللاعب بشكل آمن إلى خادم الخلفية. يتيح ذلك للعبتك استرداد هوية اللاعب وبياناته الأخرى بشكل آمن بدون أن تتعرّض للتلاعب المحتمل أثناء مرورها عبر الجهاز.

بعد أن تتم مصادقة اللاعب بنجاح، يمكنك طلب رمز خاص للاستخدام مرة واحدة (يُعرف باسم رمز التفويض الخاص بالخادم) من حزمة تطوير البرامج (SDK) الإصدار 2 من "خدمات ألعاب Play"، والذي يمرّرها العميل إلى الخادم. بعد ذلك، على الخادم، يمكنك استبدال رمز مصادقة الخادم برمز OAuth 2.0 يمكن للخادم استخدامه لإجراء طلبات إلى Google Play Games Services API.

للحصول على إرشادات إضافية حول إضافة المصادقة في ألعابك، يُرجى الاطّلاع على مصادقة المنصة لألعاب Android.

يجب اتّباع الخطوات التالية للوصول بلا إنترنت:

  1. في Google Play Console: عليك إنشاء بيانات اعتماد لخادم اللعبة. سيكون نوع عميل OAuth لبيانات الاعتماد هو "الويب".
  2. في تطبيق Android: كجزء من مصادقة المنصة، عليك طلب رمز تفويض الخادم لبيانات اعتماد الخادم وتمريره إلى الخادم. يمكن أن يطلب GamesSigninClient ثلاثة نطاقات OAuth 2.0 عند طلب الوصول إلى واجهات برمجة التطبيقات على الويب في "خدمات ألعاب Play" من جهة الخادم. النطاقات الاختيارية هي EMAIL وPROFILE وOPEN_ID. النطاقان التلقائيان هما DRIVE_APPFOLDER وGAMES_LITE.
  3. على خادم اللعبة: عليك استبدال رمز مصادقة الخادم برمز OAuth المميّز للوصول باستخدام خدمات مصادقة Google، ثم استخدامه لطلب بيانات من واجهات برمجة التطبيقات REST في "خدمات ألعاب Play".

قبل البدء

عليك أولاً إضافة لعبتك في الـ Google Play Console، كما هو موضّح في إعداد "خدمات ألعاب Google Play"، و دمج مصادقة منصة "خدمات ألعاب Play" مع لعبتك.

إنشاء تطبيق ويب من جهة الخادم

لا توفّر "خدمات ألعاب Google Play" دعمًا من جهة الخلفية لألعاب الويب. ومع ذلك، توفّر دعمًا من جهة خادم الخلفية لخادم لعبة Android.

إذا كنت تريد استخدام الـ REST APIs لخدمات ألعاب Google Play في تطبيقك من جهة الخادم، فاتّبِع الخطوات التالية:

  1. في Google Play Console، اختَر لعبة.
  2. انتقِل إلى خدمات ألعاب Play > الإعداد والإدارة > الإعدادات.
  3. انقر على إضافة بيانات اعتماد للانتقال إلى صفحة إضافة بيانات الاعتماد. اختَر خادم اللعبة كنوع بيانات الاعتماد وتابِع إلى قسم التفويض.
    1. إذا كان خادم اللعبة يتضمّن معرّف عميل OAuth، اختَره من القائمة المنسدلة. بعد حفظ التغييرات، انتقِل إلى القسم التالي.
    2. إذا لم يكن لديك معرّف عميل OAuth لخادم اللعبة، يمكنك إنشاء معرّف.
      1. انقر على إنشاء عميل OAuth واتّبِع الرابط إنشاء معرّف عميل OAuth.
      2. سينقلك ذلك إلى صفحة إنشاء معرّف عميل OAuth في Google Cloud Platform للمشروع المرتبط بلعبتك.
      3. املأ نموذج الصفحة وانقر على "إنشاء". احرِص على ضبط "نوع التطبيق" على "تطبيق الويب".
      4. عُد إلى قسم التفويض في صفحة إضافة بيانات الاعتماد، واختَر عميل OAuth الذي تم إنشاؤه حديثًا واحفظ التغييرات.

الحصول على رمز تفويض الخادم

لاسترداد رمز التفويض الخاص بالخادم الذي يمكن أن تستخدمه لعبتك للرموز المميّزة للوصول على خادم الخلفية:

  1. عليك طلب requestServerSideAccess من العميل.
    1. احرِص على استخدام معرّف عميل OAuth المسجَّل لخادم اللعبة وليس معرّف عميل OAuth لتطبيق Android.
    2. (اختياري) إذا كان خادم اللعبة يتطلّب الوصول بلا إنترنت (الوصول لفترة طويلة باستخدام رمز مميّز لإعادة التحميل) إلى "خدمات ألعاب Play"، يمكنك ضبط المعلَمة forceRefreshToken على "صحيح".
  2. (اختياري) كجزء من المصادقة، يجب أن يرى المستخدمون الجدد شاشة طلب الموافقة واحدة للنطاقات الإضافية. عند قبول الموافقة، عليك ضبط المعلَمة scopes باستخدام نطاقات OAuth‏ EMAIL وPROFILE وOPEN_ID. إذا رفض المستخدمون الموافقة، يتم إرسال النطاقَين التلقائيَين فقط DRIVE_APPFOLDER وGAMES_LITE إلى الخلفية.

    شاشة طلب الموافقة لنطاقات OAuth الإضافية
    شاشة طلب الموافقة لنطاقات OAuth الإضافية (انقر للتكبير).

     GamesSignInClient gamesSignInClient = PlayGames.getGamesSignInClient(this);
     gamesSignInClient.requestServerSideAccess(OAUTH_2_WEB_CLIENT_ID, /* forceRefreshToken= / false,
         / Additional AuthScope */ scopes)
       .addOnCompleteListener( task -> {
         if (task.isSuccessful()) {
           AuthResponse authresp = task.getResult();
           // Send the authorization code as a string and a
           // list of the granted AuthScopes that were granted by the
           // user. Exchange for an access token.
           // Verify the player with Play Games Services REST APIs.
         } else {
           // Failed to retrieve authentication code.
         }
     });
     

  3. أرسِل الرمز المميّز لرمز تفويض OAuth إلى خادم الخلفية ليتم استبداله والتحقّق من رقم تعريف اللاعب مقابل واجهات برمجة التطبيقات REST في "خدمات ألعاب Play"، ثم تتم المصادقة باستخدام لعبتك.

إرسال رمز التفويض للخادم

أرسِل رمز التفويض الخاص بالخادم إلى خادم الخلفية لاستبداله برموز الوصول والرمز المميز لإعادة التحميل. استخدِم الرمز المميّز للوصول لطلب بيانات من خدمات ألعاب Play API نيابةً عن اللاعب، ويمكنك اختياريًا تخزين الرمز المميّز لإعادة التحميل للحصول على رمز مميّز جديد للوصول عند انتهاء صلاحية الرمز المميّز للوصول.

لمزيد من المعلومات حول طريقة عمل أرقام تعريف اللاعبين، يُرجى الاطّلاع على أرقام تعريف اللاعبين من الجيل التالي.

يوضّح مقتطف الرمز التالي كيفية تنفيذ الرمز من جهة الخادم بلغة برمجة Java لاستبدال رمز مصادقة الخادم برموز الوصول.

Java

/**
 * Exchanges the authcode for an access token credential. The credential
 * is 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();

    TokenVerifier(tokenResponse);

    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;
}

يمكنك استرداد نطاقات OAuth باستخدام مكتبات عميل واجهة Google API في Java أو Python للحصول على عنصر GoogleIdTokenVerifier. يوضّح مقتطف الرمز التالي عملية التنفيذ بلغة برمجة Java.

Java

import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;

/**
 * Gets the GoogleIdTokenVerifier object and additional OAuth scopes.
 * If additional OAuth scopes are not requested, the idToken will be null.
 *
 * @param tokenResponse - the tokenResponse passed from the exchangeAuthCode
 *                        function.
 *
 **/

void TokenVerifier(GoogleTokenResponse tokenResponse) {

    string idTokenString = tokenResponse.getIdToken();

    GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
        // Specify the WEB_CLIENT_ID of the app that accesses the backend:
        .setAudience(Collections.singletonList(WEB_CLIENT_ID))
        // Or, if multiple clients access the backend:
        //.setAudience(Arrays.asList(WEB_CLIENT_ID_1, WEB_CLIENT_ID_2, WEB_CLIENT_ID_3))
        .build();

    GoogleIdToken idToken = verifier.verify(idTokenString);

    // The idToken can be null if additional OAuth scopes are not requested.
    if (idToken != null) {
        Payload payload = idToken.getPayload();

    // Print user identifier
    String userId = payload.getSubject();
    System.out.println("User ID: " + userId);

    // Get profile information from payload
    String email = payload.getEmail();
    boolean emailVerified = Boolean.valueOf(payload.getEmailVerified());
    String name = (String) payload.get("name");
    String pictureUrl = (String) payload.get("picture");
    String locale = (String) payload.get("locale");
    String familyName = (String) payload.get("family_name");
    String givenName = (String) payload.get("given_name");

    // This ID is unique to each Google Account, making it suitable for use as
    // a primary key during account lookup. Email is not a good choice because
    // it can be changed by the user.
    String sub = payload.getSubject();

    // Use or store profile information
    // ...

    } else {
      System.out.println("Invalid ID token.");
    }
}

طلب بيانات من واجهات برمجة التطبيقات REST من الخادم

يُرجى الاطّلاع على واجهات برمجة التطبيقات REST لخدمات ألعاب Google Play للحصول على وصف كامل لطلبات واجهة برمجة التطبيقات المتاحة.

في ما يلي أمثلة على طلبات واجهة برمجة التطبيقات 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 لإعادة ضبط جميع نتائج هذا اللاعب من لوحة صدارة معيّنة.