Jak to działa

Wstęp

Interfejs API rejestracji typu zero-touch pomaga sprzedawcom urządzeń zautomatyzować integrację. Narzędzia sprzedażowe w Twojej organizacji mogą zostać zintegrowane z rejestracją typu zero-touch, zwiększając w ten sposób wydajność Twoich użytkowników i klientów. Używaj interfejsu API, aby pomagać użytkownikom:

  • Przypisz kupione urządzenia do konta rejestracji typu zero-touch klienta.
  • Utwórz konto rejestracji typu zero-touch dla klienta.
  • Dołącz do urządzeń metadane dotyczące numerów telefonów i zamówień organizacji.
  • Twórz raporty o urządzeniach przypisanych do klientów.

Ten dokument stanowi wprowadzenie do interfejsu API i wyjaśnia występujące w nim wzorce. Jeśli chcesz samodzielnie poznać interfejs API, skorzystaj z krótkiego wprowadzenia do Java, .NET lub Pythona.

Pojęcia związane z interfejsami API

Interfejs API to podstawowe zasoby obejmujące klientów i urządzenia. Aby utworzyć klientów, zadzwoń pod numer create. Możesz tworzyć urządzenia za pomocą metod interfejsu API deklaracji (patrz niżej). Twoja organizacja może też tworzyć klientów i urządzenia za pomocą portalu do rejestracji typu zero-touch.

Relacja między urządzeniem a klientem

Klient
Firmy, którym Twoja organizacja sprzedaje urządzenia. Klienci mają właściwości name i ID. Użyj konta klienta, gdy chcesz zgłosić własność lub znaleźć jego urządzenia. Więcej informacji: Customer.
Urządzenie
urządzenie z Androidem lub ChromeOS sprzedawane przez Twoją organizację i obsługujące rejestrację typu zero-touch. Urządzenia mają identyfikatory sprzętu, metadane i roszczenia klientów. Urządzenia stanowią centralny element interfejsu API, więc można ich używać w niemal wszystkich metodach. Więcej informacji: Device.
DeviceIdentifier
Zawiera identyfikatory sprzętowe (np. IMEI lub MEID), aby umożliwić identyfikację wyprodukowanego urządzenia. Użyj DeviceIdentifier, aby ustawić kierowanie na urządzenie, które chcesz znaleźć, zaktualizować lub zgłosić do niego prawa. Więcej informacji znajdziesz w artykule Identyfikatory.
DeviceMetadata
Przechowuje pary klucz-wartość metadanych dla urządzenia. Przechowuj metadane organizacji w DeviceMetadata. Więcej informacji znajdziesz w artykule Metadane urządzenia.

Listę wszystkich metod i zasobów interfejsu API, z których może korzystać Twoja aplikacja, znajdziesz w dokumentacji interfejsu API.

Tworzenie klientów

W przypadku urządzeń z Androidem sprzedawca odpowiada za utworzenie konta klienta w imieniu klienta. Klient będzie używać tego konta, aby uzyskać dostęp do portalu rejestracji typu zero-touch, aby skonfigurować ustawienia obsługi administracyjnej urządzeń. Nie jest to konieczne w przypadku urządzeń z ChromeOS, które mają już konto Google Workspace, za pomocą którego będą konfigurować ustawienia obsługi administracyjnej.

Aby utworzyć konta klientów na potrzeby rejestracji typu zero-touch, możesz wywołać metodę interfejsu API create. Klienci widzą nazwę firmy w portalu rejestracji typu zero-touch, więc użytkownik aplikacji powinien potwierdzić, że jest prawidłowa. Po utworzeniu klienta nie możesz już zmienić jego nazwy.

Aby zostać właścicielem, musisz podać co najmniej jeden firmowy adres e-mail powiązany z kontem Google. Przez interfejs API nie można używać osobistych kont Gmail. Jeśli klient potrzebuje pomocy w powiązaniu konta, wyślij instrukcje podane w artykule Przypisywanie konta Google.

Gdy utworzysz klienta za pomocą interfejsu API, będzie on zarządzać dostępem swoich pracowników do portalu – nie możesz edytować użytkowników klientów za pomocą interfejsu API. Fragment kodu poniżej pokazuje, jak możesz utworzyć klienta:

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

Więcej informacji o rolach właściciela i administratora pracowników klienta znajdziesz w artykule Użytkownicy portalu.

Zarezerwuj urządzenia dla klientów

