Cách thức hoạt động

Giới thiệu

API thiết lập tự động giúp đại lý thiết bị tự động hoá việc tích hợp. Các công cụ bán hàng của tổ chức có thể tích hợp trong quy trình thiết lập tự động – giúp người dùng và khách hàng của bạn làm việc hiệu quả hơn. Sử dụng API này để giúp người dùng của bạn:

  • Chỉ định thiết bị đã mua cho tài khoản thiết lập tự động của khách hàng.
  • Tạo tài khoản thiết lập tự động cho khách hàng của bạn.
  • Đính kèm siêu dữ liệu điện thoại và đơn đặt hàng của tổ chức vào các thiết bị.
  • Tạo báo cáo về các thiết bị được chỉ định cho khách hàng của bạn.

Tài liệu này giới thiệu API và giải thích các mẫu. Nếu bạn muốn tự khám phá API, hãy thử hướng dẫn nhanh về Java, .NET hoặc Python.

Các khái niệm về API

Khách hàng và thiết bị là tài nguyên cốt lõi mà bạn sử dụng trong API. Để tạo khách hàng, hãy gọi create. Bạn có thể tạo thiết bị bằng các phương thức API xác nhận quyền sở hữu (xem bên dưới). Tổ chức của bạn cũng có thể tạo khách hàng và thiết bị bằng cổng thiết lập tự động.

Mối quan hệ giữa thiết bị và tài nguyên của khách hàng

Khách hàng
Các công ty mà tổ chức của bạn bán thiết bị. Khách hàng có nameID. Sử dụng tên của khách hàng khi bạn muốn xác nhận quyền sở hữu hoặc tìm thiết bị của họ. Để tìm hiểu thêm, hãy xem Customer.
Thiết bị
Thiết bị Android hoặc ChromeOS có khả năng thiết lập tự động mà tổ chức của bạn bán cho khách hàng. Thiết bị có mã nhận dạng phần cứng, siêu dữ liệu và thông báo xác nhận quyền sở hữu của khách hàng. Thiết bị là trọng tâm của API, vì vậy, bạn sử dụng thiết bị trong hầu hết mọi phương thức. Để tìm hiểu thêm, hãy xem Device.
DeviceIdentifier
Đóng gói mã nhận dạng phần cứng (chẳng hạn như IMEI hoặc MEID) để xác định một thiết bị được sản xuất. Sử dụng DeviceIdentifier để nhắm đến thiết bị mà bạn muốn tìm, cập nhật hoặc xác nhận quyền sở hữu. Để tìm hiểu thêm, hãy đọc phần Giá trị nhận dạng.
DeviceMetadata
Lưu trữ các cặp siêu dữ liệu khoá-giá trị của thiết bị. Sử dụng DeviceMetadata để lưu trữ siêu dữ liệu của tổ chức. Để tìm hiểu thêm, hãy đọc bài viết Siêu dữ liệu thiết bị.

Để liệt kê tất cả phương thức API và tài nguyên mà ứng dụng của bạn có thể dùng, hãy xem Tài liệu tham khảo API.

Tạo khách hàng

Đối với các thiết bị Android, đại lý chịu trách nhiệm tạo tài khoản khách hàng thay mặt cho khách hàng của họ. Khách hàng sẽ sử dụng tài khoản này để truy cập vào cổng thông tin tự động để định cấu hình các chế độ cài đặt cấp phép cho thiết bị của họ. Điều này không cần thiết đối với các thiết bị ChromeOS đã có tài khoản Google Workspace. Thiết bị này sẽ dùng tài khoản này để định cấu hình chế độ cài đặt cấp phép.

Bạn có thể gọi phương thức API create để tạo tài khoản khách hàng cho quy trình thiết lập tự động. Vì khách hàng của bạn sẽ thấy tên công ty trong cổng thiết lập tự động, nên người dùng ứng dụng của bạn phải xác nhận rằng tên đó là chính xác. Bạn không thể chỉnh sửa tên khách hàng sau khi tạo khách hàng.

Bạn cần bao gồm ít nhất một địa chỉ email công ty liên kết với một Tài khoản Google để làm chủ sở hữu. Bạn không thể sử dụng tài khoản Gmail cá nhân với API này. Nếu khách hàng cần trợ giúp về việc liên kết tài khoản, hãy gửi hướng dẫn trong phần Liên kết Tài khoản Google.

