Crea un pacchetto

Opzioni di caricamento

L'API over-the-air di Android consente di caricare i dati del pacchetto per creare una nuova risorsa del pacchetto. Questi sono pacchetti OTA che possono essere associati a una o più configurazioni per far sì che l'aggiornamento venga consegnato ai dispositivi.

Per semplificare i caricamenti di pacchetti, forniamo un programma binario per Linux e Windows. Puoi utilizzare liberamente anziché implementare i protocolli descritti di seguito. Se desideri un'integrazione più profonda, utilizza uno dei protocolli descritti di seguito.

Per utilizzarlo, devi prima creare un account di servizio e ottenere un file di chiave JSON per l'account. Consulta la nostra guida per la creazione di un account qui.
Una volta che disponi del file binario e del file della chiave, puoi eseguirlo utilizzando le opzioni della riga di comando per specificare il file della chiave, il deployment e il pacchetto che stai caricando. Utilizza --help per visualizzare tutte le opzioni.

Protocolli di caricamento

Puoi effettuare richieste di caricamento in uno dei seguenti modi. Specifica il metodo che stai utilizzando con l'intestazione della richiesta X-Goog-Upload-Protocol.

  • Caricamento multiparte: X-Goog-Upload-Protocol: multipart. Per trasferire rapidamente file e metadati più piccoli, trasferisce il file insieme ai metadati che lo descrivono, il tutto in un'unica richiesta.
  • Caricamento ripristinabile: X-Goog-Upload-Protocol: resumable. Per trasferimenti affidabili, particolarmente importanti con file di grandi dimensioni. Con questo metodo, utilizzi una richiesta di avvio della sessione che, facoltativamente, può includere metadati. Questa è una buona strategia da utilizzare per la maggior parte delle applicazioni, perché funziona anche per file più piccoli che comporta la necessità di una singola richiesta HTTP aggiuntiva per caricamento.

Caricamento multiparte

Si tratta di una buona scelta se i dati che stai inviando sono sufficientemente ridotti da poter essere ricaricati completamente in caso di problemi di connessione.

Per utilizzare il caricamento multiparte, effettua una richiesta POST all'URI /upload/package e imposta X-Goog-Upload-Protocol su multipart.

Le intestazioni HTTP di primo livello da utilizzare per una richiesta di caricamento con più parti includono:

  • Content-Type. Impostalo su multipart/related e includi la stringa limite che stai utilizzando per identificare le parti della richiesta.
  • Content-Length. Impostalo sul numero totale di byte nel corpo della richiesta.

Il corpo della richiesta è formattato come tipo di contenuti multipart/related [RFC2387] e contiene esattamente due parti. Le parti sono identificate da una stringa di confine e l'ultima stringa di confine è seguita da due trattini.

Ogni parte della richiesta con più parti richiede un'intestazione Content-Type aggiuntiva:

  1. Parte dei metadati: deve essere la prima e Content-Type deve essere application/json.
  2. Parte multimediale: deve essere seconda e Content-Type deve essere application/zip.

Esempio: caricamento multiparte

L'esempio seguente mostra una richiesta di caricamento multiparte per l'API Over The Air di Android.

POST /upload/package HTTP/1.1
Host: androidovertheair.googleapis.com
Authorization: Bearer your_auth_token
Content-Type: multipart/related; boundary=BOUNDARY
Content-Length: number_of_bytes_in_entire_request_body

--BOUNDARY
Content-Type: application/json; charset=UTF-8

{"deployment": "id", "package_title": "title" }
--BOUNDARY
Content-Type: application/zip; charset=UTF-8

Package ZIP
--BOUNDARY--

Se la richiesta ha esito positivo, il server restituisce il codice di stato HTTP 200 OK

HTTP/1.1 200

Un modo per eseguire facilmente questa operazione è utilizzare curl e oauth2l. Di seguito è riportato un esempio di richiesta che presuppone l'utilizzo di una chiave di servizio (per ulteriori informazioni, consulta le nostre istruzioni su come ottenere l'autorizzazione).

Esempio di richiesta curl
    JSON={"deployment": "id", "package_title": "title" }
    SERVICE_KEY_FILE=path to your service key json file
    curl \
    -H "$(./oauth2l header --json $SERVICE_KEY_FILE android_partner_over_the_air)" \
    -H "Host: androidovertheair.googleapis.com" \
    -H "X-Goog-Upload-Protocol: multipart" \
    -H "Content-Type: multipart/form-data" \
    -F "json=$JSON;type=application/json" \
    -F "data=@update.zip;type=application/zip" \
    androidovertheair.googleapis.com/upload/package
  

