Créer un package

Options d'importation

L'API Android Over The Air vous permet d'importer des données de package pour créer une ressource de package. Il s'agit de packages OTA qui peuvent être associés à une ou plusieurs configurations afin que la mise à jour soit transmise aux appareils.

Nous fournissons un binaire pour Linux et Windows afin de faciliter les importations de packages avec reprise. Vous pouvez l'utiliser librement au lieu de mettre en œuvre les protocoles décrits ci-dessous. Si vous souhaitez approfondir l'intégration, veuillez utiliser l'un des protocoles décrits ci-dessous.

Pour l'utiliser, vous devez d'abord créer un compte de service et obtenir un fichier de clé JSON pour ce compte. Pour en savoir plus, consultez notre guide de création d'un compte.
Une fois que vous disposez du binaire et du fichier de clé, vous pouvez l'exécuter avec des options de ligne de commande pour spécifier le fichier de clé, votre déploiement et le package que vous importez. Utilisez --help pour afficher toutes les options.

Protocoles d'importation

Vous pouvez effectuer des requêtes d'importation via l'une des méthodes indiquées ci-dessous. Spécifiez la méthode que vous utilisez avec l'en-tête de requête X-Goog-Upload-Protocol.

  • Importation en plusieurs parties : X-Goog-Upload-Protocol: multipart. Permet de transférer rapidement des fichiers de petite taille et des métadonnées. Le fichier est transféré avec les métadonnées qui le décrivent dans une seule requête.
  • Importation avec reprise : X-Goog-Upload-Protocol: resumable. Pour un transfert fiable, ce qui est particulièrement important avec des fichiers plus volumineux. Avec cette méthode, vous utilisez une requête de lancement de session qui peut éventuellement inclure des métadonnées. Il s'agit d'une bonne stratégie à utiliser pour la plupart des applications, car elle fonctionne également pour les fichiers plus petits au prix d'une requête HTTP supplémentaire par importation.

Importation en plusieurs parties

Cette option est recommandée si les données que vous envoyez sont suffisamment petites pour pouvoir être importées intégralement en cas d'échec de connexion.

Pour utiliser l'importation en plusieurs parties, envoyez une requête POST à l'URI /upload/package et définissez X-Goog-Upload-Protocol sur multipart.

Les en-têtes HTTP de premier niveau à utiliser lors d'une importation en plusieurs parties incluent :

  • Content-Type : spécifiez-y "multipart/related" et incluez la chaîne de délimitation que vous utilisez pour identifier les parties de la requête.
  • Content-Length. Défini sur le nombre total d'octets dans le corps de la requête.

Le corps de la requête est mis en forme en tant que type de contenu multipart/related [RFC2387] et contient exactement deux parties. Les parties sont identifiées par une chaîne de délimitation et la dernière chaîne est suivie de deux traits d'union.

Chaque partie de la requête en plusieurs parties nécessite un en-tête Content-Type supplémentaire :

  1. Partie métadonnées:doit apparaître en premier, et Content-Type doit être application/json.
  2. Partie média:doit apparaître en second, et Content-Type doit être application/zip.

Exemple : Importation en plusieurs parties

L'exemple ci-dessous présente une requête d'importation en plusieurs parties pour l'API Android Over The Air.

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

Si la requête aboutit, le serveur affiche le code d'état HTTP 200 OK.

HTTP/1.1 200

Pour ce faire, utilisez curl et oauth2l. Vous trouverez ci-dessous un exemple de requête qui part du principe que vous utilisez une clé de service. Pour en savoir plus, consultez notre procédure d'autorisation.

Exemple de requête 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
  

Importation avec reprise

Pour importer des fichiers de données de manière plus fiable, vous pouvez utiliser le protocole d'importation avec reprise. Ce protocole vous permet de reprendre une opération d'importation après un échec de communication ayant interrompu le flux de données. Elle est particulièrement utile si vous transférez des fichiers volumineux et que les risques d'interruption du réseau ou d'échec de transmission sont élevés, par exemple lorsque vous importez des fichiers depuis une application cliente mobile. Cela peut également réduire l'utilisation de la bande passante en cas de panne réseau, car vous n'avez pas besoin de recommencer les importations de fichiers volumineux depuis le début.