Sau khi bạn tạo khách hàng bằng cách gọi API, họ sẽ quản lý quyền truy cập vào cổng thông tin của nhân viên của họ — bạn không thể chỉnh sửa người dùng của khách hàng bằng API. Đoạn mã dưới đây cho biết cách bạn có thể tạo khách hàng:

Java

// Provide the customer data as a Company type.
// The API requires a name and owners.
Company customer = new Company();
customer.setCompanyName("XYZ Corp");
customer.setOwnerEmails(Arrays.asList("liz@example.com", "darcy@example.com"));
customer.setAdminEmails(Collections.singletonList("jane@example.com"));

// Use our reseller ID for the parent resource name.
String parentResource = String.format("partners/%d", PARTNER_ID);

// Call the API to create the customer using the values in the company object.
CreateCustomerRequest body = new CreateCustomerRequest();
body.setCustomer(customer);
Company response = service.partners().customers().create(parentResource, body).execute();

.NET

// Provide the customer data as a Company type.
// The API requires a name and owners.
var customer = new Company
{
    CompanyName = "XYZ Corp",
    OwnerEmails = new String[] { "liz@example.com", "darcy@example.com" },
    AdminEmails = new String[] { "jane@example.com" }
};

// Use our reseller ID for the parent resource name.
var parentResource = String.Format("partners/{0}", PartnerId);

// Call the API to create the customer using the values in the company object.
var body = new CreateCustomerRequest
{
    Customer = customer
};
var request = service.Partners.Customers.Create(body, parentResource);
var response = request.Execute();

Python

# Provide the customer data as a Company type. The API requires
# a name and at least one owner.
company = {'companyName':'XYZ Corp', \
  'ownerEmails':['liz@example.com', 'darcy@example.com'], \
  'adminEmails':['jane@example.com']}

# Use our reseller ID for the parent resource name.
parent_resource = 'partners/{0}'.format(PARTNER_ID)

# Call the API to create the customer using the values in the company object.
response = service.partners().customers().create(parent=parent_resource,
    body={'customer':company}).execute()

Để tìm hiểu thêm về vai trò chủ sở hữu và quản trị viên đối với nhân viên của khách hàng, hãy đọc bài viết Người dùng cổng.

Xác nhận quyền sở hữu thiết bị cho khách hàng

Sau khi mua thiết bị, khách hàng sẽ muốn định cấu hình chế độ cài đặt cấp phép cho những thiết bị này trong tài khoản của họ. Việc xác nhận quyền sở hữu thiết bị sẽ thêm thiết bị vào quy trình thiết lập tự động và cho phép khách hàng định cấu hình các chế độ cài đặt cấp phép.

Bản ghi cấp phép của thiết bị có một phần dành cho quy trình thiết lập tự động. Bạn chỉ định thiết bị bằng cách xác nhận quyền sở hữu phần thiết lập tự động của bản ghi cho khách hàng. Gọi phương thức partners.devices.claim hoặc partners.devices.claimAsync với khách hàng làm đối số. Luôn cung cấp SECTION_TYPE_ZERO_TOUCH dưới dạng một giá trị cho sectionType.

Bạn cần huỷ xác nhận (xem bên dưới) thiết bị của khách hàng rồi mới có thể xác nhận quyền sở hữu thiết bị đó cho một khách hàng khác. Các phương thức xác nhận quyền sở hữu validate các trường DeviceIdentifier, bao gồm cả IMEI hoặc MEID hoặc số sê-ri, tên nhà sản xuất và kiểu máy, cũng như mã thiết bị đã chứng thực của thiết bị ChromeOS khi tạo một thiết bị mới.

Đoạn mã dưới đây cho biết cách xác nhận quyền sở hữu thiết bị:

Java

// Identify the device to claim.
DeviceIdentifier identifier = new DeviceIdentifier();
// The manufacturer value is optional but recommended for cellular devices
identifier.setManufacturer("Google");
identifier.setImei("098765432109875");

// Create the body to connect the customer with the device.
ClaimDeviceRequest body = new ClaimDeviceRequest();
body.setDeviceIdentifier(identifier);
body.setCustomerId(customerId);
body.setSectionType("SECTION_TYPE_ZERO_TOUCH");

