我正在尝试在自定义Chrome扩展程序中挂钩一些窗口属性。我想拦截get / set调用,所以在我的内容脚本中添加了一些函数:
window.__defineGetter__('name', function() { ... })
window.__defineSetter__('name', function(v) { ... })
但似乎它不会覆盖window.name属性的默认行为。可能是什么问题?
这是注入内容脚本的清单条目:
...
"content_scripts": [
{
"matches": [
"*://*/*"
],
"js": [
"src/inject/inject.js"
]
}
]
...
答案 0 :(得分: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
即可,但脚本仍然需要在运行之前进行编译,因此仍然会对性能产生影响。
您对此做的是更改内容脚本 的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。