Wyślij żądania zbiorcze

Z tego dokumentu dowiesz się, jak grupować wywołania interfejsu API, aby zmniejszyć liczbę połączeń, które musi nawiązać klient.

Ten dokument dotyczy przede wszystkim tworzenia żądań zbiorczych za pomocą biblioteki klienta w języku Java. Podstawowy przykład jest również dostępny w Biblioteka klienta interfejsu API Google dla .NET. System wsadowy interfejsu Google Play EMM API używa tego samego protokołu HTTP. jako system przetwarzania wsadowego OData.

Omówienie

Każde żądanie wysyłane przez klienta do interfejsu Google Play EMM API skutkuje określonym nakładem pracy. Interfejs Google Play EMM API obsługuje grupowanie, dzięki czemu klient może umieścić kilka wywołań interfejsu API w jednym żądaniu.

Oto kilka przykładów sytuacji, w których warto użyć grupowania:

  • Domena została właśnie zarejestrowana i teraz ma jeszcze dużo danych do przesłania.
  • Użytkownik wprowadził zmiany w danych, gdy aplikacja działała w trybie offline, dlatego aplikacja musi zsynchronizować znaczną ilość danych lokalnych z serwerem.

W takich przypadkach zamiast wysyłać każde połączenie z osobna, możesz zgrupować je w jedną prośbę. Możesz nawet grupować żądania dotyczące wielu użytkowników lub wielu interfejsów API Google.

Obowiązuje jednak ograniczenie do 1000 wywołań w jednym żądaniu zbiorczym. Jeśli musisz wykonać więcej połączeń, użyj kilku żądań zbiorczych.

Szczegóły wsadu

Żądanie zbiorcze składa się z wielu wywołań interfejsu API połączonych w jedno żądanie JSON-RPC. W tej sekcji szczegółowo opisujemy składnię żądań zbiorczych. Przykład znajdziesz w sekcji poniżej.

Uwaga: zbiór n zbiorczych żądań wlicza się do limitu wykorzystania jako żądania n, a nie jako jedno żądanie. Przed przetworzeniem żądanie zbiorcze jest dzielone na zbiór żądań.

Format żądania zbiorczego

Biblioteka klienta Java zawiera wywołania służące do tworzenia żądań dla każdego wywołania interfejsu Google Play EMM API. Aby na przykład wyświetlić listę wszystkich aplikacji zainstalowanych na urządzeniu, należy użyć następującego polecenia:

AndroidEnterprise enterprise = ...;
InstallsListResponse response = enterprise.installs().list(enterpriseId, userId, deviceId)
  .execute();

Istnieje dodatkowe połączenie batch(), które może pojawić się w kolejce kilku żądań. Przykład:

AndroidEnterprise enterprise = ...;
BatchRequest batchRequest = enterprise.batch();
enterprise.installs().list(enterpriseId, userId, deviceId1).queue(batchRequest, callback1);
enterprise.installs().list(enterpriseId, userId, deviceId2).queue(batchRequest, callback2);
enterprise.installs().list(enterpriseId, userId, deviceId3).queue(batchRequest, callback3);
batchRequest.execute();
Po wywołaniu batchRequest.execute() wszystkie żądania oczekujące w kolejce są wysyłane do serwera jednocześnie w postaci tablicy JSON. Serwer stosuje do każdej części parametry zapytania i nagłówki żądania zewnętrznego (odpowiednio) do każdej części, a następnie traktuje każdą część tak, jakby była to osobne żądanie JSON.

Odpowiedź na żądanie zbiorcze

Serwer wykonuje każde osobne żądanie i grupuje wynik w pojedynczą odpowiedź wykonaną z pojedynczej tablicy. Biblioteka klienta dzieli tę odpowiedź na poszczególne odpowiedzi, które są wysyłane do funkcji wywołania zwrotnego przekazywanej do queue(). Wywołanie zwrotne to interfejs określający metodę w przypadku niepowodzenia i metodę sukcesu. Metoda callback1 zostałaby zaimplementowana na przykład jako:

private class InstallsCallback implements JsonBatchCallback<InstallsListResponse> {

  @Override
  public void onSuccess(InstallsListResponse response, HttpHeaders responseHeaders) {
    ...
  }

  @Override
  public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) {
    ...
  }
}

Uwaga: serwer może wykonywać wywołania w dowolnej kolejności, więc nie należy polegać na otrzymywaniu wyników w kolejności określonej w żądaniu. Jeśli chcesz mieć pewność, że w danej kolejności będą wykonywane 2 wywołania, nie możesz ich wysłać w jednym żądaniu. wyślij pierwsze żądanie i poczekaj na odpowiedź, zanim wyślesz kolejne.

Przykładowe żądanie zbiorcze

