创建软件包

上传选项

借助 Android Over The Air API,您可以上传软件包数据来创建新的软件包资源。这些是 可与一项或多项配置关联以便传送更新的 OTA 软件包 设备。

我们提供了适用于 Linux 和 Windows 的二进制文件,以便于上传 而无需实现下述协议。如果您想更深入地了解 请使用下述协议之一。

若要使用它,您首先需要创建一个服务账号并获取该账号的 JSON 密钥文件。 请点击此处参阅我们的账号创建指南。
获得二进制文件和密钥文件后,您可以使用命令行选项运行该文件,以指定 密钥文件、您的部署和您要上传的软件包。请使用 --help 查看所有选项

上传协议

您可以通过以下任一方式发出上传请求。 使用 X-Goog-Upload-Protocol 请求标头指定您要使用的方法。

  • 多部分上传X-Goog-Upload-Protocol: multipart。为了快速将 较小的文件和元数据;只需一个请求,即可传输文件以及对该文件进行说明的元数据。
  • 可续传上传X-Goog-Upload-Protocol: resumable。用于进行可靠的传输,这对于 文件。通过这种方法,您可以使用一个启动请求的会话,可以选择在其中包含元数据。对于大部分客户来说 因为它也适用于较小的文件,但每次上传时都要多发出一个 HTTP 请求。

多部分上传

如果您要发送的数据很小,那么这是一个不错的选择 以便在连接失败时再次完整上传。

要使用多部分上传,请向 /upload/package 发出 POST 请求 URI 并将 X-Goog-Upload-Protocol 设置为 multipart

发出分段上传请求时要使用的顶级 HTTP 标头包含:

  • Content-Type。将此项设为 multipart/related,并在其中添加您要修改的定界字符串 来标识请求的各个部分
  • Content-Length。请将此项设为请求正文中的字节总数。

请求正文的格式为 multipart/related 内容 类型 [RFC2387],并且正好包含两个部分。 这两个部分由定界字符串标识,最后的定界字符串后跟两个连字符。

分段请求的每个部分都需要附加一个 Content-Type 标头:

  1. 元数据部分:必须位于第一部分,且 Content-Type 必须为 application/json
  2. 媒体部分:必须位于第二部分,且 Content-Type 必须为 application/zip

示例:分段上传

以下示例展示了针对 Android Over The Air API 的多部分上传请求。

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

如果请求成功,服务器将返回 HTTP 200 OK 状态代码

HTTP/1.1 200

为方便起见,您可以使用 curloauth2l。以下是一个示例请求 假定您使用的是服务密钥(请参阅我们的 授权方法)。

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

可续传上传

如需更可靠地上传数据文件,您可以使用“可续传上传”协议。此协议允许 可在因通信故障导致数据流中断后恢复上传操作。它 如果您要传输大型文件并且可能会发生网络中断 或某些其他传输故障很严重,例如从移动客户端应用上传时。它 也可以在出现网络故障时减少带宽使用量 从头开始上传大型文件。

可续传上传协议使用多个命令:

  1. 启动可续传会话。向包含 元数据,并建立唯一的可续传上传位置。
  2. 保存可续传会话 URI。保存 对初始请求的响应;您将用它来处理此会话的后续请求
  3. 上传文件。将整个或部分 ZIP 文件发送到可续传会话 URI。

此外,使用可续传上传的应用需要通过代码来恢复中断的上传。如果上传内容 了解已成功接收了多少数据,然后从该中断处恢复上传。

注意 :上传 URI 的有效期为 3 天。

第 1 步:启动可续传会话

如需启动可续传上传,请向 /upload/package 发出 POST 请求 URI 并将 X-Goog-Upload-Protocol 设置为 resumable

对于这个发起请求,正文必须只包含元数据;你会将实际的 您要在后续请求中上传的文件的内容。

请在初始请求中使用以下 HTTP 标头:

  • X-Goog-Upload-Header-Content-Type。这是要上传的文件的内容类型,必须设为 application/zip
  • X-Goog-Upload-Command。设置为 start
  • X-Goog-Upload-Header-Content-Length。请将此项设为要在后续请求中传输的上传数据的字节数。 在发起此请求时,如果内容长度未知,那么您可以忽略此标头。
  • Content-Type。这是元数据的内容类型,必须设置为 application/json
  • Content-Length。设置为此初始请求的正文中提供的字节数。
示例:可续传会话的启动请求

以下示例展示了如何为 Android Over The Air API 启动可续传会话。

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

下一部分将介绍如何处理响应。

第 2 步:保存可续传会话 URI

如果会话启动请求成功,API 服务器会返回 HTTP 200 OK 状态代码。 此外,它还会提供 X-Goog-Upload-URL 标头来指定您的可续传会话 URI。 以下示例中显示的 X-Goog-Upload-URL 标头包含一个 upload_id 查询参数 部分,其中提供了要用于此会话的唯一上传 ID。响应还包含 X-Goog-Upload-Status 标头,如果上传请求有效且被接受,该标头将为 active。此状态可能是“final” 如果上传被拒,则会发生此错误。

示例:可续传会话的启动响应

下面是对第 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

上面的响应示例中显示的 X-Goog-Upload-URL 标头的值是 您将用作 HTTP 端点的会话 URI,用于实际上传文件或查询上传状态。

请复制并保存该会话 URI,以便在后续请求中使用。

第 3 步:上传文件

要上传文件,请发送 POST 请求至您在 上一步。上传请求的格式如下所示:

POST session_uri

发出可续传文件上传请求时要使用的 HTTP 标头包括:

  1. Content-Length。请将此项设为您要在该请求中上传的字节数(通常为上传文件大小)。
  2. X-Goog-Upload-Command。将此项设置为 uploadfinalize
  3. X-Goog-Upload-Offset。此字段指定应写入字节的偏移量。请注意,客户端 必须串行上传字节。
