让 Chrome 扩展程序下载文件

Posted

技术标签:

【中文标题】让 Chrome 扩展程序下载文件【英文标题】:Making a Chrome Extension download a file 【发布时间】:2011-06-18 05:30:04 【问题描述】:

我正在创建一个可以从网站下载 mp3 文件的扩展程序。我试图通过创建一个带有 mp3 文件链接的新选项卡来做到这一点,但 chrome 一直在播放器内打开它而不是下载它。有什么方法可以创建一个弹出窗口来要求用户“另存为”文件?

【问题讨论】:

见***.com/questions/399486/… 【参考方案1】:

我在Github 上的Appmator 代码中按照以下方式进行了操作。

基本方法是构建你的 Blob,但是你想要(Chrome 在 XmlHttpRequest 上有一个 responseBlob,所以你可以使用它),创建一个 iframe(隐藏,display:none)然后将 iframe 的 src 分配为 Blob .

这将启动下载并将其保存到文件系统。唯一的问题是,您还不能设置文件名。

var bb = new (window.BlobBuilder || window.WebKitBlobBuilder)();

var output = Builder.output("binary":true);
var ui8a = new Uint8Array(output.length);

for(var i = 0; i< output.length; i++) 
  ui8a[i] = output.charCodeAt(i);


bb.append(ui8a.buffer);

var blob = bb.getBlob("application/octet-stream");
var saveas = document.createElement("iframe");
saveas.style.display = "none";

if(!!window.createObjectURL == false) 
  saveas.src = window.webkitURL.createObjectURL(blob); 

else 
  saveas.src = window.createObjectURL(blob); 


document.body.appendChild(saveas);

