我将注入的内容脚本中的消息发送回Chrome扩展程序中的后台脚本:
chrome.runtime.sendMessage({action: "myResult"});
这很好用,直到我重新加载我的扩展程序(转到设置 - >扩展程序 - >"重新载入(Ctrl + R)"作为我的扩展程序。)
当我的后台脚本启动时,它会反复调用所有打开的标签chrome.tabs.executeScript
,以编程方式重新注入我的内容脚本({{3} }。)
但是在我这样做之后,如果我从内容脚本中调出第一个sendMessage
行,则会抛出此异常:
错误:连接到扩展名my_extension_id
时出错
知道为什么会这样吗?
答案 0 :(得分:6)
重新加载扩展运行时,在以下任何情况下都会发生
chrome.runtime.reload()
。chrome://extensions/
点击了重新加载扩展程序。然后内容脚本中的大多数扩展API方法都停止工作(包括导致问题中的错误的chrome.runtime.sendMessage
)。有两种方法可以解决这个问题。
如果您的扩展程序在没有后台页面的情况下可以正常运行,那么这可能是一个可接受的解决方例如。如果你的内容脚本除了修改DOM和/或执行跨源请求之外什么都不做。
我在我的某个扩展程序中使用以下代码段,以便在从我的内容脚本调用任何Chrome扩展程序API之前检测运行时是否仍然有效。
// It turns out that getManifest() returns undefined when the runtime has been
// reload through chrome.runtime.reload() or after an update.
function isValidChromeRuntime() {
// It turns out that chrome.runtime.getManifest() returns undefined when the
// runtime has been reloaded.
// Note: If this detection method ever fails, try to send a message using
// chrome.runtime.sendMessage. It will throw an error upon failure.
return chrome.runtime && !!chrome.runtime.getManifest();
}
// E.g.
if (isValidChromeRuntime()) {
chrome.runtime.sendMessage( ... );
} else {
// Fall back to contentscript-only behavior
}
当与后台页面的连接对您的内容脚本很重要时,您必须实现正确的卸载例程,并设置一些事件以在内容脚本为时卸载以前的内容脚本通过chrome.tabs.executeScript
插回。
// Content script
function main() {
// Set up content script
}
function destructor() {
// Destruction is needed only once
document.removeEventListener(destructionEvent, destructor);
// Tear down content script: Unbind events, clear timers, restore DOM, etc.
}
var destructionEvent = 'destructmyextension_' + chrome.runtime.id;
// Unload previous content script if needed
document.dispatchEvent(new CustomEvent(destructionEvent));
document.addEventListener(destructionEvent, destructor);
main();
请注意,任何知道事件名称的页面都可能触发内容脚本的破坏。这是不可避免的,因为在销毁扩展运行时之后,没有适当的方法可以安全地与扩展进行通信。