Come funziona

Introduzione

L'API zero-touch registration aiuta i rivenditori di dispositivi ad automatizzare l'integrazione. Gli strumenti di vendita della tua organizzazione possono integrarsi con la registrazione zero-touch, aumentando la produttività di utenti e clienti. Utilizza l'API per aiutare gli utenti a:

  • Assegna i dispositivi acquistati all'account di registrazione zero-touch di un cliente.
  • Creazione dell'account di registrazione zero-touch dei clienti.
  • Allega il numero di telefono della tua organizzazione e i metadati dell'ordine ai dispositivi.
  • Creazione di report sui dispositivi assegnati ai clienti.

Questo documento presenta l'API e spiega i pattern. Se vuoi esplorare l'API in modo autonomo, prova una guida rapida per Java, .NET o Python.

Concetti relativi alle API

I clienti e i dispositivi sono le risorse principali che utilizzi nell'API. Per creare clienti, chiama create. Puoi creare dispositivi utilizzando i metodi dell'API di attestazione (vedi sotto). La tua organizzazione può anche creare clienti e dispositivi utilizzando il portale della registrazione zero-touch.

Relazione tra dispositivo e risorse cliente

Cliente
Aziende a cui la tua organizzazione vende dispositivi. I clienti hanno un name e un ID. Utilizza un cliente quando vuoi rivendicare o trovare i suoi dispositivi. Per scoprire di più, consulta Customer.
Dispositivo
Un dispositivo Android o ChromeOS compatibile con la registrazione zero-touch che la tua organizzazione vende a un cliente. I dispositivi hanno ID hardware, metadati e dichiarazioni dei clienti. I dispositivi sono fondamentali per l'API, quindi vengono utilizzati in quasi tutti i metodi. Per scoprire di più, visita la pagina Device.
DeviceIdentifier
Contiene gli ID hardware, ad esempio IMEI o MEID, per identificare un dispositivo prodotto. Utilizza una DeviceIdentifier per scegliere come target il dispositivo che vuoi trovare, aggiornare o rivendicare. Per scoprire di più, consulta la pagina Identificatori.
DeviceMetadata
Archivia le coppie chiave-valore dei metadati relativi al dispositivo. Utilizza DeviceMetadata per archiviare i metadati della tua organizzazione. Per scoprire di più, consulta Metadati dispositivo.

Per elencare tutti i metodi e le risorse API che la tua app può utilizzare, consulta la documentazione di riferimento API.

Crea clienti

Per i dispositivi Android, il rivenditore è responsabile della creazione dell'account del cliente per suo conto. Il cliente utilizzerà questo account per accedere al portale zero-touch e configurare le impostazioni di provisioning per i propri dispositivi. Questa operazione non è necessaria per i dispositivi ChromeOS che hanno già un account Google Workspace che utilizzeranno per configurare le impostazioni di provisioning.

Puoi chiamare il metodo API create per creare account dei clienti per la registrazione zero-touch. Poiché i tuoi clienti vedono il nome dell'azienda nel portale della registrazione zero-touch, l'utente della tua app deve confermare che è corretto. Non puoi modificare il nome di un cliente dopo averlo creato.

Devi includere almeno un indirizzo email aziendale, associato a un Account Google, per essere il proprietario. Non puoi utilizzare account Gmail personali con l'API. Se il cliente ha bisogno di aiuto per associare l'account, invia le istruzioni da Associare un Account Google.

Dopo che hai creato un cliente chiamando l'API, quest'ultimo gestisce l'accesso al portale dei suoi dipendenti. Non puoi modificare gli utenti dei tuoi clienti utilizzando l'API. Lo snippet riportato di seguito mostra come creare un cliente:

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

Per scoprire di più sui ruoli di proprietario e amministratore per i dipendenti del tuo cliente, consulta Utenti del portale.

Richiedi i dispositivi per i clienti

Dopo che i tuoi clienti hanno acquistato i dispositivi, dovranno configurare le impostazioni di provisioning per questi dispositivi nel proprio account. La richiesta di un dispositivo lo aggiunge alla registrazione zero-touch e offre al cliente la possibilità di configurare le impostazioni di provisioning.