Caricamento ripristinabile

Per caricare i file di dati in modo più affidabile, puoi utilizzare il protocollo di caricamento ripristinabile. Questo protocollo consente di riprendere un'operazione di caricamento dopo che un errore di comunicazione ha interrotto il flusso di dati. È particolarmente utile se stai trasferendo file di grandi dimensioni e la probabilità di interruzione della rete o altro errore di trasmissione è elevata, ad esempio in caso di caricamento da un'app client per dispositivi mobili. Può inoltre ridurre l'utilizzo della larghezza di banda in caso di errori di rete, in quanto non devi riavviare il caricamento di file di grandi dimensioni dall'inizio.

Il protocollo di caricamento ripristinabile utilizza diversi comandi:

  1. Avviare una sessione ripristinabile. Effettua una richiesta iniziale all'URI di caricamento che includa i metadati e stabilisce una posizione di caricamento univoca ripristinabile.
  2. Salva l'URI della sessione ripristinabile. Salva l'URI della sessione restituito nella risposta della richiesta iniziale; lo utilizzerai per le restanti richieste di questa sessione.
  3. Carica il file. Invia tutto o parte del file ZIP all'URI della sessione ripristinabile.

Inoltre, le app che utilizzano un caricamento ripristinabile devono avere codice per riprendere un caricamento interrotto. Se un caricamento viene interrotto, scopri quanti dati sono stati ricevuti correttamente e riprendi il caricamento partendo da quel punto.

Nota : l'URI di caricamento scade dopo tre giorni.

Passaggio 1: avvia una sessione ripristinabile

Per avviare un caricamento ripristinabile, effettua una richiesta POST all'URI /upload/package e imposta X-Goog-Upload-Protocol su resumable.

Per questa richiesta di avvio, il corpo deve contenere solo i metadati; verranno trasferiti i contenuti effettivi del file che vuoi caricare nelle richieste successive.

Utilizza le seguenti intestazioni HTTP con la richiesta iniziale:

  • X-Goog-Upload-Header-Content-Type. Questo è il tipo di contenuto del file che stai caricando e deve essere impostato su application/zip.
  • X-Goog-Upload-Command. Imposta su start
  • X-Goog-Upload-Header-Content-Length. Imposta il numero di byte di dati di caricamento da trasferire nelle richieste successive. Se la lunghezza non è nota al momento della richiesta, puoi omettere questa intestazione.
  • Content-Type. Questo è il tipo di contenuto dei metadati e deve essere impostato su application/json.
  • Content-Length. Impostalo sul numero di byte fornito nel corpo di questa richiesta iniziale.
Esempio: richiesta di avvio della sessione ripristinabile

L'esempio seguente mostra come avviare una sessione ripristinabile per l'API Android Over The Air.

POST /upload/package HTTP/1.1
Host: android/over-the-air.googleapis.com
Authorization: Bearer your_auth_token
Content-Length: 38
Content-Type: application/json; charset=UTF-8
X-Goog-Upload-Command: start
X-Goog-Upload-Header-Content-Type: application/zip
X-Goog-Upload-Header-Content-Length: 2000000

{"deployment": "id", "package_title": "title" }

Nella sezione successiva viene descritto come gestire la risposta.

Passaggio 2: salva l'URI della sessione ripristinabile

Se la richiesta di avvio della sessione ha esito positivo, il server API risponde con un codice di stato HTTP 200 OK. Inoltre, fornisce un'intestazione X-Goog-Upload-URL che specifica l'URI della sessione ripristinabile. L'intestazione X-Goog-Upload-URL, mostrata nell'esempio riportato di seguito, include una parte del parametro di query upload_id che fornisce l'ID caricamento univoco da utilizzare per questa sessione. La risposta contiene anche un'intestazione X-Goog-Upload-Status, che sarà active se la richiesta di caricamento era valida e accettata. Questo stato potrebbe essere final se il caricamento è stato rifiutato.

Esempio: risposta di avvio della sessione ripristinabile

Ecco la risposta alla richiesta nel passaggio 1:

HTTP/1.1 200 OK
X-Goog-Upload-Status: active
X-Goog-Upload-URL: androidovertheair.googleapis.com/?upload_id=xa298sd_sdlkj2
Content-Length: 0

Il valore dell'intestazione X-Goog-Upload-URL, come mostrato nell'esempio di risposta riportato sopra, è l'URI della sessione che utilizzerai come endpoint HTTP per eseguire il caricamento effettivo del file o eseguire query sullo stato del caricamento.