// Claim the device.
ClaimDeviceResponse response = service.partners().devices().claim(PARTNER_ID, body).execute();

.NET

// Identify the device to claim.
var deviceIdentifier = new DeviceIdentifier
{
    // The manufacturer value is optional but recommended for cellular devices
    Manufacturer = "Google",
    Imei = "098765432109875"
};

// Create the body to connect the customer with the device.
ClaimDeviceRequest body = new ClaimDeviceRequest
{
    DeviceIdentifier = deviceIdentifier,
    CustomerId = CustomerId,
    SectionType = "SECTION_TYPE_ZERO_TOUCH"
};

// Claim the device.
var response = service.Partners.Devices.Claim(body, PartnerId).Execute();

Python

# Identify the device to claim.
# The manufacturer value is optional but recommended for cellular devices
device_identifier = {'manufacturer':'Google', 'imei':'098765432109875'}

# Create the body to connect the customer with the device.
request_body = {'deviceIdentifier':device_identifier, \
    'customerId':customer_id, \
    'sectionType':'SECTION_TYPE_ZERO_TOUCH'}

# Claim the device.
response = service.partners().devices().claim(partnerId=PARTNER_ID,
    body=request_body).execute()

Đang huỷ xác nhận quyền sở hữu thiết bị

Tổ chức của bạn có thể huỷ xác nhận quyền sở hữu thiết bị của khách hàng. Việc huỷ xác nhận một thiết bị sẽ xoá thiết bị đó khỏi quy trình thiết lập tự động. Đại lý có thể huỷ xác nhận quyền sở hữu thiết bị mà họ muốn di chuyển sang tài khoản khác, trả lại thiết bị hoặc thiết bị đã bị xác nhận nhầm quyền. Gọi phương thức partners.devices.unclaim hoặc partners.devices.unclaimAsync để huỷ xác nhận quyền sở hữu thiết bị của khách hàng.

Nhà cung cấp

Bạn có thể sử dụng nhà cung cấp để đại diện cho đối tác đại lý trong mạng lưới đại lý, nhà cung cấp dịch vụ tại địa phương trong mạng lưới đại lý toàn cầu hoặc bất kỳ tổ chức nào thay mặt bạn bán thiết bị. Nhà cung cấp sẽ giúp bạn tách biệt người dùng, khách hàng và thiết bị của bạn:

  • Các nhà cung cấp mà bạn tạo không thể xem tài khoản thiết lập tự động của bạn hoặc tài khoản của từng nhà cung cấp khác.
  • Bạn có thể xem khách hàng và thiết bị của nhà cung cấp, cũng như có thể huỷ đăng ký thiết bị của nhà cung cấp. Tuy nhiên, bạn không thể chỉ định thiết bị cho khách hàng của nhà cung cấp.

Sử dụng cổng thông tin để tạo nhà cung cấp cho tổ chức của bạn — bạn không thể sử dụng API. Vai trò tài khoản của bạn phải là Chủ sở hữu thì mới có thể tạo một nhà cung cấp mới. Nếu tổ chức của bạn có nhà cung cấp, bạn có thể gọi partners.vendors.list để liệt kê nhà cung cấp và partners.vendors.customers.list để lấy khách hàng của nhà cung cấp. Ví dụ sau đây sử dụng cả hai phương thức này để in báo cáo hiển thị trạng thái Điều khoản dịch vụ cho khách hàng của nhà cung cấp:

Java

// First, get the organization's vendors.
String parentResource = String.format("partners/%d", PARTNER_ID);
ListVendorsResponse results = service.partners().vendors().list(parentResource).execute();
if (results.getVendors() == null) {
  return;
}

// For each vendor, report the company name and a maximum 5 customers.
for (Company vendor: results.getVendors()) {
  System.out.format("\n%s customers\n", vendor.getCompanyName());
  System.out.println("---");
  // Use the vendor's API resource name as the parent resource.
  AndroidProvisioningPartner.Partners.Vendors.Customers.List customerRequest =
      service.partners().vendors().customers().list(vendor.getName());
  customerRequest.setPageSize(5);
  ListVendorCustomersResponse customerResponse = customerRequest.execute();

  List<Company> customers = customerResponse.getCustomers();
  if (customers == null) {
    System.out.println("No customers");
    break;
  } else {
    for (Company customer: customers) {
      System.out.format("%s: %s\n",
          customer.getCompanyName(),
          customer.getTermsStatus());
    }
  }
}

