可以从 Chrome 扩展程序修改窗口对象吗?

IT技术 javascript google-chrome-extension
2021-03-01 04:55:13

我想制作一个 Chrome 扩展程序,在window. 当在加载了扩展程序的浏览器中查看网页时,我希望window.mything通过 Javascript 可用。window.mything对象将具有一些我将在扩展中定义的函数,并且console.log当在启用了扩展的浏览器中查看页面时,这些函数应该可以从或任何 Javascript 文件中调用

我能够使用内容脚本成功地将 Javascript 文件注入页面

var s = document.createElement("script"); 
s.src = chrome.extension.getURL("mything.js");
document.getElementsByTagName("head")[0].appendChild(s);

mything.js 看起来像这样:

window.mything = {thing: true};
console.log(window);

每当页面加载时,我window都会在控制台中看到我期望的整个对象。但是,我无法window.mything从控制台对象交互似乎注入的脚本并没有真正修改全局window对象。

如何window从 Chrome 扩展程序修改全局对象?

6个回答

你不能,不能直接。内容脚本文档

但是,内容脚本有一些限制。他们不可以:

  • 使用 chrome.* API(除了 chrome.extension 的部分)
  • 使用由其扩展页面定义的变量或函数
  • 使用由网页或其他内容脚本定义的变量或函数

(强调)

window内容脚本看到的对象是不一样的window对象,它的页面看到。

但是,您可以使用window.postMessage方法通过 DOM 传递消息您的页面和内容脚本都会监听消息事件,无论何时您window.postMessage从其中一个地方调用,另一个都会收到它。“内容脚本”文档页面上有一个示例

编辑:您可以通过从内容脚本中注入脚本来向页面添加一些方法。它仍然无法与扩展的其余部分进行通信,而不使用类似的东西postMessage,但您至少可以向页面的window

