自定义chrome扩展中的钩子窗口属性

时间:2016-03-10 11:27:16

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

我正在尝试在自定义Chrome扩展程序中挂钩一些窗口属性。我想拦截get / set调用,所以在我的内容脚本中添加了一些函数:

window.__defineGetter__('name', function() { ... })
window.__defineSetter__('name', function(v) { ... })

但似乎它不会覆盖window.name属性的默认行为。可能是什么问题?

这是注入内容脚本的清单条目:

...
"content_scripts": [
    {
      "matches": [
        "*://*/*"
      ],
      "js": [
        "src/inject/inject.js"
      ]
    }
]
...

1 个答案:

答案 0 :(得分:1)

这里有两个问题:

1)您的脚本注入太晚,无法影响页面上的脚本。

请参阅documentation regarding "run_at" property

  

可选。控制何时注入js中的文件。可以是“document_start”,“document_end”或“document_idle”。默认为“document_idle”。

     

对于“document_start”,文件是在来自css的任何文件之后注入的,但是在构造任何其他DOM或运行任何其他脚本之前。

     

在“document_end”的情况下,在DOM完成之后立即注入文件,但是在加载了图像和帧之类的子资源之前。

     

在“document_idle”的情况下,浏览器选择在“document_end”和window.onload事件触发后立即注入脚本的时间。准确的注入时刻取决于文档的复杂程度和加载时间,并针对页面加载速度进行了优化。

因此,默认情况下,您的脚本在构建整个DOM之后运行(因此,运行其中一部分的脚本)+一些非确定性延迟,直到页面处于“空闲”状态。

要修复此问题,您需要将"run_at" : "document_start"添加到内容脚本定义中。

请注意,就页面加载性能而言,这可能很昂贵。您应该将在"document_start"运行的代码限制为仅需要它的代码。

您可以创建第二个内容脚本,该脚本稍后将注入,并将使用相同的上下文。只需挂钩DOMContentLoaded即可,但脚本仍然需要在运行之前进行编译,因此仍然会对性能产生影响。

2)内容脚本具有独立的上下文

您对此做的是更改内容脚本 window.name。由于控制台是默认在页面上下文(选择器中的<top frame>)中执行,因此您看不到效果。

这是context isolation的结果。但是,可以通过在文档中注入<script>标记来绕过它。请注意,此bypasses the page's CSP,如果有的话。

代码由Rob W提供:

var s = document.createElement('script');
// TODO: add "script.js" to web_accessible_resources in manifest.json
s.src = chrome.extension.getURL('script.js');
s.onload = function() {
    this.parentNode.removeChild(this);
};
(document.head || document.documentElement).appendChild(s);

请注意,document.head处的"document_start"未定义,但回退将会成功。

要详细了解web_accessible_resources,请参阅docs 对于页面级脚本,通常为the canonical question