WKWebView環境でダウンロードした画像を表示してみる
Monacaチームの小田川です。
これまでは、Qiitaに月一くらいのペースで投稿していましたが、今回からアシアルブログに投稿することになりました。今回は、WKWebView環境で外部サー バからダウンロードした画像を画面に表示するテストをしてみたいと思います。
file:// スキーム
Monacaで利用しているCordovaでは、外部リソースにアクセスする際に、file://
スキームが使用されます。WKWebViewでは、セキュリティー制限により、file:// スキームでリソースにアクセスすることができません。
Monacaプロジェクトの www
フォルダ内に配置されているリソースの場合は、Monacaから提供されている Custom Schemeプラグイン
を使用することで対応することができますが、外部サーバからアプリ内にダウンロードした画像ファイルなどには、アクセスすることができません。
ダウンロードした画像を表示する
外部サーバからアプリ内にダウンロードした画像ファイルなどにアクセスする場合は、blob
データを利用します。
ダウンロードする画像ファイルをblobデータとしてダウンロードした場合は、window.URL.createObjectURL
から取得できるURLを使用することで、画像にアクセスすることができます。
<script>
function downloadFile1() {
var xmlHttpRequest = new XMLHttpRequest();
xmlHttpRequest.open("GET", "https://cordova.apache.org/static/img/cordova_bot.png", true);
xmlHttpRequest.responseType = "blob";
xmlHttpRequest.onload = function(event) {
var blob = xmlHttpRequest.response;
if (blob) {
// blobデータのURLを取得
var url = window.URL.createObjectURL(blob);
// 画像を表示
document.getElementById('img1').src = url;
} else {
console.log('error');
}
};
// ファイルをダウンロード
xmlHttpRequest.send();
}
</script>
<body>
<input type="button" value="downloadFile1" onclick="downloadFile1()" />
<img id="img1" />
</body>
blobデータとして画像を表示するため、Content-Security-Policy
に blob:
を追加する必要があります。
<meta http-equiv="Content-Security-Policy" content="default-src * blob: data: gap: https://ssl.gstatic.com; style-src * 'unsafe-inline'; script-src * 'unsafe-inline' 'unsafe-eval'">
WKWebView用のカスタムビルドデバッガーで window.URL.createObjectURL を使用した場合は、下記のようなURLが取得されます。
blob:monaca-debugger://アプリID.monaca.io/99e8aba5-f365-4b3c-b17a-bac2ec802dab
デバッグビルドしたアプリで window.URL.createObjectURL を使用した場合は、下記のようなURLが取得されます。
blob:null/c1212065-cb51-4d73-911b-e1b2e9ccb559
WKWbViewでは、file:// スキームが null
に変換されます。
上記のような null が設定されたURLでも画像が表示されますが、Custom Schemeプラグインを有効にした場合は、下記のようなURLが取得されます。
blob:monaca-app://monaca.io/c1212065-cb51-4d73-911b-e1b2e9ccb559
ダウンロードしてファイル保存した画像を表示する その1
ダウンロードしてファイル保存した画像の場合も、保存した画像ファイルをblobデータとして取得することで、window.URL.createObjectURL を利用することができます。
サンプルでは、Fileプラグイン
を使用しています。
Fileプラグインの cordova.file.documentsDirectory
から取得できるDocumentsフォルダパスにダウンロードしたファイルを保存しています。
<script>
function downloadFile2() {
// ファイル保存ディレクトリに cordova.file.documentsDirectory を設定
window.resolveLocalFileSystemURL(cordova.file.documentsDirectory, function (dirEntry) {
var fileName = "sample.png";
var mimeType = "image/png"
var xmlHttpRequest = new XMLHttpRequest();
xmlHttpRequest.open("GET", "https://cordova.apache.org/static/img/cordova_bot.png", true);
xmlHttpRequest.responseType = 'blob';
xmlHttpRequest.onload = function() {
if (this.status == 200) {
var blob = new Blob([this.response], { type: mimeType });
// ファイルの作成
dirEntry.getFile(fileName, { create: true, exclusive: false }, function (fileEntry) {
fileEntry.createWriter(function (fileWriter) {
fileWriter.onwriteend = function() {
if (blob.type == mimeType) {
fileEntry.file(function (file) {
var reader = new FileReader();
reader.onloadend = function() {
// 読み込んだデータから blob データを作成
var blob = new Blob([new Uint8Array(this.result)], { type: mimeType });
// ファイルパスの取得
// file:// スキームパスのため、アクセスできません。
// var url = fileEntry.toURL();
// blobデータのURLを取得
var url = window.URL.createObjectURL(blob);
console.log("fileEntry.toURL: " + fileEntry.toURL());
console.log("window.URL.createObjectURL: " + window.URL.createObjectURL(blob));
// 画像を表示
document.getElementById('img1').src = url;
};
// ファイルの読み込み
reader.readAsArrayBuffer(file);
});
}
};
fileWriter.onerror = function(err) {
console.log("Failed file write: " + err.toString());
};
// ファイルへ書き込み
fileWriter.write(blob);
});
});
}
};
// ファイルをダウンロード
xmlHttpRequest.send();
}, function(err) {
console.log('error: resolveLocalFileSystemURL');
});
}
</script>
<body>
<input type="button" value="downloadFile2" onclick="downloadFile2()" />
<img id="img1" />
</body>
画像を表示するためのURLに fileEntry.toURL()
を使用した場合は、file:// スキームパスになるため、画像は表示されません。
インスペクターで確認すると、下記のようなエラーが表示されます。
Not allowed to load local resource: file:///var/mobile/Containers/Data/Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Documents/sample.png
Failed to load resource: The operation couldn’t be completed. Operation not permitted
ダウンロードしてファイル保存した画像を表示する その2
WKWebViewの file:// スキーム制限は、ファイルが保存されている場所に依存しています。
ダウンロードしてファイル保存した画像を表示する その1
では、ファイルの保存場所に cordova.file.documentsDirectory
を指定しました。この cordova.file.documentsDirectory で取得できるパスは、アプリ内の Documents
フォルダになります。Documentsフォルダの場合は、file:// スキーム制限が適用されます。
アプリ内の tmp
フォルダ内のファイルの場合は、file:// スキーム制限は適用されません。そのため、tmpフォルダ内のファイルの場合は、file:// スキームのパスを使用することができます。tmpフォルダのパスは、cordova.file.tempDirectory
で取得できます。
注意点として、Custom Schemeプラグインを有効にしている場合や、WKWebView用のカスタムビルドデバッガーを使用している場合は、仕様上、file:// スキーム制限が適用されるため、window.URL.createObjectURL を使用してください。
おわりに
WKWebView環境でダウンロードした画像などが表示されない場合は、一度、window.URL.createObjectURL
で取得したURLやファイルの保存先を cordova.file.tempDirectory
にして試してみてください。