.NET

// First, get the organization's vendors.
var parentResource = String.Format("partners/{0}", PartnerId);
var results = service.Partners.Vendors.List(parentResource).Execute();
if (results.Vendors == null)
{
    return;
}

// For each vendor, report the company name and a maximum 5 customers.
foreach (Company vendor in results.Vendors)
{
    Console.WriteLine("\n{0} customers", vendor);
    Console.WriteLine("---");
    // Use the vendor's API resource name as the parent resource.
    PartnersResource.VendorsResource.CustomersResource.ListRequest customerRequest =
        service.Partners.Vendors.Customers.List(vendor.Name);
    customerRequest.PageSize = 5;
    var customerResponse = customerRequest.Execute();

    IList<Company> customers = customerResponse.Customers;
    if (customers == null)
    {
        Console.WriteLine("No customers");
        break;
    }
    else
    {
        foreach (Company customer in customers)
        {
            Console.WriteLine("{0}: {1}", customer.Name, customer.TermsStatus);
        }
    }
}

Python

# First, get the organization's vendors.
parent_resource = 'partners/{0}'.format(PARTNER_ID)
vendor_response = service.partners().vendors().list(
    parent=parent_resource).execute()
if 'vendors' not in vendor_response:
  return

# For each vendor, report the company name and a maximum 5 customers.
for vendor in vendor_response['vendors']:
  print '\n{0} customers'.format(vendor['companyName'])
  print '---'
  # Use the vendor's API resource name as the parent resource.
  customer_response = service.partners().vendors().customers().list(
      parent=vendor['name'], pageSize=5).execute()
  if 'customers' not in customer_response:
    print 'No customers'
    break
  for customer in customer_response['customers']:
    print '  {0}: {1}'.format(customer['name'], customer['termsStatus'])

Nếu có một tập hợp thiết bị, bạn có thể cần biết đại lý hoặc nhà cung cấp nào đã xác nhận quyền sở hữu thiết bị đó. Để có mã đại lý dạng số, hãy kiểm tra giá trị của trường resellerId trong hồ sơ xác nhận quyền sở hữu của thiết bị.

Tổ chức của bạn có thể huỷ xác nhận quyền sở hữu một thiết bị do nhà cung cấp xác nhận quyền sở hữu. Đối với các lệnh gọi API khác sửa đổi thiết bị, bạn nên kiểm tra để đảm bảo tổ chức của mình đã xác nhận quyền sở hữu thiết bị trước khi gọi phương thức API. Ví dụ sau cho thấy cách thực hiện việc này:

Java

// Get the devices claimed for two customers: one of our organization's
// customers and one of our vendor's customers.
FindDevicesByOwnerRequest body = new FindDevicesByOwnerRequest();
body.setSectionType("SECTION_TYPE_ZERO_TOUCH");
body.setCustomerId(Arrays.asList(resellerCustomerId, vendorCustomerId));
body.setLimit(MAX_PAGE_SIZE);
FindDevicesByOwnerResponse response =
    service.partners().devices().findByOwner(PARTNER_ID, body).execute();
if (response.getDevices() == null) {
  return;
}

for (Device device: response.getDevices()) {
  // Confirm the device was claimed by our reseller and not a vendor before
  // updating metadata in another method.
  for (DeviceClaim claim: device.getClaims()) {
    if (claim.getResellerId() == PARTNER_ID) {
      updateDeviceMetadata(device.getDeviceId());
      break;
    }
  }
}

.NET

// Get the devices claimed for two customers: one of our organization's
// customers and one of our vendor's customers.
FindDevicesByOwnerRequest body = new FindDevicesByOwnerRequest
{
    Limit = MaxPageSize,
    SectionType = "SECTION_TYPE_ZERO_TOUCH",
    CustomerId = new List<long?>
    {
        resellerCustomerId,
        vendorCustomerId
    }
};
var response = service.Partners.Devices.FindByOwner(body, PartnerId).Execute();
if (response.Devices == null)
{
    return;
}

foreach (Device device in response.Devices)
{
    // Confirm the device was claimed by our reseller and not a vendor before
    // updating metadata in another method.
    foreach (DeviceClaim claim in device.Claims)
    {
        if (claim.ResellerId == PartnerId)
        {
            UpdateDeviceMetadata(device.DeviceId);
            break;
        }
    }
}

