ファイルのアップロード

Google Play Developer API を使用して、画像APK拡張ファイル編集のためにアップロードできます。以下では、例として画像を取り上げます。

アップロード オプション

Google Play Developer API を使用して、特定のタイプのバイナリデータ(メディア)をアップロードできます。アップロードできるデータの具体的な特性については、メディア アップロードをサポートする方法のリファレンス ページに記載されています。

  • アップロード ファイルの最大サイズ: この方法で保存できるデータ量の上限。
  • 使用可能なメディア MIME タイプ: この方法で保存できるバイナリデータのタイプ。

アップロード リクエストは次のいずれかの方法で行えます。使用する方法は、uploadType リクエスト パラメータで指定します。

  • シンプル アップロードuploadType=media)。比較的小さいファイル(例: 5 MB 以下)を高速で転送します。
  • マルチパート アップロードuploadType=multipart)。比較的小さいファイルをメタデータとともに高速で転送します。ファイルとそのファイルを記述するメタデータのすべてを 1 つのリクエストにまとめて転送します。
  • 再開可能アップロードuploadType=resumable)。比較的大きいファイルで特に重要な、信頼性の高い転送を行います。この方法ではセッション開始リクエストを使用します。必要に応じてメタデータを追加できます。これは、ほとんどのアプリで使用できるおすすめの方法です。アップロードごとに HTTP リクエストを 1 件追加する手間を厭わなければ、比較的小さいファイルでも使用できます。

メディアをアップロードする際は、特別な URI を使用します。具体的には、メディア アップロードをサポートする方法では 2 つの URI エンドポイントを使用します。

  • メディア用の /upload URI。アップロード エンドポイントの形式は、標準のリソース URI に接頭辞「/upload」を付けたものです。この URI は、メディアデータそのものを転送する場合に使用します。

    例: POST /upload/androidpublisher/v3/applications/packageName/edits/editId/listings/language/imageType

  • メタデータ用の標準のリソース URI。リソースにデータ フィールドが含まれている場合は、それらのフィールドを使用して、アップロードするファイルを記述するメタデータを格納します。この URI は、メタデータの値を作成または更新する場合に使用できます。

    例: POST /androidpublisher/v3/applications/packageName/edits/editId/listings/language/imageType

シンプル アップロード

ファイルをアップロードする最も簡単な方法は、シンプル アップロード リクエストを行うことです。この方法は次の場合におすすめです。

  • ファイルが小さく、接続が失敗したときはファイル全体を再度アップロードできる場合。
  • 送信するメタデータがない場合。たとえば、アップロードするリソースのメタデータを別のリクエストで送信することを予定している場合や、メタデータがサポートされていないか利用できない場合などです。

シンプル アップロードを使用するには、アップロード方法の /upload URI への POST リクエストまたは PUT リクエストを作成し、クエリ パラメータ uploadType=media を追加します。次に例を示します。

POST https://www.googleapis.com/upload/androidpublisher/v3/applications/packageName/edits/editId/listings/language/imageType?uploadType=media

シンプル アップロード リクエストの作成時に使用する HTTP ヘッダーの内容は次のとおりです。

  • Content-Type: アップロード方法で使用可能なアップロード メディア データタイプのいずれかに設定します(API リファレンスをご覧ください)。
  • Content-Length: アップロードするバイト数に設定します。チャンク形式の転送エンコードを使用する場合は不要です。

例: シンプル アップロード

Google Play Developer API でのシンプル アップロード リクエストの使用例を次に示します。

POST /upload/androidpublisher/v3/applications/packageName/edits/editId/listings/language/imageType?uploadType=media HTTP/1.1
Host: www.googleapis.com
Content-Type: image/png
Content-Length: number_of_bytes_in_file
Authorization: Bearer your_auth_token

PNG data

リクエストが成功すると、HTTP ステータス コード 200 OK がメタデータとともにサーバーから返されます。

HTTP/1.1 200
Content-Type: application/json

{
 
"image": {
   
"id": string,
   
"url": string,
   
"sha1": string
 
}
}

マルチパート アップロード

アップロードするデータと一緒にメタデータを送信する場合は、単一の multipart/related リクエストを作成できます。この方法は、送信するデータが小さく、接続が失敗したときはデータ全体を再アップロードできる場合に適しています。

マルチパート アップロードを使用するには、アップロード方法の /upload URI への POST リクエストまたは PUT リクエストを作成し、クエリ パラメータ uploadType=multipart を追加します。次に例を示します。

POST https://www.googleapis.com/upload/androidpublisher/v3/applications/packageName/edits/editId/listings/language/imageType?uploadType=multipart

