Lưu ý quan trọng: Chúng tôi không còn chấp nhận các lượt đăng ký mới cho Play EMM API.
Tìm hiểu thêm.
Gửi yêu cầu hàng loạt
Sử dụng bộ sưu tập để sắp xếp ngăn nắp các trang
Lưu và phân loại nội dung dựa trên lựa chọn ưu tiên của bạn.
Tài liệu này trình bày cách phân nhóm các lệnh gọi API với nhau để giảm số lượng kết nối mà ứng dụng của bạn phải thực hiện.
Tài liệu này trình bày cụ thể về việc thực hiện yêu cầu hàng loạt bằng thư viện ứng dụng Java.
Ví dụ cơ bản cũng có trong
Thư viện ứng dụng API của Google dành cho .NET. Hệ thống lô cho API EMM của Google Play sử dụng cùng một HTTP
là hệ thống xử lý theo lô OData.
Tổng quan
Mỗi yêu cầu mà ứng dụng của bạn đưa ra thông qua API EMM của Google Play đều dẫn đến một mức hao tổn nhất định. API EMM của Google Play hỗ trợ tính năng phân lô để cho phép ứng dụng của bạn đặt nhiều lệnh gọi API vào một yêu cầu duy nhất.
Sau đây là một số ví dụ về các trường hợp mà bạn có thể muốn sử dụng phân lô:
- Miền vừa được đăng ký và hiện có nhiều dữ liệu để tải lên.
- Người dùng đã thực hiện các thay đổi đối với dữ liệu trong khi ứng dụng của bạn không kết nối mạng, vì vậy, ứng dụng của bạn cần đồng bộ hoá nhiều dữ liệu cục bộ với máy chủ.
Trong những trường hợp như vậy, thay vì gửi riêng từng cuộc gọi, bạn có thể nhóm lại các cuộc gọi đó thành một yêu cầu duy nhất. Thậm chí bạn có thể nhóm các yêu cầu cho nhiều người dùng hoặc cho nhiều API của Google.
Tuy nhiên, bạn chỉ được có tối đa 1.000 lệnh gọi trong một yêu cầu hàng loạt. Nếu bạn cần thực hiện nhiều lệnh gọi hơn số lượng đó, hãy sử dụng nhiều yêu cầu hàng loạt.
Chi tiết gói
Một yêu cầu hàng loạt bao gồm nhiều lệnh gọi API kết hợp thành một yêu cầu JSON-RPC. Phần này mô tả chi tiết về cú pháp yêu cầu hàng loạt, kèm theo ví dụ trong phần sau.
Lưu ý: Một tập hợp n yêu cầu được nhóm cùng nhau sẽ được tính vào hạn mức sử dụng của bạn dưới dạng n yêu cầu chứ không phải một yêu cầu. Yêu cầu hàng loạt được tách thành một nhóm yêu cầu trước khi xử lý.
Thư viện ứng dụng Java chứa các lệnh gọi để tạo yêu cầu cho từng lệnh gọi API EMM của Google Play. Ví dụ: để liệt kê tất cả các ứng dụng đã cài đặt trên một thiết bị, bạn sẽ sử dụng lệnh sau:
AndroidEnterprise enterprise = ...;
InstallsListResponse response = enterprise.installs().list(enterpriseId, userId, deviceId)
.execute();
Còn có một lệnh gọi batch()
khác có thể đưa một số yêu cầu vào hàng đợi, như bạn thấy dưới đây:
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();
Khi batchRequest.execute()
được gọi, tất cả yêu cầu trong hàng đợi sẽ được gửi cùng lúc đến máy chủ dưới dạng một mảng JSON. Máy chủ sẽ áp dụng tiêu đề và tham số truy vấn của yêu cầu bên ngoài (nếu phù hợp) cho từng phần, sau đó xử lý từng phần như thể đó là một yêu cầu JSON riêng biệt.
Phản hồi yêu cầu hàng loạt
Máy chủ thực thi từng yêu cầu riêng biệt và nhóm kết quả thành một phản hồi duy nhất tạo thành một mảng duy nhất. Thư viện ứng dụng chia phản hồi này thành các phản hồi riêng lẻ, rồi gửi mỗi phản hồi này đến hàm callback được truyền đến queue()
. Lệnh gọi lại là một giao diện xác định một phương thức để xác định lỗi và một phương thức để thành công. Ví dụ: callback1
sẽ được triển khai dưới dạng một thực thể sau:
private class InstallsCallback implements JsonBatchCallback<InstallsListResponse> {
@Override
public void onSuccess(InstallsListResponse response, HttpHeaders responseHeaders) {
...
}
@Override
public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) {
...
}
}
Lưu ý: Máy chủ có thể thực hiện lệnh gọi theo thứ tự bất kỳ, vì vậy, đừng dựa vào việc nhận kết quả theo thứ tự được chỉ định trong yêu cầu của bạn. Nếu muốn đảm bảo rằng 2 lệnh gọi xảy ra theo một thứ tự nhất định, bạn không thể gửi các lệnh gọi đó trong một yêu cầu duy nhất; thay vào đó, hãy tự gửi yêu cầu đầu tiên rồi đợi phản hồi trước khi gửi yêu cầu thứ hai.
Ví dụ về yêu cầu hàng loạt
Ví dụ sau đây cho biết cách liệt kê tất cả ứng dụng đã cài đặt trên tất cả thiết bị của một người dùng cụ thể. Các lệnh gọi đầu tiên được dùng để lấy mã nhận dạng của doanh nghiệp và người dùng, theo đó phải được thực thi tuần tự. Sau khi đã lấy tất cả mã thiết bị bằng enterprise.devices().list()
, chúng ta có thể thực hiện yêu cầu hàng loạt để truy xuất tất cả ứng dụng trên tất cả thiết bị của người dùng cùng một lúc.
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();
}
}
Trừ phi có lưu ý khác, nội dung của trang này được cấp phép theo Giấy phép ghi nhận tác giả 4.0 của Creative Commons và các mẫu mã lập trình được cấp phép theo Giấy phép Apache 2.0. Để biết thông tin chi tiết, vui lòng tham khảo Chính sách trang web của Google Developers. Java là nhãn hiệu đã đăng ký của Oracle và/hoặc các đơn vị liên kết với Oracle.
Cập nhật lần gần đây nhất: 2025-05-08 UTC.
[null,null,["Cập nhật lần gần đây nhất: 2025-05-08 UTC."],[[["\u003cp\u003eBatching API calls in the Google Play EMM API reduces overhead by combining multiple calls into a single HTTP request.\u003c/p\u003e\n"],["\u003cp\u003eThis document focuses on batch requests using the Java client library, with an example demonstrating how to list all apps installed on a user's devices.\u003c/p\u003e\n"],["\u003cp\u003eBatch requests are limited to 1000 calls and count toward usage limits as individual requests.\u003c/p\u003e\n"],["\u003cp\u003eThe server may process batched calls in any order, requiring separate requests for sequential execution.\u003c/p\u003e\n"],["\u003cp\u003eResponses to batch requests are handled by callbacks defined for each individual request within the batch.\u003c/p\u003e\n"]]],[],null,["# Send Batch Requests\n\nThis document shows how to batch API calls together to reduce the number of connections your client has to make.\n\nThis document is specifically about making a batch request using the Java client library.\nA basic example is also available in the [Google API Client Library for .NET](https://developers.google.com/api-client-library/dotnet/guide/batch). The batch system for the Google Play EMM API uses the same HTTP\nsyntax as the [OData batch processing](http://www.odata.org/documentation/odata-version-3-0/batch-processing/) system.\n\nOverview\n--------\n\nEach request that your client makes via the Google Play EMM API results in a certain amount of overhead. The Google Play EMM API supports batching, to allow your client to put several API calls into a single request.\n\nHere are some examples of situations in which you might want to use batching:\n\n- A domain has just been enrolled and now has a lot of data to upload.\n- A user made changes to data while your application was offline, so your application needs to synchronize a great deal of local data with the server.\n\nIn cases such as these, instead of sending each call separately you can group them together into a single request. You can even group requests for multiple users, or for multiple Google APIs.\n\nYou are, however, limited to 1000 calls in a single batch request. If you need to make more calls than that, use multiple batch requests.\n\nBatch details\n-------------\n\nA batch request consists of multiple API calls combined into one JSON-RPC request. This section describes the batch request syntax in detail, with an [example](#example) in the section following.\n\n**Note** : A set of \u003cvar translate=\"no\"\u003en\u003c/var\u003e requests batched together counts toward your usage limit as \u003cvar translate=\"no\"\u003en\u003c/var\u003e requests, not as one request. The batch request is taken apart into a set of requests before processing.\n\n### Format of a batch request\n\nThe Java client library contains calls to create requests for each Google Play EMM API call. For instance, to list all apps installed on a device, you would use the following: \n\n```\nAndroidEnterprise enterprise = ...;\nInstallsListResponse response = enterprise.installs().list(enterpriseId, userId, deviceId)\n .execute();\n```\n\nThere is an additional `batch()` call that can queue several requests, as seen here: \n\n```\nAndroidEnterprise enterprise = ...;\nBatchRequest batchRequest = enterprise.batch();\nenterprise.installs().list(enterpriseId, userId, deviceId1).queue(batchRequest, callback1);\nenterprise.installs().list(enterpriseId, userId, deviceId2).queue(batchRequest, callback2);\nenterprise.installs().list(enterpriseId, userId, deviceId3).queue(batchRequest, callback3);\nbatchRequest.execute();\n```\nWhen `batchRequest.execute()` is called, all the queued requests are sent at once to the server as a JSON array. The server applies the outer request's query parameters and headers (as appropriate) to each part, and then treats each part as if it were a separate JSON request.\n\n\u003cbr /\u003e\n\n### Response to a batch request\n\nThe server executes each separate request, and groups the result into single response made of a single array. The client library splits this response into individual responses, and each one is sent to the callback function passed to `queue()`. The callback is an interface defining a method for failure and a method for success. For instance, `callback1` would be implemented as an instance of the following: \n\n```\nprivate class InstallsCallback implements JsonBatchCallback\u003cInstallsListResponse\u003e {\n\n @Override\n public void onSuccess(InstallsListResponse response, HttpHeaders responseHeaders) {\n ...\n }\n\n @Override\n public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) {\n ...\n }\n}\n```\n\n**Note**: The server may perform your calls in any order, so don't rely on receiving results in the order specified in your request. If you want to ensure that two calls occur in a given order, you can't send them in a single request; instead, send the first request by itself, and wait for a response before sending the second.\n\nExample batch request\n---------------------\n\nThe following example shows how to list all the apps installed on all of a given user devices. The first calls are used to obtain the id of the enterprise and of the user, and accordingly must be executed sequentially. Once all the device ids have been obtained with `enterprise.devices().list()`, we can do a batch request to retrieve all of the applications on all the user's devices at once. \n\n```\npackage com.google.playenterprise.example;\n\nimport com.google.api.client.auth.oauth2.Credential;\nimport com.google.api.client.googleapis.auth.oauth2.GoogleCredential;\nimport com.google.api.client.googleapis.batch.BatchRequest;\nimport com.google.api.client.googleapis.batch.json.JsonBatchCallback;\nimport com.google.api.client.googleapis.json.GoogleJsonError;\nimport com.google.api.client.http.HttpHeaders;\nimport com.google.api.client.http.HttpRequest;\nimport com.google.api.client.http.HttpRequestInitializer;\nimport com.google.api.client.http.HttpTransport;\nimport com.google.api.client.http.javanet.NetHttpTransport;\nimport com.google.api.client.json.JsonFactory;\nimport com.google.api.client.json.jackson.JacksonFactory;\nimport com.google.api.services.androidenterprise.AndroidEnterprise;\nimport com.google.api.services.androidenterprise.AndroidEnterprise.Installs;\nimport com.google.api.services.androidenterprise.AndroidEnterpriseScopes;\nimport com.google.api.services.androidenterprise.model.Device;\nimport com.google.api.services.androidenterprise.model.DevicesListResponse;\nimport com.google.api.services.androidenterprise.model.Enterprise;\nimport com.google.api.services.androidenterprise.model.Install;\nimport com.google.api.services.androidenterprise.model.InstallsListResponse;\n\nimport java.io.BufferedInputStream;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Lists all the apps installed on all devices of a given user.\n */\npublic class ListAllInstalls {\n private AndroidEnterprise enterprise;\n private final List\u003cString\u003e installList = new ArrayList\u003c\u003e();\n\n public static void main(String[] argv) throws Exception {\n if (argv.length != 2) {\n throw new IllegalArgumentException(\"Usage: ListAllInstalls email jsonFilename\");\n } else if (!argv[0].contains(\"@\")) {\n throw new IllegalArgumentException(\"First parameter should be a valid email.\");\n }\n new ListAllInstalls().run(argv[0], argv[1]);\n }\n\n private void run(String userEmail, String jsonKeyPath) throws IOException {\n enterprise = createAndroidEnterprise(jsonKeyPath);\n\n // Get the enterprise id, user id, and user devices.\n String domain = userEmail.split(\"@\")[1];\n List\u003cEnterprise\u003e results = enterprise.enterprises().list(domain).execute().getEnterprise();\n if (results.isEmpty()) {\n throw new RuntimeException(\"No enterprise found.\");\n }\n String enterpriseId = results.get(0).getId();\n String userId = enterprise\n .users()\n .list(enterpriseId, userEmail)\n .execute()\n .getUser()\n .get(0)\n .getId();\n List\u003cDevice\u003e devices = getAllDevices(enterpriseId, userId);\n\n // Batch all calls to get installs on all user devices.\n gatherAllInstalls(enterpriseId, userId, devices);\n\n for (String entry : installList) {\n // Do something.\n System.out.println(entry);\n }\n }\n\n private List\u003cDevice\u003e getAllDevices(String enterpriseId, String userId) throws IOException {\n DevicesListResponse devices = enterprise.devices().list(enterpriseId, userId).execute();\n return devices.getDevice();\n }\n\n private void gatherAllInstalls(String enterpriseId, String userId, List\u003cDevice\u003e devices)\n throws IOException {\n BatchRequest batchRequest = enterprise.batch();\n for (Device device : devices) {\n Installs.List list = enterprise\n .installs().list(enterpriseId, userId, device.getAndroidId());\n // Each callback can take the specifics of the associated request in its constructor.\n list.queue(batchRequest, new InstallsCallback(device.getAndroidId()));\n }\n // Executes all the queued requests and their callbacks, single-threaded.\n batchRequest.execute();\n }\n\n private class InstallsCallback extends JsonBatchCallback\u003cInstallsListResponse\u003e {\n private final String androidId;\n\n InstallsCallback(String androidId) {\n this.androidId = androidId;\n }\n\n @Override\n public void onSuccess(InstallsListResponse response, HttpHeaders responseHeaders) {\n for (Install install : response.getInstall()) {\n installList.add(androidId + \",\" + install.getProductId());\n }\n }\n\n @Override\n public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) {\n throw new RuntimeException(\"Error fetching a device\");\n }\n }\n\n private AndroidEnterprise createAndroidEnterprise(String jsonKeyPath) throws IOException {\n HttpTransport httpTransport = new NetHttpTransport();\n JsonFactory jsonFactory = new JacksonFactory();\n\n InputStream is = new BufferedInputStream(new FileInputStream(jsonKeyPath));\n final Credential credential = GoogleCredential.fromStream(is, httpTransport, jsonFactory)\n .createScoped(AndroidEnterpriseScopes.all());\n\n HttpRequestInitializer httpRequestInitializer = new HttpRequestInitializer() {\n @Override\n public void initialize(HttpRequest request) throws IOException {\n credential.initialize(request);\n }\n };\n return new AndroidEnterprise.Builder(httpTransport, jsonFactory, httpRequestInitializer)\n .build();\n }\n}\n```"]]