Python

# Get the devices claimed for two customers: one of our organization's
# customers and one of our vendor's customers.
request_body = {'limit':MAX_PAGE_SIZE, \
  'pageToken':None, \
  'customerId':[reseller_customer_id, vendor_customer_id], \
  'sectionType':'SECTION_TYPE_ZERO_TOUCH'}
response = service.partners().devices().findByOwner(partnerId=PARTNER_ID,
    body=request_body).execute()

for device in response['devices']:
  # Confirm the device was claimed by our reseller and not a vendor before
  # updating metadata in another method.
  for claim in device['claims']:
    if claim['resellerId'] == PARTNER_ID:
      update_device_metadata(device['deviceId'])
      break

Thao tác hàng loạt diễn ra trong thời gian dài

API bao gồm các phiên bản không đồng bộ của phương thức thiết bị. Các phương thức này cho phép xử lý hàng loạt nhiều thiết bị, trong khi các phương thức đồng bộ xử lý một thiết bị cho mỗi yêu cầu API. Tên phương thức không đồng bộ có hậu tố Async, ví dụ: claimAsync.

Các phương thức API không đồng bộ sẽ trả về kết quả trước khi quá trình xử lý hoàn tất. Các phương thức không đồng bộ cũng giúp ứng dụng (hoặc công cụ) của bạn duy trì khả năng thích ứng của người dùng trong khi họ chờ một thao tác diễn ra trong thời gian dài hoàn tất. Ứng dụng của bạn nên định kỳ kiểm tra trạng thái của hoạt động.

Hoạt động tính toán

Bạn sẽ dùng Operation để theo dõi một hoạt động hàng loạt diễn ra trong thời gian dài. Lệnh gọi thành công đến một phương thức không đồng bộ sẽ trả về thông tin tham chiếu đến thao tác trong phản hồi. Đoạn mã JSON dưới đây cho thấy một phản hồi thông thường sau khi gọi updateMetadataAsync:

{
  "name": "operations/apibatchoperation/1234567890123476789"
}

Mỗi tác vụ chứa một danh sách các tác vụ riêng lẻ. Hãy gọi operations.get để tìm hiểu thông tin về trạng thái và kết quả của các tác vụ có trong thao tác đó. Đoạn mã dưới đây cho thấy cách bạn có thể thực hiện việc này. Trong ứng dụng của riêng mình, bạn cần phải xử lý mọi lỗi.

Java

// Build out the request body to apply the same order number to a customer's
// purchase of 2 devices.
UpdateMetadataArguments firstUpdate = new UpdateMetadataArguments();
firstUpdate.setDeviceMetadata(metadata);
firstUpdate.setDeviceId(firstTargetDeviceId);

UpdateMetadataArguments secondUpdate = new UpdateMetadataArguments();
secondUpdate.setDeviceMetadata(metadata);
secondUpdate.setDeviceId(firstTargetDeviceId);

// Start the device metadata update.
UpdateDeviceMetadataInBatchRequest body = new UpdateDeviceMetadataInBatchRequest();
body.setUpdates(Arrays.asList(firstUpdate, secondUpdate));
Operation response = service
    .partners()
    .devices()
    .updateMetadataAsync(PARTNER_ID, body)
    .execute();

// Assume the metadata update started, so get the Operation for the update.
Operation operation = service.operations().get(response.getName()).execute();

.NET

// Build out the request body to apply the same order number to a customer's
// purchase of 2 devices.
var updates = new List<UpdateMetadataArguments>
{
    new UpdateMetadataArguments
    {
        DeviceMetadata = metadata,
        DeviceId = firstTargetDeviceId
    },
    new UpdateMetadataArguments
    {
        DeviceMetadata = metadata,
        DeviceId = secondTargetDeviceId
    }
};

// Start the device metadata update.
UpdateDeviceMetadataInBatchRequest body = new UpdateDeviceMetadataInBatchRequest
{
    Updates = updates
};
var response = service.Partners.Devices.UpdateMetadataAsync(body, PartnerId).Execute();

// Assume the metadata update started, so get the Operation for the update.
Operation operation = service.Operations.Get(response.Name).Execute();

Python

