ファイルのダウンロード方法 (HTML)
[この記事は、Windows ランタイム アプリを作成する Windows 8.x および Windows Phone 8.x 開発者を対象としています。Windows 10 向けの開発を行っている場合は、 「最新のドキュメント」をご覧ください]
ここでは、ファイルをダウンロードする方法について説明します。
このトピックで説明する API を使うと、アプリが Web サービスとやり取りして、写真、音楽、ビデオなどの一般的なメディア形式を使用または共有できるようになります。
JavaScript でアプリを開発する場合、インターネット上の場所のファイルを要求するために使うことができる主要オプションは 2 つあります。サイズの小さなファイル (たとえば、頻繁に取得されるサイト アセット) は、非同期 HTTP GET 要求を行う XHR を使ってダウンロードできます。この機能は、promise (JavaScript における非同期動作を可能にするプログラミング パターン) で XMLHttpRequest 呼び出しをラップします。
または、操作の持続期間内にアプリの複数回の一時停止やネットワークの可用性の変化が発生する可能性がある、サイズの大きいメディア (ビデオ、音楽) をダウンロードするときに一貫性のあるエクスペリエンスを提供するために、アプリではBackground Transferを使うことができます。バックグラウンド転送の概要については、「バックグラウンドでのデータの転送」をご覧ください。
必要条件
JavaScript アプリの作成についての一般的なヘルプは、「JavaScript を使った初めての Windows ランタイム アプリの作成」をご覧ください。このトピックでは、JavaScript の promise を使って非同期操作も実行します。このプログラミング パターンについて詳しくは、promise を使った JavaScript での非同期プログラミングに関するページをご覧ください。
アプリをネットワークに対応させるには、プロジェクトの Package.appxmanifest ファイルで該当する機能を設定する必要があります。 それぞれのネットワーク機能の定義について詳しくは、「ネットワーク分離機能を構成する方法」をご覧ください。
このトピックのすべてのバックグラウンド転送の例は、バックグラウンド転送のサンプルに基づいています。
XHR を使ってファイルをダウンロードする
JavaScript を使って基本的な非同期 HTTP 要求を開始するには、XHR を呼び出し、Option パラメーター を使って関連する要求データをこの XHR に提供します。既定では、このメソッド呼び出しは GET 要求です。このため、Option を介して提供される必須値は URL と responseType だけです。しかし、多くの Web サービスは認証を必要とするため、XHR を呼び出してセキュリティで保護された Web サービスからリソースを要求する場合はこれらの資格情報を含める必要があります。
XHR GET 操作を行う場合は、Option パラメーターで responseType を使って、応答に予期されるコンテンツの種類を指定する必要もあります。.png ファイルを要求しているこの例では、responseType 値は "blob" です。サポートされるコンテンツの種類とその要求方法について詳しくは、「WinJS.xhr によるファイルのダウンロード方法」をご覧ください。
WinJS.xhr({ url: "https://www.microsoft.com/windows/Framework/images/win_logo.png", responseType: "blob" })
.done(
function (request) {
var imageBlob = URL.createObjectURL(request.response);
var imageTag = xhrDiv.appendChild(document.createElement("image"));
imageTag.src = imageBlob;
});
JavaScript では、どの promise にも、非同期操作の結果の処理に使う関数が 2 つあります。then と done です。どちらの関数も、ダウンロードが完了したとき (つまり、readyState が 4 のとき) に呼び出される関数、エラーが発生したときに呼び出される関数、ダウンロードが進行中のとき (つまり、readyState が 2 または 3 のとき) に呼び出される関数という 3 つのパラメーターを取得します。エラーが処理されない場合、done 関数だけが例外をスローします。この関数は、エラー関数が用意されていない場合にお勧めします。
バックグラウンド転送を使ってファイルをダウンロードする
バックグラウンド転送を使う場合、各ダウンロードは DownloadOperation として存在し、操作の一時停止、再開、再起動、キャンセルに使われる多くの制御メソッドを公開します。アプリのイベント (一時停止、終了など) や接続の変更は、DownloadOperation を通じてシステムによって自動的に処理されます。ダウンロードは、アプリの一時停止中も続行し、アプリの終了以降は一時停止して保持されます。モバイル ネットワーク シナリオの場合、CostPolicy プロパティを設定することで、従量制課金接続がインターネット接続のために使われている間もアプリがダウンロードを開始または続行するかどうかを指定します。
以下に、基本的なダウンロードを作成および初期化する例と、前のアプリ セッションから続いている操作を列挙および再び取り込む例を示します。
バックグラウンド転送によるファイルのダウンロードを構成して開始する
URI とファイル名を表す文字列を使って、Uri オブジェクトと要求されたファイルを格納する StorageFile とを作成する方法を次の例で示します。この例では、新しいファイルが定義済みの場所に自動的に配置されます。 または、FileSavePicker を使ってユーザーがファイルを保存するデバイスの場所を指定できるようになります。DownloadOperation に対するコールバックを再割り当てするために呼び出される load メソッドがアプリの終了以降も持続する場合は、このセクションでこの後定義する DownloadOp クラス内にあります。
function DownloadOp() { var download = null; var promise = null; var imageStream = null; this.start = function (uriString, fileName) { try { // Asynchronously create the file in the pictures folder. Windows.Storage.KnownFolders.picturesLibrary.createFileAsync(fileName, Windows.Storage.CreationCollisionOption.generateUniqueName).done(function (newFile) { var uri = Windows.Foundation.Uri(uriString); var downloader = new Windows.Networking.BackgroundTransfer.BackgroundDownloader(); // Create a new download operation. download = downloader.createDownload(uri, newFile); // Start the download and persist the promise to be able to cancel the download. promise = download.startAsync().then(complete, error, progress); }, error); } catch (err) { displayException(err); } }; // On application activation, reassign callbacks for a download // operation persisted from previous application state. this.load = function (loadedDownload) { try { download = loadedDownload; printLog("Found download: " + download.guid + " from previous application run.<br\>"); promise = download.attachAsync().then(complete, error, progress); } catch (err) { displayException(err); } }; }
JavaScript の promise を使って定義した非同期メソッドの呼び出しに注意してください。前のコード例の 17 行目には次のコードがあります。
promise = download.startAsync().then(complete, error, progress);
非同期メソッドの後に then ステートメントが続いています。このステートメントでは、非同期メソッドの呼び出しの結果が返されたときに呼び出される、アプリで定義されたメソッドを指定しています。このプログラミング パターンについて詳しくは、「プロミスを使った JavaScript での非同期プログラミング」をご覧ください。
その他の操作制御メソッドの追加
追加の DownloadOperation メソッドを実装することによって、制御のレベルを高めることができます。上の例に次のコードを追加すると、ダウンロードをキャンセルすることができるようになります。
// Cancel download. this.cancel = function () { try { if (promise) { promise.cancel(); promise = null; printLog("Canceling download: " + download.guid + "<br\>"); if (imageStream) { imageStream.close(); } } else { printLog("Download " + download.guid + " already canceled.<br\>"); } } catch (err) { displayException(err); } };
DownloadOperation が完了するか取り消されると、関連するシステム リソースがすべて解放されます。ただし、これらのイベントのどちらかが発生する前にアプリが終了した場合、ダウンロードは一時停止され、バックグラウンドで保持されます。以下の例は、持続しているダウンロードを新しいアプリ セッションに再び取り込む方法を示しています。
持続している操作を起動時に列挙する
持続している操作を列挙する関数を定義する前に、返される DownloadOperation オブジェクトを格納する配列を作成する必要があります。
var downloadOps = [];
次に、持続している操作を列挙してそれらを配列に格納する関数を定義します。 持続している DownloadOperation に対するコールバックを再割り当てするために呼び出される load メソッドは、このセクションでこの後定義する DownloadOp 例内にあります。
// Enumerate outstanding downloads. Windows.Networking.BackgroundTransfer.BackgroundDownloader.getCurrentDownloadsAsync().done(function (downloads) { for (var i = 0; i < downloads.size; i++) { var download = new DownloadOp(); download.load(downloads[i]); downloadOps.push(download); } });
注
Windows Phone ストア アプリでは、バックグラウンド転送はアプリがフォアグラウンドでない場合でも引き続き実行されます。アプリはこのシナリオで動作していないので、転送の完了時に通知を受け取りません。アプリの再開時に、完了した転送の進行状況をそのままチェックすると、状態は BackgroundTransferStatus.Running になります。ただし、上のコード例のように、転送に接続すると、タスク完了ハンドラーが起動し、転送状態が更新されます。
要求のタイムアウト
次の 2 つの主要接続タイムアウト シナリオを考慮する必要があります。
転送のために新しい接続を確立する場合、5 分以内に接続が確立しないと、接続要求は中止されます。
接続が確立された後、2 分以内で応答を受け取らなかった HTTP 要求メッセージは中止されます。
どちらのシナリオにおいても、バックグラウンド転送はインターネット接続があることを前提に、最高 3 回まで自動的に要求を再試行します。インターネット接続が検出されないと、検出されるまで別の要求は待機します。
XHR 操作に対しては、WinJS.Promise.timeout プロパティを使って特定のタイムアウト値を定義できます。この設定方法について詳しくは、「WinJS.xhr を使う場合にタイムアウト値を設定する」をご覧ください。
デバッグのガイダンス
Microsoft Visual Studio でデバッグ セッションを停止することは、アプリを閉じることに相当します。 デバッグ時であっても、アプリでは、以前のセッションから持続しているダウンロードを列挙し、再開、再実行、取り消しを行うことができる必要があります。たとえば、現在のデバッグ セッションで以前の操作が重要ではない場合、アプリの起動時に、列挙された持続しているダウンロード操作をアプリで取り消すことができます。
アプリ マニフェストの変更など、Visual Studio プロジェクトの更新があり、アプリがアンインストールされ、もう一度展開された場合、GetCurrentUploadsAsync は、前のアプリの展開を使って作成された操作を列挙できません。
詳しくは、「Windows ストア アプリのデバッグとテスト」をご覧ください。
開発時にバックグラウンド転送を使うと、完了したアクティブな転送操作の内部キャッシュが同期しなくなる状況が発生する可能性があります。このため、新しい転送操作を開始できない場合や、既存の操作や BackgroundTransferGroup オブジェクトを処理できない場合があります。状況によっては、既存の操作を処理しようとすると、クラッシュの原因となる可能性があります。これは、TransferBehavior プロパティが Parallel に設定されている場合に発生する可能性があります。この問題は、開発中に特定のシナリオでのみ発生し、アプリのエンド ユーザーには適用されません。
Visual Studio を使う 4 つのシナリオで、この問題が発生する可能性があります。
- 既にあるプロジェクトと同じアプリ名を持つ新しいプロジェクトを、別の言語で作成する (C++ から C# など)。
- 既にあるプロジェクトのターゲット アーキテクチャを変更する (x86 から x64 など)。
- 既にあるプロジェクトのカルチャを変更する (ニュートラルから en-US など)。
- 既にあるプロジェクトのパッケージ マニフェストで機能を追加または削除する (エンタープライズ認証を追加するなど)。
機能を追加または削除するマニフェストの更新など、通常のアプリのサービスでは、アプリのエンド ユーザーに対する展開でこの問題は発生しません。
この問題を回避するには、アプリのすべてのバージョンを完全にアンインストールし、新しい言語、アーキテクチャ、カルチャ、または機能をもう一度展開します。この操作は、スタート画面で行うか、PowerShell と Remove-AppxPackage コマンドレットを使って行うことができます。
要約と次のステップ
このトピックでは、JavaScript で と Background Transfer API を使ってファイルをダウンロードする方法について説明しました。この 2 つの相違点を説明すると共に、実際のアプリケーションがダウンロードのサイズと有効期間にいかに左右されるかを示しました。
XHR とバックグラウンド転送を使って、ファイルをアップロードすることもできます。主要概念とサンプルについては、「ファイルのアップロード方法」をご覧ください。
関連トピック
その他
promise を使った JavaScript での非同期プログラミングに関する記事
JavaScript を使った初めての Windows ランタイム アプリの作成
リファレンス
Windows.Networking.BackgroundTransfer
サンプル