マルチパート アップロード リクエストの作成時に使用する最上位の HTTP ヘッダーの内容は次のとおりです。

  • Content-Type: multipart/related に設定し、リクエストのパートの識別に使用するバウンダリ文字列を追加します。
  • Content-Length: リクエスト本文の総バイト数に設定します。リクエストのメディア部分は、このアップロード方法で指定したファイルサイズの上限より小さくする必要があります。

リクエスト本文の形式は multipart/related コンテンツ タイプ(RFC2387)として設定され、厳密に 2 つのパートで構成されます。パートはバウンダリ文字列で識別され、最後のバウンダリ文字列の後に 2 つのハイフンが続きます。

マルチパート リクエストの各パートには、次に示す追加の Content-Type ヘッダーが必要です。

  1. メタデータ パート: 最初に配置する必要があります。Content-Type は、使用可能なメタデータ形式のいずれかと一致しなければなりません。
  2. メディアパート: 2 番目に配置する必要があります。Content-Type は、アップロード方法で使用可能なメディア MIME タイプのいずれかと一致しなければなりません。

各アップロード方法で使用可能なメディア MIME タイプの一覧とアップロード ファイルのサイズの上限については、API リファレンスをご覧ください。

注: 関連データをアップロードせずにメタデータ部分のみを作成または更新するには、単に POST リクエストまたは PUT リクエストを標準のリソース エンドポイント(https://www.googleapis.com/androidpublisher/v3/applications/packageName/edits/editId/listings/language/imageType)に送信します。

例: マルチパート アップロード

Google Play Developer API でのマルチパート アップロード リクエストの例を次に示します。

POST /upload/androidpublisher/v3/applications/packageName/edits/editId/listings/language/imageType?uploadType=multipart HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer your_auth_token
Content-Type: multipart/related; boundary=foo_bar_baz
Content-Length: number_of_bytes_in_entire_request_body

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

{
 
"image": {
   
"id": string,
   
"url": string,
   
"sha1": string
 
}
} --foo_bar_baz Content-Type: image/png PNG data --foo_bar_baz--

リクエストが成功すると、HTTP ステータス コード 200 OK がメタデータとともにサーバーから返されます。

HTTP/1.1 200
Content-Type: application/json

{
 
"image": {
   
"id": string,
   
"url": string,
   
"sha1": string
 
}
}

再開可能アップロード

データファイルのアップロードの信頼性を向上させるには、再開可能アップロード プロトコルを使用します。このプロトコルを使用すると、通信障害でデータの送信が中断されても、後でアップロード操作を再開できます。この方法は、大容量のファイルを転送するときや、ネットワークの中断やその他の送信エラーが起こる可能性が高いとき(たとえばモバイル クライアント アプリからアップロードするとき)に、特に役立ちます。また、ネットワーク障害が発生した場合に大容量のファイルのアップロードを最初からやり直す必要がなくなり、帯域幅の使用を削減できます。

再開可能アップロードを使用する手順は次のとおりです。

  1. 再開可能セッションを開始する: メタデータ(存在する場合)を含むアップロード URI への最初のリクエストを送信します。
  2. 再開可能セッション URI を保存する: 最初のリクエストのレスポンスで返されたセッション URI を保存します。この URI はセッションの後続のリクエストで使用します。
  3. ファイルをアップロードする: 再開可能セッション URI にメディア ファイルを送信します。

また、再開可能アップロードを使用するアプリには、中断されたアップロードを再開するためのコードも必要です。アップロードが中断された場合は、正常に受信されたデータ量を確認し、中断されたポイントからアップロードを再開します。

注: アップロード URI は 1 週間で有効期限が切れます。

ステップ 1: 再開可能セッションを開始する

再開可能アップロードを開始するには、アップロード方法の /upload URI への POST リクエストまたは PUT リクエストを作成し、クエリ パラメータ uploadType=resumable を追加します。次に例を示します。

POST https://www.googleapis.com/upload/androidpublisher/v3/applications/packageName/edits/editId/listings/language/imageType?uploadType=resumable

この最初のリクエストでは、本文は空またはメタデータのみのいずれかです。アップロードするファイルの実際の内容は後続のリクエストで転送します。

最初のリクエストでは次の HTTP ヘッダーを使用します。

  • X-Upload-Content-Type: 後続のリクエストで転送するアップロード データのメディア MIME タイプに設定します。
  • X-Upload-Content-Length: 後続のリクエストで転送するアップロード データのバイト数に設定します。このリクエストの時点でデータの長さが不明な場合、このヘッダーは省略できます。
  • Content-Type(メタデータを送信する場合): メタデータのデータ型に合わせて設定します。
  • Content-Length: 最初のリクエストの本文で送信するバイト数に設定します。チャンク形式の転送エンコードを使用する場合は不要です。

各アップロード方法で使用可能なメディア MIME タイプの一覧とアップロード ファイルのサイズの上限については、API リファレンスをご覧ください。

例: 再開可能セッション開始リクエスト

Google Play Developer API で再開可能セッションを開始する方法の例を次に示します。

POST /upload/androidpublisher/v3/applications/packageName/edits/editId/listings/language/imageType?uploadType=resumable HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer your_auth_token
Content-Length: 38
Content-Type: application/json; charset=UTF-8
X-Upload-Content-Type: image/png
X-Upload-Content-Length: 2000000

{
 
"image": {
   
"id": string,
   
"url": string,
   
"sha1": string
 
}
}

注: 最初の再開可能な更新リクエストをメタデータなしで作成する場合は、リクエストの本文を空にして、Content-Length ヘッダーを 0 に設定します。

次に、レスポンスの処理方法について説明します。

ステップ 2: 再開可能セッション URI を保存する

セッション開始リクエストが成功すると、API サーバーはレスポンスとして HTTP ステータス コード 200 OK を返します。また、再開可能セッション URI を示す Location ヘッダーも返します。下記の例の Location ヘッダーには、このセッションで使用する一意のアップロード ID を示す upload_id クエリ パラメータ部分が含まれています。

例: 再開可能セッション開始リクエストのレスポンス

ステップ 1 のリクエストに対するレスポンスは次のとおりです。

HTTP/1.1 200 OK
Location: https://www.googleapis.com/upload/androidpublisher/v3/applications/packageName/edits/editId/listings/language/imageType?uploadType=resumable&upload_id=xa298sd_sdlkj2
Content-Length: 0

上記のレスポンス例に示されている Location ヘッダーの値は、実際にファイルをアップロードするとき、またはアップロード ステータスをクエリするときに、HTTP エンドポイントとして使用するセッション URI です。

後続のリクエストで使用できるように、セッション URI をコピーして保存します。

ステップ 3: ファイルをアップロードする

ファイルをアップロードするには、前のステップで取得したアップロード URI に PUT リクエストを送信します。アップロード リクエストの形式は次のとおりです。

PUT session_uri

再開可能なファイル アップロードのリクエストを作成するときに使用する HTTP ヘッダーには、Content-Length を含めます。この値は、このリクエストでアップロードするバイト数(通常はアップロード ファイルのサイズ)に設定します。

例: 再開可能なファイル アップロード リクエスト

この例で 2,000,000 バイトの PNG ファイル全体をアップロードする再開可能なリクエストは次のとおりです。

PUT https://www.googleapis.com/upload/androidpublisher/v3/applications/packageName/edits/editId/listings/language/imageType?uploadType=resumable&upload_id=xa298sd_sdlkj2 HTTP/1.1
Content-Length: 2000000
Content-Type: image/png

bytes 0-1999999

リクエストが成功すると、サーバーは HTTP 201 Created とともに、このリソースに関連付けられているメタデータをレスポンスとして返します。再開可能セッションの最初のリクエストが既存のリソースを更新する PUT だった場合、成功時のレスポンスでは、200 OK とともに、このリソースに関連付けられているメタデータが返されます。

アップロード リクエストが中断された場合や、サーバーから HTTP 503 Service Unavailable などの 5xx レスポンスが返された場合は、中断されたアップロードを再開するに記載された手順に沿ってください。


チャンクでファイルをアップロードする

再開可能アップロードでは、ファイルをチャンクに分割し、一連のリクエストを送信して各チャンクを順番にアップロードすることもできます。しかし、リクエスト数の増加に伴ってパフォーマンスが下がるため、このアプローチはおすすめしません。また、通常は不要です。ただし、1 つのリクエストで転送するデータの量を減らすために、チャンクの使用が必要になることもあります。Google App Engine リクエストの一部のクラスのように、リクエストごとに固定の時間制限がある場合は、この方法が役立ちます。また、アップロードの進行状況がデフォルトでサポートされていない従来のブラウザで、アップロードの進行状況を提供することもできます。


中断されたアップロードを再開する

レスポンスを受信する前にアップロード リクエストが終了した場合や、サーバーから HTTP 503 Service Unavailable レスポンスが返された場合は、中断されたアップロードを再開する必要があります。その手順は次のとおりです。

  1. ステータスをリクエストする: 空の PUT リクエストをアップロード URI に送信して、アップロードの現在のステータスをクエリします。このリクエストの HTTP ヘッダーには、ファイルの現在の位置が不明であることを示す Content-Range ヘッダーを含める必要があります。たとえば、ファイルの合計サイズが 2,000,000 バイトの場合は、Content-Range*/2000000 に設定します。ファイル全体のサイズがわからない場合は、Content-Range*/* に設定します。

    注: アップロードが中断された場合だけでなく、チャンクのアップロードの合間にもステータスをリクエストできます。これは、従来のブラウザでアップロードの進行状況を表示したい場合などに役立ちます。

  2. アップロードされたバイト数を取得する: ステータス クエリからのレスポンスを処理します。サーバーはレスポンスの Range ヘッダーを使用して、その時点までに何バイト受信したかを示します。たとえば、Range ヘッダーが 0-299999 の場合、ファイルの先頭から 300,000 バイトが受信されたことがわかります。
  3. 残りのデータをアップロードする: リクエストの再開ポイントがわかったので、最後に残りのデータまたは現在のチャンクを送信します。どちらの場合も、残りのデータを独立したチャンクとして扱う必要があります。つまり、アップロードを再開するときに Content-Range ヘッダーを送信する必要があります。
例: 中断されたアップロードを再開する

1)アップロード ステータスをリクエストする。

次のリクエストでは、Content-Range ヘッダーを使用して、2,000,000 バイトのファイルで現在の位置が不明であることを示しています。

PUT {session_uri} HTTP/1.1
Content-Length: 0
Content-Range: bytes */2000000

2)レスポンスから、これまでにアップロードされたバイト数を抽出する。