Po zakupie urządzeń klienci powinni skonfigurować dla nich ustawienia obsługi administracyjnej na swoich kontach. Zarezerwowanie urządzenia powoduje dodanie go do rejestracji typu zero-touch i umożliwia klientowi skonfigurowanie ustawień obsługi administracyjnej.

Rekord obsługi administracyjnej urządzenia zawiera sekcję rejestracji typu zero-touch. Aby przypisać urządzenie, zarezerwuj dla klienta sekcję rejestracji typu zero-touch dla rekordu. Wywołaj metody partners.devices.claim lub partners.devices.claimAsync, podając klienta jako argument. Zawsze podawaj SECTION_TYPE_ZERO_TOUCH jako wartość parametru sectionType.

Aby móc zarezerwować to samo urządzenie dla innego klienta, musisz najpierw cofnąć rezerwację tego urządzenia (patrz poniżej). Podczas tworzenia nowego urządzenia podczas tworzenia nowego urządzenia validate pola DeviceIdentifier, w tym numer IMEI lub MEID lub numer seryjny, nazwę producenta i model oraz poświadczony identyfikator urządzenia z ChromeOS.

Ten fragment kodu pokazuje, jak zgłosić własność urządzenia:

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

Usuwanie rezerwacji urządzeń

Twoja organizacja może usunąć rezerwację urządzenia od klienta. Gdy cofniesz rezerwację urządzenia, zostanie ono usunięte z rejestracji typu zero-touch. Sprzedawca może wycofać rezerwację urządzenia, które chce przenieść na inne konto, zwrócić lub zostało zgłoszone przez pomyłkę. Wywołaj metodę partners.devices.unclaim lub partners.devices.unclaimAsync, aby wycofać rezerwację urządzenia od klienta.

Dostawcy

Możesz ich używać do reprezentowania partnerów sprzedawców w sieci salonów samochodowych, lokalnych operatorów w globalnej sieci sprzedawców lub dowolnej organizacji, która sprzedaje urządzenia w Twoim imieniu. Dostawcy pomagają rozdzielić użytkowników, klientów i urządzenia:

  • Tworząc przez Ciebie dostawcy, nie widzą Twojego konta rejestracji typu zero-touch ani kont innych użytkowników.
  • Możesz wyświetlać klientów i urządzenia dostawców oraz wyrejestrowywać urządzenia dostawców. Nie możesz jednak przypisywać urządzeń do klientów dostawców.

Na portalu możesz utworzyć dostawców dla swojej organizacji – nie możesz korzystać z interfejsu API. Aby można było utworzyć nowego dostawcę, musisz mieć na koncie rolę Właściciel. Jeśli Twoja organizacja ma dostawców, możesz wywołać metodę partners.vendors.list, aby wyświetlić listę dostawców, oraz metodę partners.vendors.customers.list, aby pozyskać klientów dostawcy. Poniższy przykład pokazuje wykorzystanie obu tych metod do wydrukowania raportu zawierającego stan Warunków korzystania z usługi dla klientów dostawców:

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

Jeśli masz kolekcję urządzeń, warto wiedzieć, który sprzedawca lub dostawca odebrał urządzenie. Aby uzyskać numeryczny identyfikator sprzedawcy, sprawdź wartość pola resellerId w rejestrze roszczenia urządzenia.

Twoja organizacja może wycofać rezerwację urządzenia objętego roszczeniem przez dostawcę. W przypadku innych wywołań interfejsu API, które modyfikują urządzenia, przed wywołaniem metody interfejsu API sprawdź, czy organizacja zarezerwowała urządzenie. Aby to zrobić:

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

Długo trwające operacje wsadowe

Interfejs API zawiera asynchroniczne wersje metod urządzeń. Metody te umożliwiają przetwarzanie wsadowe wielu urządzeń, a metody synchroniczne przetwarzają każde żądanie do interfejsu API po jednym urządzeniu. Nazwy metod asynchronicznych mają sufiks asynchroniczny, na przykład claimAsync.

Asynchroniczne metody interfejsu API zwracają wynik przed zakończeniem przetwarzania. Metody asynchroniczne pomagają też aplikacji (lub narzędziu) zachować reagowanie na działania użytkowników w czasie, gdy oczekują na zakończenie długotrwałej operacji. Aplikacja powinna okresowo sprawdzać stan operacji.

Operacje

Operation służy do śledzenia długo trwającej operacji zbiorczej. Skuteczne wywołanie metody asynchronicznej zwraca odwołanie do operacji w odpowiedzi. Poniższy fragment kodu JSON pokazuje typową odpowiedź po wywołaniu updateMetadataAsync:

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