Copia e salva l'URI della sessione in modo da poterlo utilizzare per le richieste successive.

Passaggio 3. Carica il file

Per caricare il file, invia una richiesta POST all'URI di caricamento ottenuto nel passaggio precedente. Il formato della richiesta di caricamento è il seguente:

POST session_uri

Le intestazioni HTTP da utilizzare per effettuare richieste di caricamento di file ripristinabili includono:

  1. Content-Length. Impostalo sul numero di byte che stai caricando in questa richiesta, che in genere corrisponde alle dimensioni del file di caricamento.
  2. X-Goog-Upload-Command. Impostala su upload e finalize.
  3. X-Goog-Upload-Offset. Questo valore ha specificato l'offset con cui devono essere scritti i byte. Tieni presente che i client devono caricare byte in serie.
Esempio: richiesta di caricamento file ripristinabile

Ecco una richiesta ripristinabile per caricare l'intero file ZIP da 2.000.000 di byte per l'esempio attuale.

POST /?upload_id=xa298sd_sdlkj2 HTTP/1.1
Host: androidovertheair.googleapis.com
X-Goog-Upload-Protocol: resumable
X-Goog-Upload-Command: upload, finalize
X-Goog-Upload-Offset: 0
Content-Length: 2000000
Content-Type: application/zip

bytes 0-1999999

Se la richiesta ha esito positivo, il server risponde con un 200 Ok HTTP.

Se la richiesta di caricamento viene interrotta o se ricevi una risposta HTTP 503 Service Unavailable o qualsiasi altra risposta 5xx dal server, segui la procedura descritta in Riprendere un caricamento interrotto.


Caricamento del file in blocchi

Con i caricamenti ripristinabili, puoi suddividere un file in blocchi e inviare una serie di richieste per caricare ogni blocco in sequenza. Questo non è l'approccio preferito perché alle richieste aggiuntive sono associati costi di prestazioni e in genere non è necessario. Consigliamo ai client di caricare tutti i byte rimanenti del payload e di includere il comando finalize con ogni comando upload.

Tuttavia, potrebbe essere necessario utilizzare la suddivisione in blocchi per ridurre la quantità di dati trasferiti in ogni singola richiesta. Ti consente inoltre di svolgere operazioni come fornire indicazioni di avanzamento del caricamento per i browser precedenti che non supportano per impostazione predefinita l'avanzamento del caricamento.


Riprendere un caricamento interrotto

Se una richiesta di caricamento viene terminata prima di ricevere una risposta o se ricevi una risposta HTTP 503 Service Unavailable dal server, devi riprendere il caricamento interrotto. Per farlo:

  1. Stato della richiesta. Query sullo stato attuale del caricamento inviando una richiesta all'URI di caricamento con X-Goog-Upload-Command impostato su query.

    Nota : puoi richiedere lo stato tra un blocco e l'altro, non solo se il caricamento viene interrotto. Ciò è utile, ad esempio, se vuoi mostrare le indicazioni di avanzamento del caricamento per i browser precedenti.

  2. Ottieni il numero di byte caricati. Elabora la risposta alla query sullo stato. Il server utilizza l'intestazione X-Goog-Upload-Size-Received nella risposta per specificare il numero di byte ricevuti finora.
  3. Carica i dati rimanenti. Infine, ora che sai dove riprendere la richiesta, invia i dati rimanenti o il blocco attuale. Tieni presente che in entrambi i casi devi trattare i dati rimanenti come un blocco separato, quindi devi impostare l'offset dell'intestazione X-Goog-Upload-Offset sull'offset corretto quando riprendi il caricamento.
Esempio: riprendere un caricamento interrotto

1) Richiedi lo stato del caricamento.

POST /?upload_id=xa298sd_sdlkj2 HTTP/1.1
Host: androidovertheair.googleapis.com
X-Goog-Upload-Command: query

Come per tutti i comandi, il client deve controllare l'intestazione X-Goog-Upload-Status nella risposta HTTP di un comando di query. Se è presente l'intestazione e il valore non è active, il caricamento è già stato terminato.

2) Estrae il numero di byte caricati finora dalla risposta.

La risposta del server utilizza l'intestazione X-Goog-Upload-Size-Received per indicare che ha ricevuto finora i primi 43 byte del file.

HTTP/1.1 200 OK
X-Goog-Upload-Status: active
X-Goog-Upload-Size-Received: 42

3) Riprendi il caricamento dal punto in cui è stato interrotto.

