问题描述
我的chrome扩展程序具有以下两个javascript:
background.js
,作为后台脚本运行:
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
if (message.data == "takeScreenshot") {
var resp = sendResponse;
chrome.tabs.captureVisibleTab(function(screenshotUrl) {
resp({
screenshot: screenshotUrl
});
});
return true; // Return true to tell that the response is sent asynchronously
} else {
return "TestReply";
}
});
api.js
,作为可访问网络的资源运行:
window.takeScreenshot = (function() {
var isTakingScreenshot = false; // Semaphore
return function() {
if(isTakingScreenshot) return Promise.reject();
isTakingScreenshot = true;
return new Promise(function(resolve, reject) {
chrome.runtime.sendMessage("eomfljlchjpefnempfimgminjnegpjod", "takeScreenshot", function(response) {
console.log(response);
isTakingScreenshot = false;
resolve(response.screenshot);
});
});
}
})()
window.test = (function() {
return function() {
return new Promise(function(resolve, reject) {
chrome.runtime.sendMessage("eomfljlchjpefnempfimgminjnegpjod", "test", function(response) {
console.log(response);
resolve(response.length);
});
});
}
})();
当我在选项卡的控制台中执行任一功能(自动完成功能都知道它们,因此它们可用)时,我会收到错误消息:
并且返回的响应未定义.
我检查了sendMessage
中的id是否与清单和chrome://extensions页面中的ID相同,并且我已经打开了扩展程序的后台页面DevTools并在其中手动添加了相同的侦听器,以使确保侦听器确实已注册.
我的搜索发现此错误表示未正确注册侦听器,但我没有找到根本原因.您是否知道导致此错误的原因?
确定.我发现了问题所在.我猜这是自72以来镀铬行为的变化.问题是,如果您在后台或弹出页面的另一端打开通道之前尝试调用chrome.runtime.connect(),则会收到该错误.
Chrome文档说的是您可以立即发送消息.在过去,这只是行之有效的,消息将被传递或丢弃.但是现在它失败了.
因此,我们的解决方法是通过仅延迟connect()调用来确保在调用connect()之前先建立连接侦听器:
chrome.runtime.onConnect.addListener(port => {
console.log('connected ', port);
if (port.name === 'hi') {
port.onMessage.addListener(this.processMessage);
}
});
如果您在内容脚本方面设置了用于断开连接事件的侦听器,则在尝试chrome.runtime.connect时实际上会被调用,并且另一端没有侦听任何内容.根据端口寿命
,这是正确的行为 port = chrome.runtime.connect(null, {name: 'hi'});
port.onDisconnect.addListener(obj => {
console.log('disconnected port');
})
我不知道有什么方法可以避免这种情况,而不是使用setTimeout并尝试在调用chrome.runtime.onConnect.addListener之后使chrome.runtime.connect出现.这不是一个好的解决方案,因为它会导致计时错误.也许另一个解决方法是反转通道的方向.然后从弹出窗口而不是contentscript启动连接.
更新:针对此问题,我做了最小复制扩展. /p>
My chrome extension has the following two javascripts:
background.js
, running as background script:
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
if (message.data == "takeScreenshot") {
var resp = sendResponse;
chrome.tabs.captureVisibleTab(function(screenshotUrl) {
resp({
screenshot: screenshotUrl
});
});
return true; // Return true to tell that the response is sent asynchronously
} else {
return "TestReply";
}
});
api.js
, running as web accessible resource:
window.takeScreenshot = (function() {
var isTakingScreenshot = false; // Semaphore
return function() {
if(isTakingScreenshot) return Promise.reject();
isTakingScreenshot = true;
return new Promise(function(resolve, reject) {
chrome.runtime.sendMessage("eomfljlchjpefnempfimgminjnegpjod", "takeScreenshot", function(response) {
console.log(response);
isTakingScreenshot = false;
resolve(response.screenshot);
});
});
}
})()
window.test = (function() {
return function() {
return new Promise(function(resolve, reject) {
chrome.runtime.sendMessage("eomfljlchjpefnempfimgminjnegpjod", "test", function(response) {
console.log(response);
resolve(response.length);
});
});
}
})();
When I execute in a tab's console either function (auto-complete knows them, so they are available), I get the error:
and the respone returned is undefined.
I have checked that the id in sendMessage
is the same as in the manifest and in the chrome://extensions page, and I have opened the background page DevTools of the extension and manually added the same listener there to make sure the listener is indeed registered.
My searches found that this error means the listener has not been correctly registered, but I don't find the underlying reason. Do you have an idea what causes this error?
OK. I found out what the problem is. This is a change in chromes behavior since 72 I guess. The problem is if you try to call chrome.runtime.connect() before you have opened a channel on the other end in Background or popup page then you will get that error.
What Chrome docs say is that you can send a message immediately. In the past this would just work and the messages would get either delivered or dropped. But now it is failing.
So our workaround is to make sure the connection listener is setup fist before calling connect() by just delaying the connect() call:
chrome.runtime.onConnect.addListener(port => {
console.log('connected ', port);
if (port.name === 'hi') {
port.onMessage.addListener(this.processMessage);
}
});
If you setup a listener for disconnect event on the content script side it actually gets gets called when you try to chrome.runtime.connect and you don't have anything listening on the other end. Which is correct behavior according the Port LifeTime
port = chrome.runtime.connect(null, {name: 'hi'});
port.onDisconnect.addListener(obj => {
console.log('disconnected port');
})
I don't know if there is way to avoid this than with setTimeout and trying to get the chrome.runtime.connect to come after there is chrome.runtime.onConnect.addListener is called. This is not a good solution because it leads to timing errors. Maybe another workaround is to reverse the direction of the channel. And initiate the connect from popup instead of contentscript.
Update: I made a minimum repro extension for this issue.
这篇关于Chrome扩展程序消息传递:未经检查的runtime.lastError:无法建立连接.接收端不存在的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!