Le protocole d'importation avec reprise utilise plusieurs commandes:

  1. Démarrez une session avec reprise. Envoyez une requête initiale à l'URI d'importation, qui inclut les métadonnées et établit un emplacement unique d'importation avec reprise.
  2. Enregistrez l'URI de la session avec reprise. Enregistrez l'URI de la session affichée dans la réponse à la requête initiale. Vous l'utiliserez pour les requêtes restantes dans cette session.
  3. Importez le fichier. Envoyez tout ou partie du fichier ZIP à l'URI de la session avec reprise.

En outre, les applications qui utilisent l'importation avec reprise doivent posséder un code pour reprendre une importation interrompue. En cas d'interruption d'une importation, déterminez la quantité de données reçue, puis reprenez l'importation à partir de ce point.

Remarque : Une URI d'importation expire au bout de trois jours.

Étape 1 : Démarrez une session avec reprise

Pour lancer une importation avec reprise, envoyez une requête POST à l'URI /upload/package, puis définissez X-Goog-Upload-Protocol sur resumable.

Pour cette requête de lancement, le corps ne doit contenir que les métadonnées. Vous transférerez le contenu réel du fichier que vous souhaitez importer dans les requêtes ultérieures.

Utilisez les en-têtes HTTP suivants avec la requête initiale :

  • X-Goog-Upload-Header-Content-Type : type de contenu du fichier en cours d'importation. Doit être défini sur application/zip.
  • X-Goog-Upload-Command. Défini sur start
  • X-Goog-Upload-Header-Content-Length. Définissez le nombre d'octets des données d'importation à transférer dans les requêtes ultérieures. Si cette valeur est inconnue au moment de cette requête, vous pouvez omettre cet en-tête.
  • Content-Type : type de contenu des métadonnées, qui doit être défini sur application/json.
  • Content-Length. Définissez le nombre d'octets fournis dans le corps de cette requête initiale.
Exemple : Requête de lancement de session avec reprise

L'exemple suivant montre comment lancer une session avec reprise pour 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" }

La section suivante décrit comment gérer la réponse.

Étape 2 : Enregistrez l'URI de la session avec reprise

Si la requête de lancement de session aboutit, le serveur d'API répond par un code d'état HTTP 200 OK. En outre, il fournit un en-tête X-Goog-Upload-URL qui spécifie votre URI de session avec reprise. L'en-tête X-Goog-Upload-URL, illustré dans l'exemple ci-dessous, inclut une partie de paramètre de requête upload_id qui fournit l'ID d'importation unique à utiliser pour cette session. La réponse contient également un en-tête X-Goog-Upload-Status, qui sera active si la requête d'importation est valide et acceptée. Cet état peut être final si l'importation a été refusée.

Exemple : Réponse de lancement de session avec reprise

La réponse à la requête de l'étape 1 se présente comme suit :

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

La valeur de l'en-tête X-Goog-Upload-URL, comme indiqué dans l'exemple de réponse ci-dessus, correspond à l'URI de session que vous utiliserez comme point de terminaison HTTP pour effectuer l'importation du fichier ou interroger l'état de l'importation.

Copiez et enregistrez l'URI de la session afin de pouvoir l'utiliser pour les requêtes ultérieures.

Étape 3 : Importez le fichier

Pour importer le fichier, envoyez une requête POST à l'URI d'importation obtenu lors de l'étape précédente. Le format de la requête d'importation se présente comme suit :

POST session_uri

Voici les en-têtes HTTP à utiliser lors des requêtes d'importation de fichiers avec reprise:

  1. Content-Length : indiquez le nombre d'octets que vous importez dans cette requête (il s'agit généralement de la taille du fichier importé).
  2. X-Goog-Upload-Command. Définissez cette valeur sur upload et finalize.
  3. X-Goog-Upload-Offset : spécifie le décalage auquel les octets doivent être écrits. Notez que les clients doivent importer les octets en série.