示例:可续传文件上传请求

下面是一个可续传请求,用于针对当前示例上传大小为 2000000 字节的整个 ZIP 文件。

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

如果请求成功,服务器会返回 HTTP 200 Ok

如果上传请求被中断,或者您收到 HTTP 503 Service Unavailable 或任何 其他 5xx 响应,请按照恢复中断的上传部分中列出的步骤进行操作。


分块上传文件

借助可续传上传,您可以将一个文件分成几块,然后发送一系列请求,按顺序上传每个分块。 这并不是首选方法,因为发送更多请求会降低性能, 通常不需要。建议客户端上传载荷的所有剩余字节 在每个 upload 命令中添加 finalize 命令。

不过,您可能需要使用分块来减少 单一请求。它还可以让您执行各种操作,例如为旧版浏览器提供上传进度指示 默认不支持上传进度的应用


恢复中断的上传

如果上传请求在收到响应之前被终止,或者您收到 HTTP 503 Service Unavailable 响应,则需要恢复中断的上传。具体操作步骤如下:

  1. 请求状态。通过向上传 URI 发出请求来查询上传的当前状态 并将 X-Goog-Upload-Command 设置为 query

    注意:您不仅可以请求查询上传是否已被中断,还可以请求查询分块之间的状态。这是 (例如,您想在旧版浏览器上显示上传进度指示时)。

  2. 获取已上传的字节数。处理服务器针对状态查询返回的响应。服务器使用 X-Goog-Upload-Size-Received 标头来指明目前已收到多少个字节。
  3. 上传剩余的数据。最后,在知道从何处恢复请求后,请将 剩余数据或当前分块请注意,无论在何种情况下,您都需要将剩余数据视为单独的分块。 您需要在恢复上传时将 X-Goog-Upload-Offset 标头设置为适当的偏移量。
示例:恢复中断的上传

1) 请求了解上传状态。

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

与所有命令一样,客户端必须检查查询命令的 HTTP 响应中的 X-Goog-Upload-Status 标头。 如果存在此标头且值不是 active,则表示上传已终止。

2) 从响应中提取目前已上传的字节数。

服务器的响应使用 X-Goog-Upload-Size-Received 标头来指明其已 目前已收到文件的前 43 个字节。

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

3) 从中断处恢复上传。

下面的请求通过发送文件中的剩余字节(从第 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

最佳做法

在上传媒体时,了解错误处理方面的一些最佳做法很有帮助。

  • 恢复或重试由于连接中断或任何 5xx 错误而失败的上传,此类错误包括:
    • 500 Internal Server Error
    • 502 Bad Gateway
    • 503 Service Unavailable
    • 504 Gateway Timeout
  • 如果在恢复或重试上传请求时收到任何 5xx 服务器错误,请使用指数退避算法策略。如果服务器发生超载,则可能会出现此类错误。在出现大量请求或网络流量拥堵期间,指数退避有助于缓解这类问题。
  • 不应通过指数退避算法来处理其他类型的请求,但仍然可以重试其中的许多请求。重试这些请求时,请限制重试的次数。例如,您的代码可以限制为重试 10 次或更少的次数就会报告错误。
  • 执行可续传上传时,通过从头开始整个上传过程来处理 404 Not Found 错误。

指数退避算法

指数退避是网络应用的标准错误处理策略,在此过程中,客户端按照不断增加的时间间隔定期重试失败的请求。如果因大量的请求或网络流量拥堵而导致服务器返回错误,指数退避策略能够很好地处理此类错误。相反,此策略并不适合处理与网络流量或响应时间无关的错误,例如授权凭据无效或找不到文件这样的错误。

如果使用得当,指数退避还能提高带宽使用效率、减少获得成功响应所需的请求数,并最大程度地提高并发环境中的请求吞吐量。

实现简单指数退避的流程如下:

  1. 向 API 发出请求。
  2. 收到 HTTP 503 响应(指示您应该重试该请求)。
  3. 等待 1 秒 + random_number_milliseconds 毫秒,然后重试该请求。
  4. 收到 HTTP 503 响应(指示您应该重试该请求)。
  5. 等待 2 秒 + random_number_milliseconds 毫秒,然后重试该请求。
  6. 收到 HTTP 503 响应(指示您应该重试该请求)。
  7. 等待 4 秒 + random_number_milliseconds 毫秒,然后重试该请求。
  8. 收到 HTTP 503 响应(指示您应该重试该请求)。
  9. 等待 8 秒 + random_number_milliseconds 毫秒,然后重试该请求。
  10. 收到 HTTP 503 响应(指示您应该重试该请求)。
  11. 等待 16 秒 + random_number_milliseconds 毫秒,然后重试该请求。
  12. 停止。报告或记录错误。

在上述流程中,random_number_milliseconds 是一个小于或等于 1000 的随机毫秒数。这是一项很有必要的机制,因为引入一个较小的随机延迟时间有助于更均匀地分配负载,并降低服务器发生拥堵的可能性。random_number_milliseconds 的值必须在每次等待后重新定义。

注意:等待时间始终是 (2 ^ n) 秒 + random_number_milliseconds 毫秒,其中 n 是单调递增的整数,初始值为 0。整数 n 在每次迭代(每次请求)后递增 1。

该算法设置为 n 等于 5 时终止。设置此上限的目的在于防止客户端无止尽地重试;在请求被视为“不可恢复的错误”之前,它使延迟总时间达到约 32 秒。重试更多次数是可以接受的,特别是在大数量上传正在进行的情况下;只需确保重试延迟时间的上限设置合理即可(比如说少于 1 分钟)。