var elt = document.createElement("script");
elt.innerHTML = "window.foo = {bar:function(){/*whatever*/}};"
document.head.appendChild(elt);
谢谢,我没有逐字使用你的建议,但这个概念帮助我在真正的问题上归零。
2021-04-17 04:55:13
<script>元素黑客完美。我很好奇,<head>即使页面已经加载,这些 Javascript 标记是否会在添加到 后立即执行
2021-05-06 04:55:13
您可以window使用对象自己的修改器(如addEventListener. 不需要文档元素注入。
2021-05-09 04:55:13
你也可以使用 eval("window.foo = {bar:function(){/*whatever*/}};");
2021-05-12 04:55:13
如果它是内联脚本,即<script>//do something</script>是的,它会立即(同步)执行。如果它是一个远程脚本,<script src="foo.js"></script>那么它将在脚本下载后执行。在添加async标记之前,这将是防止脚本下载阻止页面呈现的常用方法。
2021-05-13 04:55:13

经过数小时尝试不同的尝试并面临 CORS 等安全问题后,我找到了windowChromeFirefox编辑对象的方法Safari您需要对每个策略使用不同的策略:

铬合金

  1. 将您的脚本添加到content_scripts.
  2. 在您的脚本文件中,将 a 附加script到页面并使其内联运行您的自定义代码。像这样:
;(function() {
  function script() {
    // your main code here
    window.foo = 'bar'
  }

  function inject(fn) {
    const script = document.createElement('script')
    script.text = `(${fn.toString()})();`
    document.documentElement.appendChild(script)
  }

  inject(script)
})()

火狐

在 Firefox 上,由于Content-Security-Policy错误,上述解决方案不起作用但以下解决方法目前正在发挥作用,至少目前是这样:

  1. 将 2 个脚本添加到content_scripts,例如inject.jsscript.js
  2. inject脚本将获得完整的绝对URL中的script.js文件并加载它:
;(function() {
  const b = typeof browser !== 'undefined' ? browser : chrome

  const script = document.createElement('script')
  script.src = b.runtime.getURL('script.js')
  document.documentElement.appendChild(script)
})()
  1. script.js将包含您的主要代码:
;(function() {
  // your main code here
  window.foo = 'bar'
})()

苹果浏览器

它与 Firefox 非常相似。

  1. 创建 2 个 javascript 文件,例如inject.jsscript.js
  2. inject脚本将获得完整的绝对URL中的script.js文件并加载它:
;(function() {
  const script = document.createElement('script')
  script.src = safari.extension.baseURI + 'script.js'
  document.documentElement.appendChild(script)
})()
  1. script.js将包含您的主要代码:
;(function() {
  // your main code here
  window.foo = 'bar'
})()

源代码

在此处查看完整代码:https : //github.com/brunolemos/simplified-twitter

我使用 cloneInto 命令在 firefox 中进行了管理:developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/...遗憾的是这在 Chrome 中不起作用......
2021-04-26 04:55:13
这是失败的 Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self'". Either the 'unsafe-inline' keyword, a hash ('sha256-2hqy/01Xj3kkdA60wVjY8N6m2WXv5URv1rhk3jCDyHY='), or a nonce ('nonce-...') is required to enable inline execution.
2021-04-27 04:55:13
感谢解决方案,这安全吗?或者有没有其他安全的方式?
2021-05-14 04:55:13

正如其他人指出的那样,上下文脚本不会在与页面相同的上下文中运行,因此,要访问正确的window,您需要将代码注入页面。

这是我的看法:

function codeToInject() {
    // Do here whatever your script requires. For example:
    window.foo = "bar";
}

function embed(fn) {
    const script = document.createElement("script");
    script.text = `(${fn.toString()})();`;
    document.documentElement.appendChild(script);
}

embed(codeToInject);

清洁且易于使用。无论您需要在页面上下文中运行什么,都将其放入codeToInject()(您可以随意称呼它)。embed()函数负责打包您的函数并将其发送到页面中运行。

embed()函数的作用是script在页面中创建一个标记并将该函数codeToInject()作为IIFE嵌入其中浏览器将在新script标签附加到文档后立即执行,并且您注入的代码将按预期在页面上下文中运行。

chrome 扩展程序content_script在其自己的上下文中运行,该上下文与窗口分开。您可以将脚本注入页面,以便它在与页面窗口相同的上下文中运行,如下所示:Chrome 扩展程序 - 从网页中检索全局变量

我能够调用 window 对象上的方法并通过将 a 添加script.js到页面的 DOM 来修改窗口属性

var s = document.createElement('script');
s.src = chrome.extension.getURL('script.js');
(document.head||document.documentElement).appendChild(s);
s.onload = function() {
    s.remove();
};

并在该注入的脚本文件中创建自定义事件侦听器:

document.addEventListener('_my_custom_event', function(e) {
  // do whatever you'd like! Like access the window obj
  window.myData = e.detail.my_event_data;
})

并在 content_script 中调度该事件:

var foo = 'bar'
document.dispatchEvent(new CustomEvent('_save_OG_Editor', {
  'detail': {
    'my_event_data': foo
  }
}))

或相反亦然; script.js在您的扩展的 content_script 中分派事件并监听它们(就像上面的链接很好地说明了一样)。

只需确保将注入的脚本添加到扩展文件中,并将脚本文件的路径添加到其中的清单中,"web_accessible_resources"否则会出现错误。

希望对大家有所帮助\(•◡•)/

我一直在玩这个。我发现我可以通过将我的 javascript 包装到 window.location= 调用中来与浏览器的 window 对象进行交互。

var myInjectedJs = "window.foo='This exists in the \'real\' window object';"
window.location = "javascript:" + myInjectedJs;

var myInjectedJs2 = "window.bar='So does this.';"
window.location = "javascript:" + myInjectedJs2;

它有效,但仅适用于设置的 window.location 的最后一个实例。如果您访问文档的 window 对象,它将有一个变量“bar”而不是“foo”