Exemple : Requête d'importation de fichier avec reprise

Voici une requête avec reprise permettant d'importer l'intégralité du fichier ZIP de 2 000 000 octets pour l'exemple actuel.

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

Si la requête aboutit, le serveur renvoie une réponse HTTP 200 Ok.

Si la requête d'importation est interrompue, ou si le serveur vous envoie une réponse HTTP 503 Service Unavailable ou toute autre réponse 5xx, suivez la procédure expliquant comment reprendre une importation interrompue.


Importer un fichier fragmenté

Les importations avec reprise vous permettent de diviser un fichier en plusieurs fragments et d'envoyer une série de requêtes afin d'importer chacun de ces fragments l'un après l'autre. Cette approche n'est pas recommandée, car des coûts de performance sont associés aux requêtes supplémentaires, ce qui n'est généralement pas nécessaire. Nous recommandons aux clients d'importer tous les octets restants de la charge utile et d'inclure la commande finalize dans chaque commande upload.

Toutefois, vous devrez peut-être recourir à la fragmentation pour réduire la quantité de données transférées dans une seule requête. Elle vous permet également de fournir des indications concernant la progression de l'importation pour les anciens navigateurs qui ne sont pas compatibles par défaut avec cette fonctionnalité.


Reprendre une importation interrompue

Si une requête d'importation se termine avant de recevoir une réponse ou si le serveur vous envoie une réponse HTTP 503 Service Unavailable, vous devez reprendre l'importation interrompue. Procédez comme suit :

  1. Interrogez l'état. Interrogez l'état actuel de l'importation en envoyant une requête à l'URI d'importation avec le paramètre X-Goog-Upload-Command défini sur query.

    Remarque : Vous pouvez interroger l'état entre les fragments, et pas seulement si l'importation est interrompue. Cette fonctionnalité est utile si vous souhaitez afficher des indications de progression de l'importation pour les navigateurs anciens, par exemple.

  2. Obtenez le nombre d'octets importés. Traitez la réponse à partir de la requête d'état. Le serveur utilise l'en-tête X-Goog-Upload-Size-Received dans sa réponse pour spécifier le nombre d'octets reçus jusqu'à présent.
  3. Importez les données restantes. Enfin, maintenant que vous savez où reprendre la requête, envoyez les données restantes ou le fragment actuel. Notez que vous devez traiter les données restantes comme un fragment distinct dans les deux cas. Vous devez donc définir l'en-tête X-Goog-Upload-Offset sur le décalage approprié lorsque vous reprenez l'importation.
Exemple : Reprendre une importation interrompue

1) Interrogez l'état de l'importation.

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

Comme pour toutes les commandes, le client doit vérifier l'en-tête X-Goog-Upload-Status dans la réponse HTTP d'une commande de requête. Si l'en-tête est présent et que la valeur n'est pas active, l'importation a déjà été terminée.

2) Procédez à l'extraction du nombre d'octets importés jusqu'à présent à partir de la réponse.

La réponse du serveur utilise l'en-tête X-Goog-Upload-Size-Received pour indiquer qu'il a reçu les 43 premiers octets du fichier jusqu'à présent.

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

3) Reprenez l'importation là où elle s'était arrêtée.

La requête suivante reprend l'importation en envoyant les octets restants du fichier, en commençant par l'octet 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

Bonnes pratiques

