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

Zac*_*ner 26 javascript google-chrome-extension

我想制作一个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);
Run Code Online (Sandbox Code Playgroud)

mything.js看起来像这样:

window.mything = {thing: true};
console.log(window);
Run Code Online (Sandbox Code Playgroud)

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

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

nyn*_*464 40

你不能,不能直接.从内容脚本文档:

但是,内容脚本有一些限制.他们不能:

  • 使用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);
Run Code Online (Sandbox Code Playgroud)

  • 如果它是内联脚本,即`<script>//do something</script>` 那么是的,它会立即(同步)执行。如果它是一个远程脚本`<script src="foo.js"></script>` 那么它将在脚本下载后执行。在添加 `async` 标签之前,这将是防止脚本下载阻止页面呈现的常用方法。 (2认同)

Bru*_*mos 17

经过数小时尝试不同的尝试并面临 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)
})()
Run Code Online (Sandbox Code Playgroud)

火狐

在 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)
})()
Run Code Online (Sandbox Code Playgroud)
  1. script.js将包含您的主要代码:
;(function() {
  // your main code here
  window.foo = 'bar'
})()
Run Code Online (Sandbox Code Playgroud)

苹果浏览器

它与 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)
})()
Run Code Online (Sandbox Code Playgroud)
  1. script.js将包含您的主要代码:
;(function() {
  // your main code here
  window.foo = 'bar'
})()
Run Code Online (Sandbox Code Playgroud)

源代码

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

  • 这是失败的,并显示“拒绝执行内联脚本,因为它违反了以下内容安全策略指令:“script-src 'self'”。启用内联执行需要“unsafe-inline”关键字、哈希值(“sha256-2hqy/01Xj3kkdA60wVjY8N6m2WXv5URv1rhk3jCDyHY=”)或随机数(“nonce-...”)。` (12认同)

Luc*_*iva 9

正如其他人指出的那样,上下文脚本不会在与页面相同的上下文中运行,因此,要访问正确的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);
Run Code Online (Sandbox Code Playgroud)

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

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


ztr*_*yle 7

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();
};
Run Code Online (Sandbox Code Playgroud)

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

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

并在 content_script 中调度该事件:

var foo = 'bar'
document.dispatchEvent(new CustomEvent('_save_OG_Editor', {
  'detail': {
    'my_event_data': foo
  }
}))
Run Code Online (Sandbox Code Playgroud)

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

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

希望对某人有所帮助\(•?•)/


小智 6

我一直在玩这个.我发现通过将javascript包装到window.location = call中,我可以与浏览器的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;
Run Code Online (Sandbox Code Playgroud)

它可以工作,但仅适用于设置的window.location的最后一个实例.如果您访问文档的窗口对象,它将具有变量"bar"但不是"foo"