仕組み

Customer API を使用すると、デバイスと Android ゼロタッチ登録の設定をプログラムで制御できます。このドキュメントでは、企業向けモバイル管理(EMM)プロバイダと企業の IT デベロッパーに API を紹介します。このドキュメントを読むと、API で使用されるコアリソースと、それらの相互作用を理解できるようになります。ゼロタッチ登録を初めて行う場合は、android.com の概要をご覧ください。

概要

Customer API は、組織が Android ゼロタッチ登録デバイスを購入する際に役立ちます。IT 管理者はアプリまたはツールを利用して次のことを行えます。

  • プロビジョニング構成の作成、編集、削除。
  • デバイスに設定を適用または削除します。
  • 今後ゼロタッチ登録に追加するデバイスのデフォルト設定を選択します。

IT 管理者は API を使用して、ゼロタッチ登録からデバイスの登録を解除することもできます。IT 管理者は、組織のユーザーを管理する場合、または利用規約に同意するために、ゼロタッチ登録のポータルを使用します。

この API の一般的なユーザーは次のとおりです。

  • コンソールへのゼロタッチ登録のサポートを追加する EMM プロバイダ
  • ゼロタッチ登録のタスクを自動化するツールを作成する企業の IT デベロッパー。

コアリソース

構成とデバイスは、API で使用するコアリソースです。また、ゼロタッチ登録ポータルを使用して構成とデバイスを作成することもできます。

デバイスと顧客リソースの関係

設定
IT 管理者は、設定を使用してデバイスのプロビジョニング オプションを設定します。 構成には、ユーザーをサポートするために表示される EMM モバイル ポリシーと連絡先情報が含まれます。構成は API の中心となるため、さまざまなメソッドで使用できます。詳細については、後述の構成をご覧ください。
デバイス
組織が販売パートナーから購入したゼロタッチ登録対応の Android デバイス。ゼロタッチ登録にデバイスを含める設定を適用します。デバイスには、ハードウェア ID とアタッチされたメタデータがあります。詳細については、以下のデバイスをご覧ください。
DPC
EMM の DPC(Device Policy Controller)への読み取り専用の参照。設定に 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()

デフォルト構成は 1 つだけ設定できます。新しいデフォルト構成を作成すると、以前の構成の isDefault フィールドが false に設定されます。isDefault フィールドに正しい値が表示されるように、キャッシュに保存された Configuration インスタンスの更新が必要になる場合があります。

デバイスのユーザーに案内する

ゼロタッチ設定では、デバイス設定ウィザードに、カスタマイズされたユーザー ガイダンスが表示され、ユーザーをサポートします。設定には、連絡先の電話番号とメールアドレスと、デバイスを管理する組織の名前を含める必要があります。また、customMessage フィールドに 1 つまたは 2 つの文を含めて、ユーザーのデバイスで何が起こっているかをより詳細に把握することもおすすめします。

ユーザーは、セットアップしているデバイスから通話やメールを受け取れないため、情報をひと目でわかるように電話番号とメールアドレスの形式にします。

デバイス

お客様がゼロタッチ登録用にデバイスを購入したときに、販売パートナーがデバイスを作成します。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 など)はページングされた結果をサポートしています。ページングされた結果を使用すると、アプリは大規模なリストを 1 ページずつ反復的にリクエストして処理できます。

API メソッドを呼び出した後、レスポンスに nextPageToken の値が含まれているかどうかを確認します。nextPageTokennull でない場合、アプリはこのメソッドを再度呼び出すことで、デバイスの別のページをフェッチできます。pageSize パラメータでデバイス数の上限を設定する必要があります。nextPageTokennull の場合、アプリは最後のページをリクエストしています。

以下のメソッドの例は、アプリがデバイスのリストを 1 ページずつ出力する方法を示しています。

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.NETPython のクイックスタート ガイドをご覧ください。Colab を使用して API 呼び出しの例を確認し、自分で API の呼び出しを試すことができます。