サーバーのレスポンスの Range ヘッダーは、これまでにファイルの先頭の 43 バイトを受信したことを示しています。Range ヘッダーの上限値を使用して、再開可能アップロードを開始する位置を決定します。

HTTP/1.1 308 Resume Incomplete
Content-Length: 0
Range: 0-42

注: アップロードが完了しているにもかかわらず、ステータスのレスポンスが 201 Created または 200 OK になることがあります。すべてのバイトがアップロードされてからクライアントがサーバーからのレスポンスを受信するまでの間に接続が切断されると、この現象が起こる可能性があります。

3)中断した位置からアップロードを再開する。

次のリクエストでは、アップロードが再開されて、ファイルのバイト位置 43 以降の残りのバイトが送信されます。

PUT {session_uri} HTTP/1.1
Content-Length: 1999957
Content-Range: bytes 43-1999999/2000000

bytes 43-1999999

おすすめの方法

メディアをアップロードする場合は、エラー処理に関するおすすめの方法が参考になります。

  • 接続の中断や次のような 5xx エラーが原因で失敗した場合は、アップロードを再開または再試行します。
    • 500 Internal Server Error
    • 502 Bad Gateway
    • 503 Service Unavailable
    • 504 Gateway Timeout
  • アップロード リクエストを再開または再試行したときに 5xx サーバーエラーが返された場合は、指数バックオフ戦略を使用します。この種のエラーは、サーバーが過負荷になっている場合に発生することがあります。指数バックオフは、リクエスト量またはネットワーク トラフィックが多い時間帯に、この種の問題を緩和するために役立ちます。
  • その他の種類のリクエストは指数バックオフでは処理できませんが、多くのリクエストは再試行が可能です。リクエストを再試行する際に、再試行回数を制限します。たとえば、コードを使用して、再試行回数を 10 回に制限し、それを超えたらエラーを出力するようにします。
  • 再開可能アップロードの実行中に 404 Not Found または 410 Gone エラーが発生した場合は、ファイル全体のアップロードを最初からやり直します。

