الوصول من جهة الخادم إلى "خدمات ألعاب 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"، وتكامل تسجيل الدخول باستخدام "خدمات ألعاب Google Play" مع لعبتك.

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

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

إذا كنت تريد استخدام واجهات برمجة التطبيقات REST لخدمات "ألعاب 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.
    3. (اختياري) كجزء من عملية تسجيل الدخول، من المفترض أن تظهر للمستخدمين الجدد شاشة موافقة واحدة لمنح أذونات الوصول الإضافية. بعد قبول الموافقة، يمكنك ضبط المَعلمة 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.
       }
      });

  2. أرسِل الرمز المميّز لرمز مصادقة 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 في 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 من الخادم

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

لوحات الصدارة

يمكنك الاطّلاع على دليل قوائم الصدارة للاطّلاع على التفاصيل.

  • هل تريد الحصول على قائمة بجميع قوائم النتائج في اللعبة؟ أجرِ مكالمة إلى Leaderboards.list.

  • إذا أنهى أحد اللاعبين لعبة، يمكنك إرسال نتيجته إلى Scores.submit معرفة ما إذا كانت أعلى نتيجة جديدة.

  • لعرض قائمة صدارة، احصل على البيانات من Scores.list وعرضها للمستخدم.

  • استخدِم Scores.listWindow للعثور على مجموعة من النتائج القريبة من أعلى نتيجة للمستخدِم.

  • للحصول على مزيد من المعلومات عن نتيجة اللاعب في قائمة صدارة معيّنة (على سبيل المثال، إذا كان اللاعب ضمن أفضل% 12 من جميع اللاعبين)، يمكنك طلب Scores.get.

  • إذا كنت بصدد تصحيح أخطاء لعبة، يمكنك استدعاء Scores.reset من واجهات برمجة التطبيقات Management API لإعادة ضبط جميع النقاط لهذا اللاعب من قائمة صدارة معيّنة.