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

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

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

للحصول على إرشادات إضافية حول إضافة المصادقة في ألعابك، يمكنك الاطّلاع على مصادقة النظام الأساسي لألعاب 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 API الخاصة بـ "خدمات ألعاب Play".

قبل البدء

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

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

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

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

  1. في Google Play Console، اختَر لعبة.
  2. انتقِل إلى خدمات ألعاب Google 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 على القيمة true.
  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 API في "خدمات ألعاب Play"، ثم يتم إثبات الهوية باستخدام لعبتك.

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

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

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

يوضّح مقتطف الرمز البرمجي التالي كيفية تنفيذ الرمز البرمجي من جهة الخادم بلغة البرمجة 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");

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

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

طلب بيانات من واجهات REST API من الخادم

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

تشمل الأمثلة على طلبات REST API التي قد تجدها مفيدة ما يلي:

اللاعب

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