작동 방식

고객 API는 Android 제로터치 등록을 위한 기기 및 구성을 프로그래매틱 방식으로 제어할 수 있는 기능을 제공합니다. 이 문서에서는 엔터프라이즈 모바일 관리 (EMM) 제공업체와 엔터프라이즈 IT 개발자에게 API를 소개합니다. 이 문서를 읽은 후에는 API에 사용되는 핵심 리소스와 이러한 리소스가 상호작용하는 방식을 이해해야 합니다. 제로터치 등록을 처음 사용한다면 간단한 android.com 소개를 읽어보세요.

 개요

고객 API는 Android 제로터치 등록 기기를 구매하는 조직에 도움이 됩니다. 앱이나 도구를 사용하면 IT 관리자는 다음 작업을 할 수 있습니다.

  • 프로비저닝 구성을 생성, 수정, 삭제합니다.
  • 기기에 구성을 적용하거나 삭제합니다.
  • 향후 제로터치 등록에 추가되는 모든 기기의 기본 구성을 선택합니다.

IT 관리자는 API를 통해 기기의 제로터치 등록을 취소할 수도 있습니다. 조직의 사용자를 관리하거나 서비스 약관에 동의하기 위해 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()

패치 API를 사용하여 구성을 업데이트할 때는 필드 마스크(또는 null로 설정하지 않으려는 모든 필드의 값)를 포함해야 합니다. 구성을 효율적으로 업데이트하는 방법을 보여주는 예는 아래의 기본 구성을 참고하세요.

구성 삭제

기기에 아직 적용 중인 구성은 삭제할 수 없습니다. 사용 중인 구성을 삭제하려고 하면 API 메서드가 HTTP 400 Bad Request 상태 코드와 이 구성을 사용하는 기기 수를 설명하는 메시지를 반환합니다. customers.devices.removeConfiguration를 호출하여 기기에서 구성을 삭제한 후 다시 시도하세요.

기본 구성

제로터치 등록은 조직에서 구매하는 모든 새 기기에 적용되는 기본 구성을 설정할 때 가장 잘 작동합니다. 기본 구성이 설정되지 않은 경우 IT 관리자에게 기본 구성을 설정하라는 메시지를 표시하는 것이 좋습니다. 아래 예는 isDefaulttrue로 설정하여 기존 구성을 기본값으로 만드는 방법을 보여줍니다.

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로 설정합니다. isDefault 필드의 올바른 값을 보려면 캐시된 Configuration 인스턴스를 새로고침해야 할 수 있습니다.

기기 사용자 안내

제로터치 구성은 사용자를 돕기 위해 기기 설정 마법사에 맞춤설정된 사용자 안내를 표시합니다. 구성에서 기기를 관리하는 조직의 이름과 함께 연락처 전화번호, 이메일 주소를 포함해야 합니다. 또한 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 값이 포함되어 있는지 확인합니다. nextPageTokennull이 아니면 앱은 메서드를 다시 호출하여 다른 기기 페이지를 가져오는 데 사용할 수 있습니다. pageSize 매개변수의 기기 수의 상한값을 설정해야 합니다. nextPageTokennull이면 앱이 마지막 페이지를 요청한 것입니다.

아래의 메서드 예는 앱이 기기 목록을 한 번에 한 페이지씩 출력하는 방법을 보여줍니다.

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를 살펴보려면 자바, .NET, Python의 빠른 시작 가이드를 참조하세요. Colab을 사용하여 API 호출의 예를 확인하고 API를 직접 호출하여 실험할 수 있습니다.