La seguente richiesta riprende il caricamento inviando i byte rimanenti del file, a partire dal byte 43.

POST /?upload_id=xa298sd_sdlkj2 HTTP/1.1
Host: androidovertheair.googleapis.com
X-Goog-Upload-Command: upload, finalize
Content-Length: 1999957
X-Goog-Upload-Offset: 43

bytes 43-1999999

best practice

Quando carichi contenuti multimediali, è utile conoscere alcune best practice relative alla gestione degli errori.

  • Riprendi o riprova i caricamenti non riusciti a causa di interruzioni della connessione o di eventuali errori 5xx, tra cui:
    • 500 Internal Server Error
    • 502 Bad Gateway
    • 503 Service Unavailable
    • 504 Gateway Timeout
  • Utilizza una strategia di backoff esponenziale se viene restituito un errore del server 5xx durante il ripristino o la ripetizione delle richieste di caricamento. Questi errori possono verificarsi in caso di sovraccarico del server. Il backoff esponenziale può aiutare ad alleviare questo tipo di problemi durante i periodi di volume elevato di richieste o traffico di rete intenso.
  • Altri tipi di richieste non dovrebbero essere gestiti dal backoff esponenziale, ma puoi comunque riprovare un certo numero. Limita il numero di nuovi tentativi di queste richieste. Ad esempio, il codice potrebbe limitare a 10 tentativi o meno prima di segnalare un errore.
  • Gestisci gli errori di 404 Not Found durante i caricamenti ripristinabili, ripartendo l'intero caricamento dall'inizio.

Backoff esponenziale

Il backoff esponenziale è una strategia di gestione degli errori standard per le applicazioni di rete in cui il client riprova periodicamente a effettuare una richiesta non riuscita per un periodo di tempo crescente. Se un volume elevato di richieste o un traffico di rete intenso fa sì che il server restituisca errori, il backoff esponenziale può essere una buona strategia per la gestione di questi errori. Al contrario, non si tratta di una strategia pertinente per la gestione di errori non correlati al volume di rete o ai tempi di risposta, come credenziali di autorizzazione non valide o errori di file non trovato.

Se usato correttamente, il backoff esponenziale aumenta l'efficienza dell'utilizzo della larghezza di banda, riduce il numero di richieste necessarie per ottenere una risposta corretta e massimizza la velocità effettiva delle richieste in ambienti contemporanei.

Il flusso per l'implementazione di un backoff esponenziale semplice è il seguente:

  1. Effettua una richiesta all'API.
  2. Ricevi una risposta HTTP 503, che indica che devi ritentare la richiesta.
  3. Attendi 1 secondo + numero_casuale_di_millisecondi e riprova.
  4. Ricevi una risposta HTTP 503, che indica che devi ritentare la richiesta.
  5. Attendi 2 secondi + numero_casuale_di_millisecondi e riprova.
  6. Ricevi una risposta HTTP 503, che indica che devi ritentare la richiesta.
  7. Attendi 4 secondi + numero_casuale_di_millisecondi e riprova.
  8. Ricevi una risposta HTTP 503, che indica che devi ritentare la richiesta.
  9. Attendi 8 secondi + numero_casuale_di_millisecondi e riprova.
  10. Ricevi una risposta HTTP 503, che indica che devi ritentare la richiesta.
  11. Attendi 16 secondi + numero_casuale_di_millisecondi e riprova.
  12. Interrompi. Segnala o registra un errore.

Nel flusso precedente, numero_casuale_millisecondi è un numero casuale di millisecondi inferiore o uguale a 1000. Questo è necessario, perché l'introduzione di un piccolo ritardo casuale consente di distribuire il carico in modo più uniforme ed evitare la possibilità di stampare in eccesso il server. Il valore di numero_casuale_millisecondi deve essere ridefinito dopo ogni attesa.

Nota : l'attesa è sempre (2 ^ n) + numero_casuale_millisecondi, dove n è un numero intero con aumento monotonico inizialmente definito come 0. Il numero intero n viene incrementato di 1 per ogni iterazione (ogni richiesta).

L'algoritmo è impostato per terminare quando n è 5. Questo limite impedisce ai client di effettuare nuovi tentativi all'infinito e genera un ritardo totale di circa 32 secondi prima che una richiesta venga considerata "un errore irreversibile". Un numero massimo di nuovi tentativi è sufficiente, soprattutto se è in corso un caricamento lungo; assicurati solo di limitare il ritardo tra tentativi a un valore ragionevole, ad esempio inferiore a un minuto.