Google Chrome拡張機能からファイルダウンロードを行う手法一覧


一覧と言ってみたものの網羅しているかは不明。
他にあったら教えてほしいです。

比較表

観点は3つ。

  • permissions: downloadが必要か
  • 保存プロンプトで初期表示されるファイル名が指定できるか
  • 保存プロンプトで選択した保存先フォルダ情報が保持され、次回保存時のプロンプトでそのフォルダが初期表示されるか
手法 permissions: download ファイル名指定 保存先フォルダの保持
1 不要 同一オリジン内のみ〇
2 必要 ×
3 必要 ×
4 必要 ×

ファイル名指定と保存先フォルダの保持どっちも〇なのがほしいんだけどなぁ。

手法1: a要素を生成してクリックを発火

シンプルなやつ。

event.js
var aElement = document.createElement('a');
aElement.href = 'http://example.com/sample.jpg';
aElement.download = 'test.jpg';

aElement.click();

良い点:

  • permissionを与える必要がない
  • 同一オリジン内ではファイル名が指定できる
    (example.com上でexample.com下のファイルを落とす場合)
  • 保存先フォルダ情報が保持される

悪い点:

  • 中ではダウンロードを投げているのにdownloadsのpermission与えないの、なんかちょっときもちわるくないですか?
  • クロスオリジンだとファイル名の指定が効かない
    (example.com上でqiita.comなど異なるオリジン下のファイルを落とす場合) 1

手法2: chrome.downloads.downloadメソッドを使う

これもシンプル。chrome.downloads API2のdownloadメソッド3を使う。

manifest.json
{
    ...
    "permissions": [
      "downloads"
    ],
    ...
}
event.js
chrome.downloads.download({
    url: 'http://example.com/sample.jpg', 
    filename: 'test.jpg'
});

良い点:

  • permissionsが実態に沿ってる
  • ファイル名が指定できる
  • なにをしているかわかりやすい

悪い点:

  • permission与えるのめんどくさい
  • 保存先フォルダ情報が保持されない。毎回必ず、Chromeの設定で保存先に指定しているフォルダがプロンプトで初期表示される

手法3: ダウンロード発火後にchrome.downloads.onDeterminingFilenameでファイル名を変える

ダウンロードの発火後、ファイル名を決定するときに発生するchrome.downloads.onDeterminingFilenameイベント4のタイミングでファイル名を変える。

発火には手法1か2を使うことになるが、どちらも選んでもonDeterminingFilenameを使う時点でdownloadsのpermissionは必要。

manifest.json
{
    ...
    "permissions": [
      "downloads"
    ],
    ...
}
event.js
chrome.downloads.onDeterminingFilename.addListener(function(downloadItem, suggest) {
    suggest({ filename: 'test.jpg' });
});

// 手法1か2でダウンロードを発火 (どちらを使っても結果は同じ)
chrome.downloads.download({
    url: 'http://example.com/sample.jpg',
});

良い点:

  • permissionsが実態に沿ってる
  • ファイル名が指定できる

悪い点:

  • permission与えるのめんどくさい
  • 保存先フォルダ情報が保持されない。毎回必ず、Chromeの設定で保存先に指定しているフォルダがプロンプトで初期表示される
  • 回りくどい。単純にダウンロードしたいだけの場合には使わないと思う

手法4: ダウンロード発火後にonDeterminingFilenameのファイル名指定であえてエラーを起こす

手法3の亜種。onDeterminingFilenameイベント4を使うが、あえて指定できない形式のファイル名を指定する。

Absolute paths, empty paths, and paths containing back-references ".." will be ignored.

つまり絶対パスを渡すとエラーとなるのだが、するとあら不思議、なぜか保存先フォルダ情報が保持される。

内部でエラーを吐いているが保存自体は正常に実行できる。
参考: chrome.downloads.onDeterminingFilenameを使うと最後に保存したフォルダを記憶してくれなくなるがfilenameに絶対パスを指定することでエラーを起こし無理やり機能させる

manifest.json
{
    ...
    "permissions": [
      "downloads"
    ],
    ...
}
event.js
chrome.downloads.onDeterminingFilename.addListener(function(downloadItem, suggest) {
    suggest({ filename: 'C://test.jpg' });
});

// 手法1か2でダウンロードを発火 (どちらを使っても結果は同じ)
chrome.downloads.download({
    url: 'http://example.com/sample.jpg',
});

良い点:

  • permissionsが実態に沿ってる
  • 保存先フォルダ情報が保持される

悪い点:

  • permission与えるのめんどくさい
  • ファイル名が指定できない。
    上記コードではC://test.jpgとしているが、プロンプトでの初期ファイル名はtest.jpgにはならない。URLから持ってきたsample.jpgのまま。
    発火時にファイル名を指定していても同じ結果となる
  • 変化球である