En ce qui concerne l'importation de médias, il est utile de connaître certaines bonnes pratiques en matière de traitement des erreurs.

  • Reprenez ou relancez les importations qui échouent en raison d'interruptions de connexion ou d'erreurs 5xx, parmi lesquelles :
    • 500 Internal Server Error
    • 502 Bad Gateway
    • 503 Service Unavailable
    • 504 Gateway Timeout
  • Si une erreur de serveur 5xx est renvoyée lors de la reprise ou de la nouvelle tentative d'importation, utilisez une stratégie d'intervalle exponentiel entre les tentatives. Ces erreurs peuvent se produire quand un serveur est surchargé. L'intervalle exponentiel entre les tentatives peut aider à résoudre ce type de problème lors des pics de volumes de requêtes ou de trafic réseau.
  • Les autres types de requêtes ne doivent pas être traités par un intervalle exponentiel entre les tentatives, mais vous pouvez toujours essayer d'en relancer un certain nombre. Lorsque vous relancez ces requêtes, limitez le nombre de tentatives. Par exemple, votre code peut être limité à 10 tentatives ou moins avant de signaler une erreur.
  • Lorsque vous effectuez des importations avec reprise, traitez les erreurs 404 Not Found en recommençant toute l'importation depuis le début.

Intervalle exponentiel entre les tentatives

L'intervalle exponentiel entre les tentatives est une stratégie standard en matière de traitement d'erreurs pour les applications réseau, selon laquelle le client relance périodiquement une requête ayant échoué sur une durée de plus en plus longue. Si un volume élevé de requêtes ou un trafic réseau important provoquent des erreurs sur le serveur, l'intervalle exponentiel entre les tentatives peut s'imposer comme une stratégie efficace pour traiter ces erreurs. À l'inverse, cette stratégie n'est pas pertinente pour traiter les erreurs sans rapport avec le volume réseau ou les temps de réponse, telles que les erreurs associées aux identifiants d'autorisation non valides ou aux fichiers introuvables.

Utilisé correctement, l'intervalle exponentiel entre les tentatives augmente l'efficacité de l'utilisation de la bande passante, réduit le nombre de requêtes nécessaires pour obtenir une réponse positive et optimise le débit des requêtes dans les environnements avec simultanéité.

Le fonctionnement de l'intervalle exponentiel simple entre les tentatives se présente comme suit :

  1. Vous envoyez une requête à l'API.
  2. Vous recevez une réponse HTTP 503, qui indique que vous devez relancer la requête.
  3. Vous patientez 1 seconde + "random_number_milliseconds", puis vous relancez la requête.
  4. Vous recevez une réponse HTTP 503, qui indique que vous devez relancer la requête.
  5. Vous patientez 2 secondes + "random_number_milliseconds", puis vous relancez la requête.
  6. Vous recevez une réponse HTTP 503, qui indique que vous devez relancer la requête.
  7. Vous patientez 4 secondes + "random_number_milliseconds", puis vous relancez la requête.
  8. Vous recevez une réponse HTTP 503, qui indique que vous devez relancer la requête.
  9. Vous patientez 8 secondes + "random_number_milliseconds", puis vous relancez la requête.
  10. Vous recevez une réponse HTTP 503, qui indique que vous devez relancer la requête.
  11. Vous patientez 16 secondes + "random_number_milliseconds", puis vous relancez la requête.
  12. Vous arrêtez, puis vous signalez ou consignez une erreur.

Dans le flux ci-dessus, "random_number_milliseconds" correspond à un nombre aléatoire de millisecondes inférieur ou égal à 1 000. Cette valeur est nécessaire, car l'introduction d'un petit délai aléatoire permet de répartir la charge de manière plus uniforme et d'éviter la surcharge du serveur. La valeur de "random_number_milliseconds" doit être redéfinie après chaque temps d'attente.

Remarque : L'attente correspond toujours à (2 ^ n) + "random_number_milliseconds", où "n" est un entier augmentant de manière monotone défini initialement sur 0. L'entier "n" est augmenté de 1 pour chaque itération (chaque requête).

L'algorithme est configuré pour se terminer lorsque "n" vaut 5. Ce plafond empêche les clients d'effectuer des relances indéfiniment et entraîne un délai total d'environ 32 secondes avant qu'une requête ne soit considérée comme une "erreur non récupérable". Vous pouvez tout à fait définir un nombre maximal de tentatives plus élevé, surtout si une longue importation est en cours d'exécution. Veillez simplement à limiter le délai des nouvelles tentatives de manière raisonnable, par exemple à moins d'une minute.