指数バックオフ

指数バックオフはネットワーク アプリで使用される標準的なエラー処理戦略で、失敗したリクエストをクライアントが再試行する際に、失敗するたびに次の再試行までの待機時間を増やしていく方法です。指数バックオフは、リクエスト量またはネットワーク トラフィックが多いためにサーバーがエラーを返す場合のエラー処理に適しています。一方、認証情報が無効なエラーやファイルが見つからないエラーなど、ネットワーク量または応答時間と無関係なエラーの処理には適していません。

指数バックオフを適切に使用すると、帯域幅の使用の効率を高め、正常なレスポンスを受け取るために必要なリクエストの数を減らし、同時実行環境におけるリクエストのスループットを最大化することができます。

単純な指数バックオフを実装するフローを次に示します。

  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 は 1,000 以下のランダムなミリ秒数です。これが必要なのは、短いランダムな遅延時間を挿入することで負荷をより均等に分散し、サーバーの暴走を防ぐためです。random_number_milliseconds の値は、個々の待機の後で再定義する必要があります。

注: 待機時間は常に (2 ^ n) + random_number_milliseconds となります。n は、最初はゼロとして定義され、その後単調に増加する整数です。整数 n は、反復(個々のリクエスト)のたびに 1 ずつ増加します。

上記のアルゴリズムは、n が 5 に達したら停止するように設定されています。この上限によって、クライアントが無限に再試行を繰り返すことを防ぎます。総遅延時間が約 32 秒に達すると、リクエストは「回復不能なエラー」と判断されます。再試行の最大回数を増やすこともできます(特に、長時間かかるアップロードの場合など)。ただし、再試行の遅延時間には必ず合理的な上限(たとえば 1 分未満)を設定してください。

API クライアント ライブラリ ガイド