# Build out the request body to apply the same order number to a customer's
# purchase of 2 devices.
updates = [{'deviceMetadata':metadata,'deviceId':first_target_device_id},
    {'deviceMetadata':metadata,'deviceId':second_target_device_id}]

# Start the device metadata update.
response = service.partners().devices().updateMetadataAsync(
    partnerId=PARTNER_ID, body={'updates':updates}).execute()

# Assume the metadata update started, so get the Operation for the update.
operation = service.operations().get(name=response['name']).execute()

Để tìm hiểu xem một thao tác đã hoàn tất hay chưa, hãy kiểm tra thao tác đối với trường done có giá trị true. Nếu thiếu done hoặc false thì thao tác này vẫn đang chạy.

Phản hồi

Sau khi một thao tác kết thúc, API sẽ cập nhật thao tác đó bằng kết quả – ngay cả khi tất cả hoặc không có tác vụ riêng lẻ nào thành công. Trường response là đối tượng DevicesLongRunningOperationResponse, trong đó nêu chi tiết quá trình xử lý từng thiết bị trong thao tác.

Kiểm tra trường successCount để tìm hiểu xem có thao tác nào không thành công một cách hiệu quả hay không và tránh lặp lại thông qua danh sách kết quả lớn. Trường perDeviceStatus của DevicesLongRunningOperationResponse là danh sách các thực thể OperationPerDevice nêu chi tiết từng thiết bị trong thao tác. Thứ tự danh sách khớp với các nhiệm vụ trong yêu cầu ban đầu.

Mỗi tác vụ OperationPerDevice chứa một trường result và một bản tóm tắt lời nhắc về yêu cầu mà máy chủ nhận được. Kiểm tra xem thao tác thành công hay không bằng cách sử dụng trường result.

Đoạn mã JSON dưới đây cho thấy một phần của phản hồi thông thường của một thao tác sau lệnh gọi đến updateMetadataAsync:

"response": {
  "perDeviceStatus": [
    {
      "result": {
        "deviceId": "12345678901234567",
        "status": "SINGLE_DEVICE_STATUS_SUCCESS"
      },
      "updateMetadata": {
        "deviceId": "12345678901234567",
        "deviceMetadata": {
          "entries": {
            "phonenumber": "+1 (800) 555-0100"
          }
        }
      }
    }
  ],
  "successCount": 1
}

Theo dõi tiến trình

Nếu ứng dụng của bạn cần theo dõi tiến trình, bạn nên định kỳ tìm nạp lại thao tác. Trường metadata chứa thực thể DevicesLongRunningOperationMetadata để giúp ứng dụng kiểm tra tiến trình mới nhất của thao tác đang chạy. Sử dụng các trường của DevicesLongRunningOperationMetadata được liệt kê trong bảng sau để theo dõi tiến trình của hoạt động:

Trường Tỷ lệ sử dụng thông thường
processingStatus Các thay đổi từ BATCH_PROCESS_PENDING thành BATCH_PROCESS_IN_PROGRESS và sau đó thành BATCH_PROCESS_PROCESSED khi hoạt động này diễn ra.
progress Tỷ lệ phần trăm bản cập nhật đã xử lý. Ứng dụng của bạn có thể dùng thông tin này để ước tính thời gian kết thúc. Vì giá trị progress có thể là 100 trong khi thao tác này hoàn tất, hãy kiểm tra trường done của thao tác để xem thao tác đó đã hoàn tất và có kết quả hay chưa.
devicesCount Cho biết số lượng nội dung cập nhật trong hoạt động. Số liệu này có thể khác với số nội dung cập nhật trong yêu cầu của bạn nếu API không thể phân tích cú pháp một số nội dung cập nhật.

Ví dụ đơn giản bên dưới cho thấy cách một ứng dụng có thể dùng siêu dữ liệu về tiến trình để đặt khoảng thời gian thăm dò ý kiến. Trong ứng dụng, bạn có thể cần một trình chạy tác vụ phức tạp hơn để thăm dò ý kiến. Bạn cũng cần thêm phương thức xử lý lỗi.

Java

// Milliseconds between polling the API.
private static long MIN_INTERVAL = 2000;
private static long MAX_INTERVAL = 10000;

// ...
// Start the device metadata update.
Operation response = service
    .partners()
    .devices()
    .updateMetadataAsync(PARTNER_ID, body)
    .execute();
String operationName = response.getName();

