借助 customer API,您可以通过编程控制设备和配置 Android 零触摸注册。本文档向企业移动管理 (EMM) 提供商和企业 IT 开发者介绍了此 API。阅读本文档后,您应该已经了解该 API 中使用的核心资源及其交互方式。如果您刚开始接触零触摸注册,请阅读简短的 android.com 简介。
概览
客户 API 可帮助购买 Android 零触摸注册设备的组织。您的应用或工具可以帮助 IT 管理员执行以下操作:
- 创建、修改和删除预配配置。
- 对设备应用或移除配置。
- 为以后添加到零触摸注册的所有设备选择默认配置。
通过该 API,IT 管理员还可以为设备取消注册零触摸注册。如需管理其组织的用户或接受服务条款,IT 管理员可使用零触摸注册门户。
此 API 的典型用户是:
- EMM 提供商在其控制台中添加了对零触摸注册的支持。
- 企业 IT 开发者可以打造用于自动执行零触摸注册任务的工具。
核心资源
配置和设备是您在 API 中使用的核心资源。组织还可以使用零触摸注册门户创建配置和设备。
- 配置
- IT 管理员使用配置来为设备设置配置选项。 配置包括 EMM 移动设备政策和联系信息,显示以帮助用户。配置是 API 的核心,因此可在许多方法中使用。如需了解详情,请参阅下面的配置。
- 设备
- 组织从其转销商处购买的支持零触摸注册的 Android 设备。应用配置以将设备包含在零触摸注册中。设备具有硬件 ID 和附加元数据。如需了解详情,请参阅下面的设备。
- 设备政策控制器 (DPC)
- 对 EMM 的 DPC(设备政策控制器)的只读引用。将 DPC 添加到配置中,以便为设备选择 EMM 解决方案。API 列出的所有 DPC 都支持零触摸注册,并且可以在 Google Play 中找到。如需了解详情,请参阅
Dpc
。
如需列出您的应用可以使用的所有 API 方法和资源,请参阅 API 参考文档。
配置
Configuration
API 资源包含以下各项:
- 设备上安装的 EMM 的 DPC。
- 已在设备上强制执行 EMM 政策。
- 设备上显示的联系信息,用于在设置过程中帮助用户。
通过使用 API,您的应用可以为 IT 管理员管理配置。调用该 API 以提取、创建、更新和删除配置。以下示例展示了如何创建新配置:
Java
// Add metadata to help the device user during provisioning. Configuration configuration = new Configuration(); configuration.setConfigurationName("Sales team"); configuration.setCompanyName("XYZ Corp."); configuration.setContactEmail("it-support@example.com"); configuration.setContactPhone("+1 (800) 555-0112"); configuration.setCustomMessage("We're setting up your phone. Call or email for help."); // Set the DPC that zero-touch enrollment downloads and installs from Google Play. configuration.setDpcResourcePath(dpc.getName()); // Set the JSON-formatted EMM provisioning extras that are passed to the DPC. configuration.setDpcExtras("{" + "\"android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED\":true," + "\"android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE\":{" + "\"default_min_password_length\":6," + "\"company_name\":\"XYZ Corp\"," + "\"management_server\":\"emm.example.com\"," + "\"terms_url\":\"https://www.example.com/policies/terms/\"," + "\"allowed_user_domains\":\"[\\\"example.com\\\", \\\"example.org\\\"]\"" + "}" + "}"); // Create the new configuration on the server. AndroidProvisioningPartner.Customers.Configurations.Create request = service.customers().configurations().create(customerAccount, configuration); Configuration response = request.execute();
.NET
// Add metadata to help the device user during provisioning. Configuration configuration = new Configuration { ConfigurationName = "Sales team", CompanyName = "XYZ Corp.", ContactEmail = "it-support@example.com", ContactPhone = "+1 (800) 555-0112", CustomMessage = "We're setting up your phone. Call or email for help." }; // Set the DPC that zero-touch enrollment downloads and installs from Google Play. configuration.DpcResourcePath = dpc.Name; // Set the JSON-formatted EMM provisioning extras that are passed to the DPC. configuration.DpcExtras = @"{ ""android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED"":true, ""android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE"":{ ""default_min_password_length"":6, ""company_name"":""XYZ Corp"", ""management_server"":""emm.example.com"", ""terms_url"":""https://www.example.com/policies/terms/"", ""allowed_user_domains"":""[\""example.com\"", \""example.org\""]"" } }"; // Create the new configuration on the server. var request = service.Customers.Configurations.Create(configuration, customerAccount); var response = request.Execute();
Python
# Add metadata to help the device user during provisioning. configuration = { 'configurationName': 'Sales team', 'companyName': 'XYZ Corp.', 'contactEmail': 'it-support@example.com', 'contactPhone': '+1 (800) 555-0112', 'customMessage': 'We\'re setting up your phone. Call or email for help.'} # Set the DPC that zero-touch enrollment installs from Google Play. configuration['dpcResourcePath'] = dpc['name'] # Set the JSON-formatted EMM provisioning extras that are passed to the DPC. configuration['dpcExtras'] = '''{ "android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED":true, "android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE":{ "default_min_password_length":6, "company_name":"XYZ Corp", "management_server":"emm.example.com", "terms_url":"https://www.example.com/policies/terms/", "allowed_user_domains":"[\\"example.com\\", \\"example.org\\"]"} }''' # Create the new configuration on the server. response = service.customers().configurations().create( parent=customer_account, body=configuration).execute()
使用 Patch API 更新配置时,请务必添加字段掩码,或者为您不希望为 null
的每个字段添加相应的值。有关说明如何高效更新配置的示例,请参阅下文的默认配置。
删除配置
如果某个配置仍应用于设备,则无法删除该配置。如果您尝试删除使用中的配置,该 API 方法会返回 HTTP 400 Bad Request
状态代码以及说明有多少设备使用了该配置的消息。请先调用 customers.devices.removeConfiguration
从设备中移除配置,然后重试。
默认配置
当组织设置默认配置并将其应用于其购买的任何新设备时,零触摸注册效果最佳。如果未设置默认配置,请考虑提示 IT 管理员设置默认配置。
以下示例展示了如何通过将 isDefault
设置为 true
来将现有配置设为默认配置:
Java
// Send minimal data with the request. Just the 2 required fields. // targetConfiguration is an existing configuration that we want to make the default. Configuration configuration = new Configuration(); configuration.setIsDefault(true); configuration.setConfigurationId(targetConfiguration.getConfigurationId()); // Call the API, including the FieldMask to avoid setting other fields to null. AndroidProvisioningPartner.Customers.Configurations.Patch request = service .customers() .configurations() .patch(targetConfiguration.getName(), configuration); request.setUpdateMask("isDefault"); Configuration results = request.execute();
.NET
// Send minimal data with the request. Just the 2 required fields. // targetConfiguration is an existing configuration that we want to make the default. Configuration configuration = new Configuration { IsDefault = true, ConfigurationId = targetConfiguration.ConfigurationId, }; // Call the API, including the FieldMask to avoid setting other fields to null. var request = service.Customers.Configurations.Patch(configuration, targetConfiguration.Name); request.UpdateMask = "IsDefault"; Configuration results = request.Execute();
Python
# Send minimal data with the request. Just the 2 required fields. # target_configuration is an existing configuration we'll make the default. configuration = { 'isDefault': True, 'configurationId': target_configuration['configurationId']} # Call the API, including the FieldMask to avoid setting other fields to null. response = service.customers().configurations().patch( name=target_configuration['name'], body=configuration, updateMask='isDefault').execute()
只能有一个默认配置。如果创建新的默认配置,则会将先前配置的 isDefault
字段设置为 false
。您可能需要刷新任何缓存的 Configuration
实例才能看到 isDefault
字段中的正确值。
向导设备用户
零触摸配置会在设备设置向导中显示自定义用户指南,以帮助用户。您需要在配置中包含联系人电话号码和电子邮件地址,以及管理设备的组织的名称。我们还建议在 customMessage
字段中添加一两个句子,以提供有关用户设备所发生情况的更多详细信息。
由于用户无法通过正在设置的设备拨打电话或发送电子邮件,因此请设置电话号码和电子邮件地址的格式,以便于浏览信息。
设备
客户在购买设备以进行零触摸注册时,转销商会创建设备 - IT 管理员无法创建设备。如需使用设备,请对 Device
API 资源调用方法。如果您需要搜索设备,请在应用中列出所有设备并在本地过滤每个批次。有关示例,请参阅下面的分页结果。
配置设备
将配置应用于设备,即可为设备注册零触摸注册。如需应用配置,请调用 customers.devices.applyConfiguration
。应用配置后,设备会在首次启动或下次恢复出厂设置时自动进行预配。以下示例展示了如何将配置应用于一组设备:
Java
List<Device> devices = getDevicesToConfigure(service); Configuration configurationToApply = getConfigurationToApply(service); // Loop through the collection and apply the configuration to each device. This might // take some time if the collection contains many devices. for (Device device : devices) { System.out.println(device.getDeviceIdentifier().getImei()); // Wrap the device ID in a DeviceReference. DeviceReference deviceRef = new DeviceReference(); deviceRef.setDeviceId(device.getDeviceId()); // Build and send the request to the API. CustomerApplyConfigurationRequest body = new CustomerApplyConfigurationRequest(); body.setConfiguration(configurationToApply.getName()); body.setDevice(deviceRef); AndroidProvisioningPartner.Customers.Devices.ApplyConfiguration request = service .customers() .devices() .applyConfiguration(customerAccount, body); request.execute(); }
.NET
IList<Device> devices = GetDevicesToConfigure(service); Configuration configurationToApply = GetConfigurationToApply(service); // Loop through the collection and apply the configuration to each device. This might // take some time if the collection contains many devices. foreach (Device device in devices) { Console.WriteLine(device.DeviceIdentifier.Imei); // Wrap the device ID in a DeviceReference. var deviceRef = new DeviceReference { DeviceId = device.DeviceId }; // Build and send the request to the API. CustomerApplyConfigurationRequest body = new CustomerApplyConfigurationRequest { Configuration = configurationToApply.Name, Device = deviceRef }; var request = service.Customers.Devices.ApplyConfiguration(body, customerAccount); request.Execute(); }
Python
devices = get_devices_to_configure(service) configuration = get_configuration_to_apply(service) # Loop through the collection and apply the configuration to each device. # This might take some time if the collection contains many devices. for device in devices: print(device['deviceIdentifier']['imei']) # Wrap the device ID in a DeviceReference. device_ref = {'deviceId': device['deviceId']} # Build and send the request to the API. body = {'configuration': configuration['name'], 'device': device_ref} service.customers().devices().applyConfiguration( parent=customer_account, body=body).execute()
如需从设备中移除配置,请调用 customers.devices.removeConfiguration
。此更改将在设备恢复出厂设置后生效。
取消声明设备所有权
IT 管理员可以取消对设备的所有权,从而将其从零触摸注册中移除。IT 管理员可能取消对要迁移到其他帐号、出售或退还给转销商的设备的所有权。调用 customers.devices.unclaim
方法,向组织取消声明对设备的所有权。
以下示例展示了如何通过 IMEI 识别码和制造商名称取消声明设备:
Java
// Wrap the hardware ID and manufacturer values in a DeviceIdentifier. // Then wrap the DeviceIdentifier in a DeviceReference. DeviceIdentifier identifier = new DeviceIdentifier(); identifier.setImei("123456789012347"); identifier.setManufacturer("Google"); DeviceReference reference = new DeviceReference(); reference.setDeviceIdentifier(identifier); // Create the body of the request. CustomerUnclaimDeviceRequest body = new CustomerUnclaimDeviceRequest(); body.setDevice(reference); // Call the API method to unclaim the device from the organization. service.customers().devices().unclaim(customerAccount, body).execute();
.NET
// Wrap the hardware ID and manufacturer values in a DeviceIdentifier. // Then wrap the DeviceIdentifier in a DeviceReference. DeviceIdentifier identifier = new DeviceIdentifier { Imei = "123456789012347", Manufacturer = "Google" }; DeviceReference reference = new DeviceReference(); reference.DeviceIdentifier = identifier; // Create the body of the request. CustomerUnclaimDeviceRequest body = new CustomerUnclaimDeviceRequest(); body.Device = reference; // Call the API method to unclaim the device from the organization. service.Customers.Devices.Unclaim(body, customerAccount).Execute();
Python
# Wrap the hardware ID and manufacturer values in a DeviceIdentifier. # Then wrap the DeviceIdentifier in a DeviceReference. identifier = {'imei': '123456789012347', 'manufacturer': 'Google'} reference = {'deviceIdentifier': identifier} # Create the body of the request. body = {'device': reference} # Call the API method to unclaim the device from the organization. service.customers().devices().unclaim( parent=customer_account, body=body).execute()
设备元数据
IT 管理员可以查看转销商为设备附加的元数据。在您的应用中显示此设备元数据,以帮助 IT 管理员识别设备。
如需详细了解您可能会看到的元数据,请参阅面向转销商的设备元数据指南。
分页结果
customers.devices.list
API 方法可能会返回非常大的设备列表。为了减小响应大小,此方法和其他 API 方法(如 customers.list
)支持分页结果。通过分页结果,您的应用可以迭代方式请求和处理大型列表,一次一页。
调用 API 方法后,检查响应是否包含 nextPageToken
的值。如果 nextPageToken
不是 null
,您的应用可以通过再次调用该方法,使用它来提取设备的另一页。您需要在 pageSize
参数中设置设备数量上限。如果 nextPageToken
为 null
,则表示您的应用请求了最后一个页面。
以下示例方法展示了您的应用如何才能逐页输出设备列表:
Java
private void printDevices(AndroidProvisioningPartner service, String customerAccount, String pageToken) throws IOException { // Call the API to get a page of Devices. Send a page token from the method argument. // If the page token is null, the API returns the first page. AndroidProvisioningPartner.Customers.Devices.List request = service.customers().devices().list(customerAccount); request.setPageSize(50L); request.setPageToken(pageToken); CustomerListDevicesResponse response = request.execute(); // 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 & print the devices. if (response.getNextPageToken() != null) { this.printDevices(service, customerAccount, response.getNextPageToken()); } }
.NET
private void PrintDevices(AndroidProvisioningPartnerService service, String customerAccount, String pageToken) { // Call the API to get a page of Devices. Send a page token from the method argument. // If the page token is null, the API returns the first page. var request = service.Customers.Devices.List(customerAccount); request.PageSize = 50; request.PageToken = pageToken; var response = request.Execute(); // 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(service, customerAccount, response.NextPageToken); } }
Python
def print_devices(service, customer_account, page_token): """Demonstrates how to loop through paginated lists of devices.""" # Call the API to get a page of Devices. Send a page token from the method # argument. If the page token is None, the API returns the first page. response = service.customers().devices().list( parent=customer_account, pageSize=50, pageToken=page_token).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(service, customer_account, response['nextPageToken'])
开始使用
接下来,请阅读授权以了解如何对 API 调用进行授权。如果您想探索这些 API,请查看 Java、.NET 和 Python 快速入门指南。您可以使用 Colab 查看 API 调用示例,并尝试自行调用 API。