【发布时间】:2014-10-29 09:51:38
【问题描述】:
一点背景
我已经在 Chrome 扩展程序上工作了几天,该扩展程序每天多次截取给定网页的屏幕截图。我以this 为指导,一切正常。
不过,有一个小要求扩展无法满足。用户必须有权访问保存图像(屏幕截图)的文件夹,但 Chrome Extensions don't have access to the file system。另一方面,Chrome 应用程序可以。因此,环顾四周后,我得出结论,我必须同时创建一个 Chrome 扩展程序和一个 Chrome 应用程序。这个想法是扩展程序将创建一个截图的 blob,然后将该 blob 发送到应用程序,然后将其作为图像保存到用户指定的位置。这正是我正在做的——我在扩展端创建一个截图的 blob,然后将其发送到应用程序,要求用户选择保存图像的位置。
问题
直到节省部分,一切都按预期工作。 Blob 在扩展程序上创建,发送到应用程序,由应用程序接收,用户被询问在哪里保存,图像被保存......这就是事情崩溃的地方。 生成的图像无法使用。当我尝试打开它时,我收到一条消息,提示 “无法确定类型”。以下是我正在使用的代码:
-
首先在扩展方面,我创建一个 blob 并将其发送过来,如下所示:
chrome.runtime.sendMessage( APP_ID, /* I got this from the app */ {myMessage: blob}, /* Blob created previously; it's correct */ function(response) { appendLog("response: "+JSON.stringify(response)); } ); -
然后,在 APP 端,我收到 blob 并尝试像这样保存它:
// listen for external messages chrome.runtime.onMessageExternal.addListener( function(request, sender, sendResponse) { if (sender.id in blacklistedIds) { sendResponse({"result":"sorry, could not process your message"}); return; // don't allow this extension access } else if (request.incomingBlob) { appendLog("from "+sender.id+": " + request.incomingBlob); // attempt to save blob to choosen location if (_folderEntry == null) { // get a directory to save in if not yet chosen openDirectory(); } saveBlobToFile(request.incomingBlob, "screenshot.png"); /* // inspect object to try to see what's wrong var keys = Object.keys(request.incomingBlob); var keyString = ""; for (var key in keys) { keyString += " " + key; } appendLog("Blob object keys:" + keyString); */ sendResponse({"result":"Ok, got your message"}); } else { sendResponse({"result":"Ops, I don't understand this message"}); } } );这是执行实际保存的应用程序上的功能:
function saveBlobToFile(blob, fileName) { appendLog('entering saveBlobToFile function...'); chrome.fileSystem.getWritableEntry(_folderEntry, function(entry) { entry.getFile(fileName, {create: true}, function(entry) { entry.createWriter(function(writer) { //writer.onwrite = function() { // writer.onwrite = null; // writer.truncate(writer.position); //}; appendLog('calling writer.write...'); writer.write(blob); // Also tried writer.write(new Blob([blob], {type: 'image/png'})); }); }); }); }
没有错误。没有打嗝。代码有效,但图像无用。我到底错过了什么?我哪里错了?是不是我们只能在扩展/应用程序之间传递字符串? blob 是否在途中损坏?我的应用程序是否因为 blob 是在扩展程序上创建的而无法访问它?任何人都可以解释一下吗?
更新(2014 年 9 月 23 日) 抱歉更新晚了,但我被分配到另一个项目,直到 2 天前才能回复。
所以在环顾四周后,我决定采用@Danniel Herr 的建议,该建议建议使用 SharedWorker 和嵌入在应用程序框架中的页面。这个想法是扩展将 blob 提供给 SharedWorker,SharedWorker 将 blob 转发到扩展中的页面,该页面嵌入在应用程序的框架中。该页面,然后使用 parent.postMessage(...) 将 blob 转发到应用程序。这有点麻烦,但似乎这是我唯一的选择。
让我发布一些代码,以便更有意义:
扩展:
var worker = new SharedWorker(chrome.runtime.getURL('shared-worker.js'));
worker.port.start();
worker.postMessage('hello from extension'); // Can send blob here too
worker.port.addEventListener("message", function(event) {
$('h1Title').innerHTML = event.data;
});
proxy.js
var worker = new SharedWorker(chrome.runtime.getURL('shared-worker.js'));
worker.port.start();
worker.port.addEventListener("message",
function(event) {
parent.postMessage(event.data, 'chrome-extension://[extension id]');
}
);
proxy.html
<script src='proxy.js'></script>
shared-worker.js
var ports = [];
var count = 0;
onconnect = function(event) {
count++;
var port = event.ports[0];
ports.push(port);
port.start();
/*
On both the extension and the app, I get count = 1 and ports.length = 1
I'm running them side by side. This is so maddening!!!
What am I missing?
*/
var msg = 'Hi, you are connection #' + count + ". ";
msg += " There are " + ports.length + " ports open so far."
port.postMessage(msg);
port.addEventListener("message",
function(event) {
for (var i = 0; i < ports.length; ++i) {
//if (ports[i] != port) {
ports[i].postMessage(event.data);
//}
}
});
};
在应用上
context.addEventListener("message",
function(event) {
appendLog("message from proxy: " + event.data);
}
);
这就是执行流程...在扩展上,我创建了一个共享工作者并向其发送消息。共享工作者应该能够接收 blob,但出于测试目的,我只发送一个简单的字符串。
接下来,共享工作者接收消息并将其转发给所有已连接的人。此时应用程序框架内的 proxy.html/js 确实已连接,并且应该接收共享工作者转发的任何内容。
接下来,proxy.js [应该] 接收来自共享工作者的消息并使用 parent.postMessage(...) 将其发送到应用程序。该应用程序正在通过 window.addEventListener("message",...) 进行侦听。
为了测试这个流程,我首先打开应用程序,然后单击扩展按钮。我在应用程序上没有收到任何消息。我也没有错误。
扩展程序可以与共享工作者进行来回通信。该应用程序可以很好地与共享工作者通信。但是,我从 extension->proxy->app 发送的消息没有到达应用程序。我错过了什么?
对不起,长帖子的家伙,但我希望有人能解释一下,因为这让我发疯了。
谢谢
【问题讨论】:
标签: javascript google-chrome google-chrome-extension google-chrome-app