// Start polling for completion.
long startTime = new Date().getTime();
while (true) {

  // Get the latest update on the operation's progress using the API.
  Operation operation = service.operations().get(operationName).execute();

  if (operation.get("done") != null && operation.getDone()) {
    // The operation is finished. Print the status.
    System.out.format("Operation complete: %s of %s successful device updates\n",
        operation.getResponse().get("successCount"),
        operation.getMetadata().get("devicesCount"));
    break;

  } else {
    // Estimate how long the operation *should* take - within min and max value.
    BigDecimal opProgress = (BigDecimal) operation.getMetadata().get("progress");
    double progress = opProgress.longValue();
    long interval = MAX_INTERVAL;
    if (progress > 0) {
      interval = (long) ((new Date().getTime() - startTime) *
          ((100.0 - progress) / progress));
    }
    interval = Math.max(MIN_INTERVAL, Math.min(interval, MAX_INTERVAL));

    // Sleep until the operation should be complete.
    Thread.sleep(interval);
  }
}

.NET

// Milliseconds between polling the API.
private static double MinInterval = 2000;
private static double MaxInterval = 10000;

// ...
// Start the device metadata update.
var response = service.Partners.Devices.UpdateMetadataAsync(body, PartnerId).Execute();
var operationName = response.Name;

// Start polling for completion.
var startTime = DateTime.Now;
while (true)
{

    // Get the latest update on the operation's progress using the API.
    Operation operation = service.Operations.Get(operationName).Execute();

    if (operation.Done == true)
    {
        // The operation is finished. Print the status.
        Console.WriteLine("Operation complete: {0} of {1} successful device updates",
                          operation.Response["successCount"],
                          operation.Metadata["devicesCount"]);
        break;
    }
    else
    {
        // Estimate how long the operation *should* take - within min and max value.
        double progress = (double)(long)operation.Metadata["progress"];
        double interval = MaxInterval;
        if (progress > 0)
        {
            interval = DateTime.Now.Subtract(startTime).TotalMilliseconds *
                                     ((100.0 - progress) / progress);
        }
        interval = Math.Max(MinInterval, Math.Min(interval, MaxInterval));

        // Sleep until the operation should be complete.
        System.Threading.Thread.Sleep((int)interval);
    }
}

Python

# Seconds between polling the API.
MIN_INTERVAL = 2;
MAX_INTERVAL = 10;

# ...
# Start the device metadata update
response = service.partners().devices().updateMetadataAsync(
  partnerId=PARTNER_ID, body={'updates':updates}).execute()

op_name = response['name']
start_time = time.time()

# Start polling for completion
while True:
  # Get the latest update on the operation's progress using the API
  op = service.operations().get(name=op_name).execute()

  if 'done' in op and op['done']:
    # The operation is finished. Print the status.
    print('Operation complete: {0} of {1} successful device updates'.format(
      op['response']['successCount'], op['metadata']['devicesCount']
    ))
    break
  else:
    # Estimate how long the operation *should* take - within min and max.
    progress = op['metadata']['progress']
    interval = MIN_INTERVAL
    if progress > 0:
      interval = (time.time() - start_time) * ((100.0 - progress) / progress)
    interval = max(MIN_INTERVAL, min(interval, MAX_INTERVAL))

    # Sleep until the operation should be complete.
    time.sleep(interval)

Hãy chọn một phương pháp thăm dò ý kiến phù hợp với người dùng ứng dụng của bạn. Một số người dùng ứng dụng có thể hưởng lợi từ các bản cập nhật tiến trình thường xuyên nếu họ đang chờ một quy trình hoàn tất.

Kết quả được phân trang

Phương thức API partners.devices.findByOwner có thể trả về danh sách rất lớn các thiết bị. Để giảm kích thước phản hồi, phương thức này và các phương thức API khác (chẳng hạn như partners.devices.findByIdentifier) sẽ hỗ trợ kết quả được phân trang. Với kết quả được phân trang, ứng dụng của bạn có thể lặp lại yêu cầu và xử lý danh sách lớn trên từng trang một.

