使用方法

简介

零触摸注册 API 可帮助设备转销商实现集成自动化。 贵组织的销售工具可内置“零触摸注册”机制, 从而提升客户的工作效率使用此 API 帮助您的用户:

  • 将购买的设备分配给客户的零触摸注册账号。
  • 为您的客户创建零触摸注册账号。
  • 将贵组织的电话号码和订单元数据附加到设备上。
  • 针对分配给客户的设备创建报告。

本文档介绍了此 API 并介绍了这些模式。如果您想 尝试查看 API 的快速入门 Java.NETPython

API 概念

客户和设备是您在该 API 中使用的核心资源。要创建 请致电 create。您可以创建设备 (请参阅下文)。贵组织还可以 通过零触摸注册门户创建客户和设备。

设备和客户资源之间的关系

客户
贵组织出售设备的公司。客户有nameID。当您想要领取客户设备或寻找他们的设备时,请与其联系。接收者 如需了解详情,请参阅 Customer
设备
贵组织的支持零触摸注册的 Android 或 ChromeOS 设备 销售给客户设备具有硬件 ID、元数据和客户信息 声明。设备是 API 的核心,因此你几乎可以在 方法。如需了解详情,请参阅 Device
设备标识符
封装硬件 ID,例如 IMEI 或 MEID,以标识制造 设备。使用 DeviceIdentifier 定位设备 您想要查找、更新或声明的资源。如需了解详情,请参阅 标识符
DeviceMetadata
存储设备的元数据的键值对。使用 DeviceMetadata(用于存储贵组织的元数据)。接收者 如需了解详情,请参阅设备元数据

如需列出您的应用可以使用的所有 API 方法和资源,请参阅 API 参考文档

创建客户

对于 Android 设备,转销商负责创建客户 账号。客户将使用此账号执行以下操作: 访问零触摸门户以配置其配置设置 设备。对于已在安装 Google 软件的 ChromeOS 设备,则无需执行此操作 Workspace 账号,他们将使用此账号来配置配置设置。

您可以调用 create API 方法来创建 客户账号进行零触摸注册。因为客户会看到 公司名称,那么应用用户应 确认其正确无误。客户名称一经创建,便无法修改 客户。

您需要加入至少一个公司电子邮件地址, Google 账号。您无法将个人 Gmail 账号用于 API。如果客户需要关联账号方面的帮助,请发送 说明 关联 Google 账号

通过调用该 API 创建客户后,客户负责管理其员工的 您无法修改客户的用户使用 API代码段 创建客户的方法如下所示:

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()

如需详细了解客户员工的所有者和管理员角色, 请参阅门户用户

为客户认领设备

客户购买设备后,需要配置配置 可在其账号中为这些设备配置的设置认领设备即会添加该设备 并让客户能够配置 配置设置。