Il record di provisioning di un dispositivo contiene una sezione per la registrazione zero-touch. Puoi assegnare il dispositivo rivendicando la sezione della registrazione zero-touch del record per un cliente. Chiama i metodi partners.devices.claim o partners.devices.claimAsync con il cliente come argomento. Fornisci sempre SECTION_TYPE_ZERO_TOUCH come valore per sectionType.

Devi annullare la rivendicazione (vedi sotto) sul dispositivo di un cliente prima di poter rivendicare lo stesso dispositivo per un altro cliente. I metodi di dichiarazione consentono di validate i campi DeviceIdentifier, inclusi il codice IMEI o MEID, il numero di serie, il nome del produttore e il modello e l'ID dispositivo attestato per i dispositivi ChromeOS, quando crei un nuovo dispositivo.

Lo snippet seguente mostra come rivendicare un dispositivo:

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

Annullamento della rivendicazione dei dispositivi

La tua organizzazione può annullare la rivendicazione di un dispositivo da parte di un cliente. L'annullamento della rivendicazione di un dispositivo lo rimuove dalla registrazione zero-touch. Un rivenditore potrebbe annullare la rivendicazione di un dispositivo che vuole migrare a un altro account, restituito o che è stato rivendicato per errore. Chiama il metodo partners.devices.unclaim o partners.devices.unclaimAsync per annullare la rivendicazione di un dispositivo da un cliente.

Fornitori

Puoi utilizzare i fornitori per rappresentare i rivenditori partner nella tua rete di concessionari, gli operatori locali all'interno di una rete di rivenditori globale o qualsiasi organizzazione che vende dispositivi per tuo conto. I fornitori ti aiutano a separare utenti, clienti e dispositivi:

  • I fornitori che crei non possono visualizzare il tuo account di registrazione zero-touch né gli account degli altri.
  • Puoi visualizzare i clienti e i dispositivi dei tuoi fornitori e annullare la registrazione dei dispositivi dei fornitori. Tuttavia, non puoi assegnare dispositivi ai clienti dei tuoi fornitori.

Utilizza il portale per creare fornitori per la tua organizzazione: non puoi usare l'API. Per creare un nuovo fornitore, il ruolo del tuo account deve essere Proprietario. Se la tua organizzazione ha fornitori, puoi chiamare partners.vendors.list per elencarli e partners.vendors.customers.list per acquisire clienti del tuo fornitore. L'esempio seguente utilizza entrambi i metodi per stampare un report che mostra lo stato dei Termini di servizio per i clienti dei fornitori:

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

Se hai un insieme di dispositivi, potrebbe essere necessario sapere quale rivenditore o fornitore ha rivendicato il dispositivo. Per ottenere l'ID rivenditore numerico, controlla il valore del campo resellerId nella registrazione della rivendicazione di un dispositivo.

La tua organizzazione può annullare la rivendicazione di un dispositivo rivendicato dal fornitore. Per altre chiamate API che modificano i dispositivi, devi verificare che la tua organizzazione abbia rivendicato il dispositivo prima di chiamare il metodo API. Nell'esempio seguente viene illustrato come eseguire questa operazione:

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

Operazioni batch a lunga esecuzione

L'API include versioni asincrone dei metodi dei dispositivi. Questi metodi consentono l'elaborazione batch di molti dispositivi, mentre i metodi sincroni elaborano un dispositivo per ogni richiesta API. I nomi dei metodi asincroni hanno un suffisso Async, ad esempio claimAsync.

I metodi API asincroni restituiscono un risultato prima del completamento dell'elaborazione. Inoltre, i metodi asincroni consentono alla tua app (o allo strumento) di rimanere reattiva per gli utenti mentre sono in attesa del completamento di un'operazione a lunga esecuzione. L'app dovrebbe controllare periodicamente lo stato dell'operazione.

Suite operativa

Puoi utilizzare Operation per monitorare un'operazione batch a lunga esecuzione. Una chiamata riuscita a un metodo asincrono restituisce un riferimento all'operazione nella risposta. Lo snippet JSON di seguito mostra una risposta tipica dopo aver chiamato updateMetadataAsync:

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

