【问题标题】:Re-inject content scripts after update更新后重新注入内容脚本
【发布时间】:2013-08-28 18:31:47
【问题描述】:

我有一个 chrome 扩展程序,它会在每个打开的选项卡中注入一个 iframe。我的 background.js 中有一个 chrome.runtime.onInstalled 侦听器,它手动注入所需的脚本,如下所示(此处 API 的详细信息:http://developer.chrome.com/extensions/runtime.html#event-onInstalled):

background.js

  var injectIframeInAllTabs = function(){
    console.log("reinject content scripts into all tabs");
    var manifest = chrome.app.getDetails();
    chrome.windows.getAll({},function(windows){
      for( var win in windows ){
        chrome.tabs.getAllInWindow(win.id, function reloadTabs(tabs) {
          for (var i in tabs) {
            var scripts = manifest.content_scripts[0].js;
            console.log("content scripts ", scripts);
            var k = 0, s = scripts.length;
            for( ; k < s; k++ ) {
              chrome.tabs.executeScript(tabs[i].id, {
                file: scripts[k]
              });
            }

          }
        });
      }
    });
  };

当我第一次安装扩展时,这很好用。当我的扩展更新时,我想做同样的事情。如果我在更新时也运行相同的脚本,我看不到注入新的 iframe。不仅如此,如果我尝试在更新后向我的内容脚本发送消息,则不会有任何消息通过内容脚本。我看到其他人在 SO (Chrome: message content-script on runtime.onInstalled) 上也遇到了同样的问题。 chrome 扩展更新后删除旧内容脚本并注入新内容的正确方法是什么?

【问题讨论】:

    标签: google-chrome-extension


    【解决方案1】:

    更新扩展时,Chrome 会自动切断所有“旧”内容脚本与后台页面的对话,如果旧内容脚本确实尝试与运行时通信,它们也会抛出异常。这对我来说是缺失的部分。我所做的只是,在chrome.runtime.onInstalledbg.js 中,我调用了与问题中发布的相同的方法。这会注入另一个与正确运行时对话的 iframe。在某个时间点,旧的内容脚本尝试与失败的运行时对话。我抓住了那个异常,只是清除了旧的内容脚本。另请注意,每个 iframe 都被注入到自己的“孤立世界”中(此处解释了孤立世界:http://www.youtube.com/watch?v=laLudeUmXHM),因此新注入的 iframe 无法清除旧的挥之不去的 iframe。

    希望这对将来的人有所帮助!

    【讨论】:

      【解决方案2】:

      没有办法“删除”旧的内容脚本(除了使用 window.location.reload 重新加载有问题的页面,这会很糟糕)

      如果您想更灵活地选择在内容脚本中执行的代码,请使用 executeScript 函数中的“code”参数,它可以让您通过 javascript 代码传入原始字符串。如果您的内容脚本只是一个位于 background.js 中的大函数(即 content_script_function)

      background.js中:

      function content_script_function(relevant_background_script_info) {
         // this function will be serialized as a string using .toString()
         // and will be called in the context of the content script page
         // do your content script stuff here...
      }
      
      function execute_script_in_content_page(info) {
        chrome.tabs.executeScript(tabid,
          {code: "(" + content_script_function.toString() + ")(" +
           JSON.stringify(info) + ");"});
      }
      
      chrome.tabs.onUpdated.addListener(
        execute_script_in_content_page.bind( { reason: 'onUpdated',
                                               otherinfo: chrome.app.getDetails() });
      
      chrome.runtime.onInstalled.addListener(
        execute_script_in_content_page.bind( { reason: 'onInstalled',
                                               otherinfo: chrome.app.getDetails() });
      )
      

      related_background_script_info 包含有关背景页面的信息,即它是哪个版本,是否有升级事件以及调用该函数的原因。内容脚本页面仍保持其所有相关状态。这样您就可以完全控制如何处理“升级”事件。

      【讨论】:

      • 谢谢@kzahel,我可以看到这可能有效。我会试一试,但还有一个后续问题是:如果更新包中的内容脚本本身有更多变化怎么办?在这种情况下,仅在内容脚本上调用“更新”函数是不够的。真的吗?
      • 好吧。您在后台页面中定义 content_script_function 的定义,而后台页面是调用 .toString() 的页面,因此当您的扩展更新时,您将获得新的定义。这是最灵活的处理方式。您还可以在 document_start 注入并让您的脚本在任何其他脚本之前运行。使用“code”参数注入进一步保证了这一点,因为它以“同步”方式运行
      • 嗯..我还是不确定。如果我将内容脚本作为后台脚本,则扩展如何在浏览器尝试自行注入内容脚本的刷新时工作?另外,如果我可以在更新后执行脚本,那么当扩展更新时我不能调用我最初在问题中发布的方法并且可以正确处理事情吗?我一定遗漏了一些东西,你有这个例子吗?谢谢!
      猜你喜欢
      • 1970-01-01
      • 2012-06-15
      • 2022-11-16
      • 2021-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-30
      • 2021-11-13
      相关资源
      最近更新 更多