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

时间:2012-09-12 20:26:04

标签: javascript google-chrome-extension

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

我能够使用Content Script成功将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对象。

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

7 个答案:

答案 0 :(得分:37)

你不能,不能直接。来自content scripts documentation

  

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

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

(强调补充)

内容脚本看到的window对象与页面看到的window对象不同。

但是,您可以使用window.postMessage方法通过DOM传递消息。您的网页和内容脚本都会收听消息事件,当您从其中一个地方拨打window.postMessage时,另一个会收到该信息。 “内容脚本”文档页面上有一个example of this

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

var elt = document.createElement("script");
elt.innerHTML = "window.foo = {bar:function(){/*whatever*/}};"
document.head.appendChild(elt);

答案 1 :(得分:7)

我一直在玩这个。我发现通过将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;

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

答案 2 :(得分:2)

经过数小时的尝试,并遇到了诸如CORS之类的安全问题,我找到了在Chrome和Firefox上编辑window对象的方法。您需要为每种策略使用不同的策略:

Chrome

  1. 将脚本添加到content_scripts
  2. 在脚本文件中,将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

在Firefox上,由于出现Content-Security-Policy错误,上述解决方案无法正常工作。但是,至少在目前,以下变通办法目前正在起作用:

  1. 将2个脚本添加到content_scripts,例如inject.jsscript.js
  2. inject脚本将获取script.js文件的完整绝对URL 并加载它:
;(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'
})()

源代码

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

答案 3 :(得分:1)

内容脚本可以调用window方法,然后可以使用这些方法来改变window对象。这比<script>代码注入更容易,即使尚未解析<head><body>(例如使用run_at: document_start时),也会有效。

// In Content Script
window.addEventListener('load', loadEvent => {
    let window = loadEvent.currentTarget;
    window.document.title='You changed me!';
});

答案 4 :(得分:1)

Chrome扩展程序content_script在其自己的上下文中运行,该窗口与窗口分开。您可以将脚本注入页面,因此它在与页面窗口相同的上下文中运行,如下所示:Chrome extension - retrieving global variable from webpage

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

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中监听它们(如上面的链接所示)。

请务必在扩展程序的文件中添加注入的脚本,并将脚本文件的路径添加到manifest within "web_accessible_resources",否则您将收到错误。

希望能帮助某人\(•◡•)/

答案 5 :(得分:1)

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

这是我的看法:

function runEmbedded() {
    // Put here whatever your script needs to do. For example:
    window.foo = "bar";
}

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

embed(runEmbedded);

清洁且易于使用。无论您需要在页面上下文中运行什么内容,都可以将其放在runEmbedded()中(您可以根据自己的喜好将其命名)。 embed()函数负责打包函数并将其发送到页面中运行。

答案 6 :(得分:0)

感谢这里的其他答案,这是我正在使用的:

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

  // Your code here
  // ...

})

效果很好,没问题。