使用 XmlHttpRequest 的 responseBlob 的示例(参见:http://www.w3.org/TR/XMLHttpRequest2/#dom-xmlhttprequest-responseblob)

var xhr = new XmlHttpRequest();
xhr.overrideMimeType("application/octet-stream"); // Or what ever mimeType you want.
xhr.onreadystatechanged = function() 
if(xhr.readyState == 4 && xhr.status == 200) 

  var blob = xhr.responseBlob();
  var saveas = document.createElement("iframe");
  saveas.style.display = "none";

  if(!!window.createObjectURL == false) 
    saveas.src = window.webkitURL.createObjectURL(blob); 
  
  else 
    saveas.src = window.createObjectURL(blob); 
  

  document.body.appendChild(saveas);

【讨论】:

在哪里指定要下载的文件? 这取决于你。它可能是 xhr 请求上的 responseBlob 是的,您可以编辑代码以显示如何执行此操作吗?我不知道该把位置放在哪里。 如何设置下载为正确的文件类型? Chrome 一直尝试将其下载为 html 文件。创建 blob 的页面也会冻结并崩溃。看起来 blob 的源也是空白的。 您能否展示一些示例代码,说明您正在尝试执行的操作导致其崩溃 - 很难说出您现在正在尝试执行的操作。我会说我添加了一小段代码来覆盖 mimetype。【参考方案2】:

我使用了解决方案的变体here

var downloadCSS = function () 
    window.URL = window.webkitURL || window.URL;
    file = new BlobBuilder(); //we used to need to check for 'WebKitBlobBuilder' here - but no need anymore
    file.append(someTextVar); //populate the file with whatever text it is that you want
    var a = document.createElement('a');
    a.href = window.URL.createObjectURL(file.getBlob('text/plain'));
    a.download = 'combined.css'; // set the file name
    a.style.display = 'none';
    document.body.appendChild(a);
    a.click(); //this is probably the key - simulatating a click on a download link
    delete a;// we don't need this anymore

您需要记住的一件事是,此代码需要在页面上执行,而不是在您的扩展程序上执行 - 否则用户将看不到 chrome 执行的下载操作。下载仍会发生,您将能够在下载选项卡中看到它,但他们不会看到实际的下载发生。

编辑(事后考虑让您的代码在内容页面上执行):

您在内容页面而不是您的扩展程序上执行操作的方式是使用 Chrome "message passing"。基本上,您将来自扩展程序(几乎就像一个单独的页面)的消息传递到扩展程序正在使用的内容页面。然后,您有一个侦听器,您的扩展已注入到内容页面中,该侦听器对消息做出反应并进行下载。像这样的:

chrome.extension.onMessage.addListener(
  function (request, sender, sendResponse)   
      if (request.greeting == "hello") 
          try
              downloadCSS();
          
          catch (err) 
              alert("Error: "+err.message);
          
      
  );

【讨论】:

delete a; 并没有做你认为它在这里做的事情,你实际上需要a.parentNode.removeChild(a);。 (不需要删除对 a 的引用,因为作为局部变量,它会在函数完成时丢失)。 如果这仍然有效,你会吗?chrome.downloads 不能按我想要的方式工作。 仍然有效,但遇到了与 chrome 下载相同的问题。 Chrome不允许允许扩展程序下载多个文件。【参考方案3】:

这是@Steve Mc 的答案的略微修改版本,它只是使其成为可以轻松复制和按原样使用的通用函数:

function exportInputs() 
    downloadFileFromText('inputs.ini','dummy content!!')


function downloadFileFromText(filename, content) 
    var a = document.createElement('a');
    var blob = new Blob([ content ], type : "text/plain;charset=UTF-8");
    a.href = window.URL.createObjectURL(blob);
    a.download = filename;
    a.style.display = 'none';
    document.body.appendChild(a);
    a.click(); //this is probably the key - simulating a click on a download link
    delete a;// we don't need this anymore

【讨论】:

对于目前的人:SteveMC 的答案不再有效,但这个有效。【参考方案4】:

快进 3 年,现在 Google Chrome 提供 chrome.downloads API(自 Chrome 31 起)。

在清单中声明"downloads" 权限后,可以通过此调用启动下载:

chrome.downloads.download(
  url: "http://your.url/to/download",
  filename: "suggested/filename/with/relative.path" // Optional
);

如果要在脚本中生成文件内容,可以使用BlobURL API,例如:

var blob = new Blob(["array of", " parts of ", "text file"], type: "text/plain");
var url = URL.createObjectURL(blob);
chrome.downloads.download(
  url: url // The object URL can be used as download URL
  //...
);

有关更多选项(即“另存为”对话框、覆盖现有文件等),请参阅documentation。

【讨论】:

谢谢!是否可以让 Chrome 将文件附加到现有文件?我想下载一个由片段组成的文件,生成一个完整的文件而不是多个片段。 @marlar 为此,最好使用filesystem API(尽管有警告,Chrome 支持)来获取块,构建完整的文件,然后download 结果进入下载文件夹。但这是一个不同的问题。如果您仍需要帮助,请提出新问题。 "filename" 在我的系统上被完全忽略了! @Xan 我收到了这个错误:Unchecked runtime.lastError while running downloads.download: Invalid filename 有什么想法吗? @anunixercoder 可能已经发现了这个问题,但是对于后来的人来说:这段代码需要在background.js 上,它不能在content.js 上运行【参考方案5】:

这是使用@Xan 和@AmanicA 的解决方案在 Chrome 清单中使用 "downloads" 权限下载文件的简洁方法

function downloadFile(options) 
    if(!options.url) 
        var blob = new Blob([ options.content ], type : "text/plain;charset=UTF-8");
        options.url = window.URL.createObjectURL(blob);
    
    chrome.downloads.download(
        url: options.url,
        filename: options.filename
    )


// Download file with custom content
downloadFile(
  filename: "foo.txt",
  content: "bar"
);

// Download file from external host
downloadFile(
  filename: "foo.txt",
  url: "http://your.url/to/download"
);

【讨论】:

非常感谢简洁,希望我能早点注意到它。无需模拟对隐藏的a 标签的点击。谢谢! 这个脚本是在内容脚本还是后台脚本还是其他地方?我在“chrome.downloads.download(

以上是关于让 Chrome 扩展程序下载文件的主要内容,如果未能解决你的问题,请参考以下文章

下载谷歌浏览器(Chrome)扩展离线安装包crx文件最简单的方法

如何在 Chrome 扩展程序中录制音频?

如何让 Chrome 扩展程序休眠一段时间并在端口上发布消息

Chrome 商店老是打不开?一招教你轻松下载安装插件

让 Chrome 57 支持迅雷精简版

如何开发Chrome扩展程序