重新加载Chrome扩展程序后,chrome.runtime.sendMessage会从内容脚本中抛出异常

时间:2014-09-15 04:05:44

标签: javascript google-chrome google-chrome-extension content-script

我将注入的内容脚本中的消息发送回Chrome扩展程序中的后台脚本

chrome.runtime.sendMessage({action: "myResult"});

这很好用,直到我重新加载我的扩展程序(转到设置 - >扩展程序 - >"重新载入(Ctrl + R)"作为我的扩展程序。)

当我的后台脚本启动时,它会反复调用所有打开的标签chrome.tabs.executeScript,以编程方式重新注入我的内容脚本({{3} }。)

但是在我这样做之后,如果我从内容脚本中调出第一个sendMessage行,则会抛出此异常:

  

错误:连接到扩展名my_extension_id

时出错

知道为什么会这样吗?

1 个答案:

答案 0 :(得分:6)

重新加载扩展运行时,在以下任何情况下都会发生

  • 您致电chrome.runtime.reload()
  • 您已在chrome://extensions/点击了重新加载扩展程序。
  • 扩展程序已更新。

然后内容脚本中的大多数扩展API方法都停止工作(包括导致问题中的错误的chrome.runtime.sendMessage)。有两种方法可以解决这个问题。

选项1:回退到仅内容脚本功能

如果您的扩展程序在没有后台页面的情况下可以正常运行,那么这可能是一个可接受的解决方例如。如果你的内容脚本除了修改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
}

选项2:在内容脚本插入

上卸载以前的内容脚本

当与后台页面的连接对您的内容脚本很重要时,您必须实现正确的卸载例程,并设置一些事件以在内容脚本为时卸载以前的内容脚本通过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();

请注意,任何知道事件名称的页面都可能触发内容脚本的破坏。这是不可避免的,因为在销毁扩展运行时之后,没有适当的方法可以安全地与扩展进行通信。