Każda operacja zawiera listę poszczególnych zadań. Wywołaj operations.get, aby uzyskać informacje o stanie i wynikach zadań zawartych w operacji. Poniższy fragment kodu pokazuje, jak to można zrobić. Wszystkie błędy musisz naprawić we własnej aplikacji.

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

Aby dowiedzieć się, czy operacja została zakończona, sprawdź ją na polu done z wartością true. Jeśli brakuje done lub false, operacja jest nadal wykonywana.

Odpowiedzi

Po zakończeniu operacji interfejs API aktualizuje ją o jej wynik, nawet jeśli nie udało się wykonać wszystkich zadań lub nie wykonać żadnego działania. Pole response jest obiektem DevicesLongRunningOperationResponse, który określa przetwarzanie każdego urządzenia w ramach operacji.

Zbadaj pole successCount, aby skutecznie sprawdzić, czy jakieś zadanie się nie udało, i uniknąć iteracji z użyciem obszernych list wyników. Pole perDeviceStatus obiektu DevicesLongRunningOperationResponse zawiera listę instancji OperationPerDevice zawierających szczegółowe informacje o poszczególnych urządzeniach w ramach operacji. Kolejność na liście odpowiada zadaniom w pierwotnym żądaniu.

Każde zadanie OperationPerDevice zawiera pole result i przypomnienie z podsumowaniem żądania otrzymanego przez serwer. Sprawdź w polu result, czy udało się wykonać zadanie.

Poniższy fragment kodu JSON pokazuje część typowej odpowiedzi z operacji po wywołaniu funkcji updateMetadataAsync:

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

Śledź postęp

Jeśli aplikacja musi śledzić postęp, należy co jakiś czas ponownie pobierać operację. Pole metadata zawiera instancję DevicesLongRunningOperationMetadata, która ułatwia aplikacji sprawdzanie najnowszego postępu uruchomionej operacji. Aby śledzić postęp operacji, użyj pól DevicesLongRunningOperationMetadata wymienionych w tej tabeli:

Pole Typowe zastosowanie
processingStatus Zmienia się z BATCH_PROCESS_PENDING na BATCH_PROCESS_IN_PROGRESS, a w miarę postępów operacji na BATCH_PROCESS_PROCESSED.
progress Odsetek przetworzonych aktualizacji. Na podstawie tych informacji Twoja aplikacja może oszacować czas zakończenia. Ze względu na to, że podczas kończenia operacji wartość progress może wynosić 100, dlatego sprawdź w polu done działanie, czy operacja została zakończona i przyniosła oczekiwany rezultat.
devicesCount Pokazuje liczbę aktualizacji w ramach operacji. Ta wartość może różnić się od liczby aktualizacji w żądaniu, jeśli interfejs API nie może przeanalizować niektórych aktualizacji.

Poniżej znajdziesz uproszczony przykład pokazujący, jak aplikacja może używać metadanych postępu do ustawiania interwałów odpytywania. W aplikacji możesz potrzebować bardziej zaawansowanego mechanizmu uruchamiania zadań do odpytywania. Musisz też dodać obsługę błędów.

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)

Wybierz metodę ankietowania odpowiednią dla użytkowników Twojej aplikacji. Niektórzy użytkownicy aplikacji mogą korzystać z regularnych aktualizacji, gdy oczekują na zakończenie procesu.

Wyniki podzielone na strony

Metoda partners.devices.findByOwner API może zwracać bardzo duże listy urządzeń. Aby zmniejszyć rozmiar odpowiedzi, ta i inne metody interfejsu API (np. partners.devices.findByIdentifier) obsługują wyniki z podziałem na strony. Dzięki temu aplikacja może iteracyjnie prosić o duże listy i przetwarzać je pojedynczo.

Po wywołaniu metody interfejsu API sprawdź, czy odpowiedź zawiera wartość nextPageToken. Jeśli nextPageToken nie ma wartości null, aplikacja może użyć jej do pobrania innej strony urządzeń, ponownie wywołując tę metodę. Musisz ustawić górny limit liczby urządzeń w parametrze limit. Jeśli nextPageToken to null, aplikacja zażądała ostatniej strony.

W przykładowej metodzie poniżej pokazujemy, jak aplikacja może drukować listę urządzeń (po jednej stronie):

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

Dalsze kroki

Skoro już wiesz, jak działa interfejs API, zapoznaj się z przykładami w krótkim wprowadzeniu do Java, .NET lub Pythona.