W tym przykładzie pokazujemy, jak wyświetlić listę wszystkich aplikacji zainstalowanych na wszystkich urządzeniach danego użytkownika. Pierwsze wywołania służą do uzyskania identyfikatora firmy i użytkownika, więc muszą być wykonywane po kolei. Gdy enterprise.devices().list() uzyska wszystkie identyfikatory urządzeń, możemy wysłać żądanie zbiorcze, by pobrać wszystkie aplikacje na wszystkich urządzeniach użytkownika jednocześnie.

package com.google.playenterprise.example;

import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.batch.BatchRequest;
import com.google.api.client.googleapis.batch.json.JsonBatchCallback;
import com.google.api.client.googleapis.json.GoogleJsonError;
import com.google.api.client.http.HttpHeaders;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson.JacksonFactory;
import com.google.api.services.androidenterprise.AndroidEnterprise;
import com.google.api.services.androidenterprise.AndroidEnterprise.Installs;
import com.google.api.services.androidenterprise.AndroidEnterpriseScopes;
import com.google.api.services.androidenterprise.model.Device;
import com.google.api.services.androidenterprise.model.DevicesListResponse;
import com.google.api.services.androidenterprise.model.Enterprise;
import com.google.api.services.androidenterprise.model.Install;
import com.google.api.services.androidenterprise.model.InstallsListResponse;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * Lists all the apps installed on all devices of a given user.
 */
public class ListAllInstalls {
  private AndroidEnterprise enterprise;
  private final List<String> installList = new ArrayList<>();

  public static void main(String[] argv) throws Exception {
    if (argv.length != 2) {
      throw new IllegalArgumentException("Usage: ListAllInstalls email jsonFilename");
    } else if (!argv[0].contains("@")) {
      throw new IllegalArgumentException("First parameter should be a valid email.");
    }
    new ListAllInstalls().run(argv[0], argv[1]);
  }

  private void run(String userEmail, String jsonKeyPath) throws IOException {
    enterprise = createAndroidEnterprise(jsonKeyPath);

    // Get the enterprise id, user id, and user devices.
    String domain = userEmail.split("@")[1];
    List<Enterprise> results = enterprise.enterprises().list(domain).execute().getEnterprise();
    if (results.isEmpty()) {
      throw new RuntimeException("No enterprise found.");
    }
    String enterpriseId = results.get(0).getId();
    String userId = enterprise
        .users()
        .list(enterpriseId, userEmail)
        .execute()
        .getUser()
        .get(0)
        .getId();
    List<Device> devices = getAllDevices(enterpriseId, userId);

    // Batch all calls to get installs on all user devices.
    gatherAllInstalls(enterpriseId, userId, devices);

    for (String entry : installList) {
      // Do something.
      System.out.println(entry);
    }
  }

  private List<Device> getAllDevices(String enterpriseId, String userId) throws IOException {
    DevicesListResponse devices = enterprise.devices().list(enterpriseId, userId).execute();
    return devices.getDevice();
  }

  private void gatherAllInstalls(String enterpriseId, String userId, List<Device> devices)
      throws IOException {
    BatchRequest batchRequest = enterprise.batch();
    for (Device device : devices) {
      Installs.List list = enterprise
          .installs().list(enterpriseId, userId, device.getAndroidId());
      // Each callback can take the specifics of the associated request in its constructor.
      list.queue(batchRequest, new InstallsCallback(device.getAndroidId()));
    }
    // Executes all the queued requests and their callbacks, single-threaded.
    batchRequest.execute();
  }

  private class InstallsCallback extends JsonBatchCallback<InstallsListResponse> {
    private final String androidId;

    InstallsCallback(String androidId) {
      this.androidId = androidId;
    }

    @Override
    public void onSuccess(InstallsListResponse response, HttpHeaders responseHeaders) {
      for (Install install : response.getInstall()) {
        installList.add(androidId + "," + install.getProductId());
      }
    }

    @Override
    public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) {
      throw new RuntimeException("Error fetching a device");
    }
  }

  private AndroidEnterprise createAndroidEnterprise(String jsonKeyPath) throws IOException {
    HttpTransport httpTransport = new NetHttpTransport();
    JsonFactory jsonFactory = new JacksonFactory();

    InputStream is = new BufferedInputStream(new FileInputStream(jsonKeyPath));
    final Credential credential = GoogleCredential.fromStream(is, httpTransport, jsonFactory)
        .createScoped(AndroidEnterpriseScopes.all());

    HttpRequestInitializer httpRequestInitializer = new HttpRequestInitializer() {
      @Override
      public void initialize(HttpRequest request) throws IOException {
        credential.initialize(request);
      }
    };
    return new AndroidEnterprise.Builder(httpTransport, jsonFactory, httpRequestInitializer)
        .build();
  }
}