设备的配置记录中包含零触摸注册部分。您 通过声明对该记录的零触摸注册部分的所有权来分配该设备 客户。调用 partners.devices.claimpartners.devices.claimAsync 方法(带有 customer 作为参数。始终提供 SECTION_TYPE_ZERO_TOUCH 作为 sectionType

您需要取消对客户设备的所有权(请参阅下文),然后才能取消对客户设备的所有权 为不同的客户认领相同的设备。版权主张方法 验证 DeviceIdentifier 字段, 包括 IMEI 或 MEID 或序列号, 制造商名称和型号,以及 经过认证的设备 ID(在创建新设备时)。

以下代码段展示了如何声明设备所有权:

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()

取消声明设备所有权

贵组织可以取消对客户设备的声明。取消声明设备所有权 会将其从“零触摸注册”中移除。转销商可能会取消声明存在以下情况的设备 他们希望迁移到其他账号、被退回或者被错误声明的账号。 调用 partners.devices.unclaim 方法或 partners.devices.unclaimAsync即可取消声明对 获取客户的设备

供应商

您可以使用供应商来代表您的经销商联盟(本地)中的转销商合作伙伴 全球转销商网络中的运营商,或者销售 设备。供应商可帮助您区分用户、客户和 设备:

  • 您创建的供应商无法查看您的零触摸注册账号,也无法查看您的每个注册账号 其他用户的账号。
  • 您可以查看供应商的客户和设备,也可以取消注册 供应商的设备不过,您无法将设备分配给供应商的 客户。

使用该门户网站为您的创建供应商 组织 - 您无法使用该 API。您的账号角色必须是 Owner,用于创建新供应商。如果贵组织有供应商 您可以调用 partners.vendors.list 列出您的 和partners.vendors.customers.list 。以下示例使用了这两种方法 输出显示供应商服务条款状态的 客户:

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'])

如果您有一系列设备,则可能需要知道是哪家转销商或 供应商认领了该设备。要获取数字形式的转销商 ID,请检查 设备保修记录中的 resellerId 字段。

贵组织可以取消对供应商声明的设备的所有权。对于其他 API 调用 修改设备,则应检查贵组织是否已认领该设备 然后再调用 API 方法。以下示例展示了如何执行此操作:

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

长时间运行的批量操作

该 API 包含异步版本的设备方法。 这些方法允许批处理许多设备,而同步 方法针对每个 API 请求处理一台设备。异步方法名称 具有 Async 后缀,例如 claimAsync

异步 API 方法会在处理完成之前返回一个结果。 异步方法还有助于您的应用(或工具) 等待长时间运行的操作完成的用户。您的应用应 定期检查操作状态。

操作

您可以使用 Operation 来跟踪长时间运行的批量操作。答 成功调用异步方法将返回对相应操作的引用 。以下 JSON 代码段显示了调用 updateMetadataAsync:

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

每项操作都包含一系列单独的任务。致电 operations.get,即可了解状态信息和 操作中包含的任务的结果。以下代码段展示了如何 可以执行此操作。在您自己的应用中,您需要处理所有错误。

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()

如需了解某项操作是否完成,请检查操作是否有 done 字段 值为 true。如果 done 缺失或 false,操作仍会进行 。

响应

操作完成后,API 会使用结果更新操作,即使 如果所有任务都成功或都没有成功,则会发生此错误。response 字段是 DevicesLongRunningOperationResponse 对象详细说明操作中每个设备的处理。

检查 successCount 字段以高效了解是否有任何任务失败并 请避免遍历较大的结果列表。此 API 中的 perDeviceStatus 字段 DevicesLongRunningOperationResponse是一个列表 OperationPerDevice 个实例,详细说明了以下类别中的每台设备: 操作。列表顺序与原始请求中的任务匹配。

每项 OperationPerDevice 任务都包含一个 result 字段和一个提醒摘要 。检查任务是成功还是失败 result 字段。

下面的 JSON 代码段显示了在 对 updateMetadataAsync 的调用:

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

跟踪进度

如果您的应用需要跟踪进度,您应该定期重新获取 操作。metadata 字段包含 DevicesLongRunningOperationMetadata 实例来帮助您的应用检查正在运行的操作的最新进度。使用 下面列出的 DevicesLongRunningOperationMetadata 字段 表来跟踪操作进度:

字段 典型用途
processingStatus 从“BATCH_PROCESS_PENDING”更改为“ BATCH_PROCESS_IN_PROGRESS,然后切换到 BATCH_PROCESS_PROCESSED
progress 已处理的更新所占的百分比。您的应用可以使用 以估算完成时间。因为 progress 值可以是 100, 请检查操作的 done 字段, 已完成并产生结果。
devicesCount 显示操作中的更新数量。这个 可能不同于 请求。

下面的简化示例展示了应用如何使用进度元数据 设置轮询间隔。在您的应用中,您可能需要更复杂的任务 用于轮询的运行程序。您还需要添加错误处理功能。

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)

选择对应用用户有意义的轮询方法。部分应用用户 可能受益于定期更新进度 。

分页结果

partners.devices.findByOwner API 方法 可能会返回非常庞大的设备列表。为了减小响应大小, 其他 API 方法(例如 partners.devices.findByIdentifier) 支持分页结果。利用分页结果,您的应用可以 一次一页请求和处理大型列表。

调用 API 方法后,检查响应是否包含 nextPageToken。如果nextPageToken 不是 null,您的应用可以通过调用它来使用它获取另一页面设备 方法。您需要设置 limit 参数。如果 nextPageTokennull,则说明您的应用已请求 最后一页。

以下示例方法展示了您的应用可能如何输出设备列表, 每次加载网页:

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);

后续步骤

现在,您已经了解了 API 的工作原理,通过快速入门,试用示例 Java.NETPython