Sau khi gọi phương thức API, hãy kiểm tra xem phản hồi có chứa giá trị cho nextPageToken hay không. Nếu nextPageToken không phải là null, ứng dụng của bạn có thể sử dụng thành phần này để tìm nạp một trang thiết bị khác bằng cách gọi lại phương thức này. Bạn cần đặt giới hạn trên cho số lượng thiết bị trong tham số limit. Nếu nextPageTokennull, tức là ứng dụng của bạn đã yêu cầu trang cuối cùng.

Phương thức ví dụ bên dưới cho biết cách ứng dụng của bạn có thể in danh sách thiết bị, từng trang một:

Java

private static long MAX_PAGE_SIZE = 10;

// ...
/**
 * Demonstrates how to loop through paginated lists of devices.
 * @param pageToken       The token specifying which result page to return.
 * @throws IOException    If the zero-touch API call fails.
 */
private void printDevices(String pageToken) throws IOException {

  // Create the request body to find the customer's devices.
  FindDevicesByOwnerRequest body = new FindDevicesByOwnerRequest();
  body.setLimit(MAX_PAGE_SIZE);
  body.setSectionType("SECTION_TYPE_ZERO_TOUCH");
  body.setCustomerId(Collections.singletonList(targetCustomerId));

  // Call the API to get a page of Devices. Send a page token from the method
  // argument (might be None). If the page token is None, the API returns the first page.
  FindDevicesByOwnerResponse response =
      service.partners().devices().findByOwner(PARTNER_ID, body).execute();
  if (response.getDevices() == null) {
    return;
  }

  // Print the devices included in this page of results.
  for (Device device: response.getDevices()) {
    System.out.format("Device %s\n", device.getName());
  }
  System.out.println("---");

  // Check to see if another page of devices is available. If yes,
  // fetch and print the devices.
  if (response.getNextPageToken() != null) {
    this.printDevices(response.getNextPageToken());
  }
}

// ...
// Pass null to start printing the first page of devices.
printDevices(null);

.NET

private static int MaxPageSize = 10;

// ...
/// <summary>Demonstrates how to loop through paginated lists of devices.</summary>
/// <param name="pageToken">The token specifying which result page to return.</param>
private void PrintDevices(string pageToken)
{
    // Create the request body to find the customer's devices.
    FindDevicesByOwnerRequest body = new FindDevicesByOwnerRequest
    {
        PageToken = pageToken,
        Limit = MaxPageSize,
        SectionType = "SECTION_TYPE_ZERO_TOUCH",
        CustomerId = new List<long?>
        {
            targetCustomerId
        }
    };

    // Call the API to get a page of Devices. Send a page token from the method
    // argument (might be None). If the page token is None, the API returns the first page.
    var response = service.Partners.Devices.FindByOwner(body, PartnerId).Execute();
    if (response.Devices == null)
    {
        return;
    }

    // Print the devices included in this page of results.
    foreach (Device device in response.Devices)
    {
        Console.WriteLine("Device: {0}", device.Name);
    }
    Console.WriteLine("---");

    // Check to see if another page of devices is available. If yes,
    // fetch and print the devices.
    if (response.NextPageToken != null)
    {
        this.PrintDevices(response.NextPageToken);
    }
}

// ...
// Pass null to start printing the first page of devices.
PrintDevices(null);

Python

MAX_PAGE_SIZE = 10;

# ...
def print_devices(page_token):
  """Demonstrates how to loop through paginated lists of devices.

  Args:
    page_token: The token specifying which result page to return.
  """

   # Create the body to find the customer's devices.
  request_body = {'limit':MAX_PAGE_SIZE, \
    'pageToken':page_token, \
    'customerId':[target_customer_id], \
    'sectionType':'SECTION_TYPE_ZERO_TOUCH'}

  # Call the API to get a page of Devices. Send a page token from the method
  # argument (might be None). If the page token is None,
  # the API returns the first page.
  response = service.partners().devices().findByOwner(partnerId=PARTNER_ID,
    body=request_body).execute()

  # Print the devices included in this page of results.
  for device in response['devices']:
    print 'Device: {0}'.format(device['name'])
  print '---'

  # Check to see if another page of devices is available. If yes,
  # fetch and print the devices.
  if 'nextPageToken' in response:
    print_devices(response['nextPageToken'])

# ...
# Pass None to start printing the first page of devices.
print_devices(None);

Các bước tiếp theo

Bây giờ, bạn đã biết cách hoạt động của API, hãy xem các ví dụ hướng dẫn nhanh về Java, .NET hoặc Python.