Ogni operazione contiene un elenco di singole attività. Chiama operations.get per trovare informazioni sullo stato e sui risultati delle attività contenute nell'operazione. Lo snippet di seguito mostra come fare. Nella tua app, dovrai gestire eventuali errori.

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

Per scoprire se un'operazione è terminata, controllala per un campo done con valore true. Se done non è presente o false, l'operazione è ancora in esecuzione.

Risposte

Al termine di un'operazione, l'API aggiorna l'operazione con il risultato, anche se tutte o nessuna delle singole attività ha esito positivo. Il campo response è un oggetto DevicesLongRunningOperationResponse che descrive nel dettaglio l'elaborazione di ciascun dispositivo nell'operazione.

Controlla il campo successCount per scoprire in modo efficiente se alcune attività non sono riuscite ed evita di ripetere lunghi elenchi di risultati. Il campo perDeviceStatus di DevicesLongRunningOperationResponse è un elenco di istanze OperationPerDevice con il dettaglio di ciascun dispositivo nell'operazione. L'ordine dell'elenco corrisponde alle attività nella richiesta originale.

Ogni attività OperationPerDevice contiene un campo result e un riepilogo promemoria della richiesta ricevuta dal server. Controlla se l'attività è riuscita o meno utilizzando il campo result.

Lo snippet JSON di seguito mostra parte di una risposta tipica da un'operazione dopo una chiamata a updateMetadataAsync:

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

Monitora i progressi

Se l'app deve monitorare l'avanzamento, devi recuperarla periodicamente. Il campo metadata contiene un'istanza DevicesLongRunningOperationMetadata che consente alla tua app di verificare l'ultimo avanzamento di un'operazione in esecuzione. Utilizza i campi DevicesLongRunningOperationMetadata elencati nella seguente tabella per monitorare l'avanzamento dell'operazione:

Campo Utilizzo tipico
processingStatus Cambia da BATCH_PROCESS_PENDING a BATCH_PROCESS_IN_PROGRESS e poi a BATCH_PROCESS_PROCESSED man mano che l'operazione procede.
progress La percentuale di aggiornamenti elaborati. L'app può utilizzare questa informazione per stimare il tempo di fine. Poiché il valore progress può essere 100 mentre l'operazione è in fase di completamento, controlla il campo done di un'operazione per sapere se è terminata e ha un risultato.
devicesCount Mostra il numero di aggiornamenti nell'operazione. Potrebbe essere diverso dal numero di aggiornamenti nella richiesta se l'API non è in grado di analizzare alcuni aggiornamenti.

L'esempio semplificato riportato di seguito mostra come un'app potrebbe utilizzare i metadati di avanzamento per impostare gli intervalli di polling. Nell'app, potresti aver bisogno di un'esecuzione attività più sofisticata per il polling. Dovrai anche aggiungere la gestione degli errori.

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)

Scegli un approccio di polling adeguato per gli utenti della tua app. Alcuni utenti di app potrebbero trarre vantaggio da aggiornamenti regolari dei progressi se sono in attesa del completamento del processo.

Risultati con pagine

Il metodo API partners.devices.findByOwner potrebbe restituire elenchi di dispositivi molto ampi. Per ridurre le dimensioni della risposta, questo e altri metodi dell'API (come partners.devices.findByIdentifier) supportano i risultati impaginati. Con i risultati impaginati, l'applicazione può richiedere ed elaborare in modo iterativo elenchi di grandi dimensioni, una pagina alla volta.

Dopo aver chiamato il metodo API, verifica se la risposta include un valore per nextPageToken. Se nextPageToken non è null, l'app può utilizzarlo per recuperare un'altra pagina di dispositivi richiamando di nuovo questo metodo. Devi impostare un limite massimo per il numero di dispositivi nel parametro limit. Se nextPageToken è null, la tua app ha richiesto l'ultima pagina.

Il metodo di esempio riportato di seguito mostra in che modo la tua app potrebbe stampare un elenco di dispositivi, una pagina alla volta:

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

Passaggi successivi

Ora che sai come funziona l'API, prova gli esempi con una guida rapida per Java, .NET o Python.