简体   繁体   English

Chrome扩展程序-从网页检索全局变量

[英]Chrome extension - retrieving global variable from webpage

I am working on an extension for Chrome. 我正在为Chrome扩展程序。 I wish parse the content of the "original" Gmail message (the currently viewed message). 我希望解析“原始” Gmail邮件(当前查看的邮件)的内容。

I tried to utilize the jQuery.load() as follows 我试图利用jQuery.load()如下

$(windows).load(function() { alert(GLOBALS); });

and place it at the content script, but it does not work either. 并将其放置在内容脚本中,但是它也不起作用。 I am using Chrome's developer tools, which returns the following error on the invocation of the alert(GLOBALS); 我正在使用Chrome的开发人员工具,该工具在调用alert(GLOBALS);返回以下错误alert(GLOBALS);

Uncaught ReferenceError: GLOBALS is not defined 未捕获的ReferenceError:未定义GLOBALS

Although, when using the developers tools' console, typing into the console GLOBALS it returns an array. 尽管在使用开发人员工具的控制台时,在控制台GLOBALS键入它会返回一个数组。

Any clue how to access the GLOBALS from the content script? 有什么线索如何从内容脚本访问GLOBALS吗?

Content scripts run in an isolated environment. 内容脚本在隔离的环境中运行。 To get access to the any global properties (of the page's window ), you have to either inject a new <script> element, or use event listeners for passing data. 要访问(页面window )任何全局属性,您必须注入新的<script>元素,或使用事件侦听器传递数据。

See this answer for example on injecting a <script> element in the context of the page. 有关在页面上下文中注入<script>元素的示例,请参见此答案

Example

contentscript.js ( "run_at": "document_end" in manifest): contentscript.js (清单中的"run_at": "document_end" ):

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

// Event listener
document.addEventListener('RW759_connectExtension', function(e) {
    // e.detail contains the transferred data (can be anything, ranging
    // from JavaScript objects to strings).
    // Do something, for example:
    alert(e.detail);
});

script.js - Located in the extension directory, this will be injected into the page itself: script.js位于扩展目录中,这将被注入页面本身:

setTimeout(function() {
    /* Example: Send data from the page to your Chrome extension */
    document.dispatchEvent(new CustomEvent('RW759_connectExtension', {
        detail: GLOBALS // Some variable from Gmail.
    }));
}, 0);

Since this file is being loaded via a chrome-extension: URL from within the DOM, "script.js" must be added to the web_accessible_resources section of the manifest file. 由于此文件是通过DOM中的chrome-extension:URL加载的,因此“ script.js”必须添加到清单文件的web_accessible_resources部分。 Otherwise Chrome will refuse to load the script file. 否则,Chrome将拒绝加载脚本文件。

You should run as little logic as possible in the web page, and handle most of your logic in the content script. 您应该在网页中运行尽可能少的逻辑,并在内容脚本中处理大部分逻辑。 This has multiple reasons. 这有多个原因。 First and foremost, any script injected in the page runs in the same context as the web page, so the web page can (deliberately or inadvertently) modify JavaScript/DOM methods in such a way that your extension stops working. 首先,插入到页面中的任何脚本都在与网页相同的上下文中运行,因此,网页可以(有意或无意)修改JavaScript / DOM方法,以使扩展程序停止工作。 Secondly, content script have access to extra features, such a limited subset of the chrome.* APIs and cross-origin network requests (provided that the extension has declared permissions for those). 其次,内容脚本可以访问其他功能,例如chrome。* API的有限子集和跨域网络请求(前提是扩展程序已声明了这些功能的许可)。

A more modern solution for communicating between a chrome extension content_script and the javascript on the page would be to use the html5 postMessage API. 在chrome扩展content_script和页面上的javascript之间进行通信的更现代的解决方案是使用html5 postMessage API。 Any messages sent to "window" are visible from both the javascript on the webpage and the extension's content_script. 从网页上的javascript和扩展名的content_script都可以看到发送到“窗口”的所有消息。

The extension's content_script.js: 扩展程序的content_script.js:

window.addEventListener('message', function(event) {
    console.log('content_script.js got message:', event);
    // check event.type and event.data
});

setTimeout(function () {
    console.log('cs sending message');
    window.postMessage({ type: 'content_script_type',
                         text: 'Hello from content_script.js!'},
                       '*' /* targetOrigin: any */ );
}, 1000);

The javascript running on the webpage: 在网页上运行的javascript:

window.addEventListener('message', function(event) {
    console.log('page javascript got message:', event);
});

setTimeout(function() {
    console.log('page javascript sending message');
    window.postMessage({ type: 'page_js_type',
                         text: "Hello from the page's javascript!"},
                       '*' /* targetOrigin: any */);
}, 2000);

Also see http://developer.chrome.com/extensions/content_scripts.html#host-page-communication 另请参见http://developer.chrome.com/extensions/content_scripts.html#host-page-communication

There is a new API for web pages to communicate securely and without any side effects (window.postMessage can have other listeners!) to the content script. 网页有一个新的API,可以安全地进行通讯,而不会对内容脚本产生任何副作用(window.postMessage可以有其他侦听器!)。

"From the web page, use the runtime.sendMessage or runtime.connect APIs to send a message to a specific app or extension" “从网页上,使用runtime.sendMessage或runtime.connect API将消息发送到特定的应用程序或扩展”

// The ID of the extension we want to talk to.
var editorExtensionId = "abcdefghijklmnoabcdefhijklmnoabc";

// Make a simple request:
chrome.runtime.sendMessage(editorExtensionId, {openUrlInEditor: url},
  function(response) {
    if (!response.success)
    handleError(url);
});

"From your app or extension, you may listen to messages from web pages via the runtime.onMessageExternal or runtime.onConnectExternal APIs, similar to cross-extension messaging. Only the web page can initiate a connection. [...]" “从应用程序或扩展中,您可以通过runtime.onMessageExternal或runtime.onConnectExternal API来监听来自网页的消息,类似于交叉扩展消息传递。只有网页才能启动连接。[...]

(from http://developer.chrome.com/extensions/messaging.html ) This is still only available in chrome's dev channel, but seems like it'll be in the next version or so. (来自http://developer.chrome.com/extensions/messaging.html )该功能仍然仅在chrome的dev通道中可用,但似乎将在下一版本中使用。

Don't ask me how this works, it seems highly confusing. 不要问我这是如何工作的,这似乎很令人困惑。 How on earth does chrome.runtime get defined on the web page? chrome.runtime如何在网页上定义? What if the script already defined that variable for some reason? 如果脚本由于某种原因已经定义了该变量怎么办? I also couldn't find the chromium bug report to see the history of the development of this feature. 我也找不到Chrome错误报告来查看此功能的开发历史。

I had a slightly different approach based on your extension's accessible html pages. 根据您扩展程序的可访问html页面,我使用的方法略有不同。

Add your page to the manifest: 将页面添加到清单中:

 "web_accessible_resources": ["variables.html"] 

Create your page (here, variables.html) and extract the content's data (ie window.contentVar): 创建您的页面(此处为variables.html)并提取内容的数据(即window.contentVar):

 <script type="text/javascript"> $("#my-var-name").text(window["contentVar"]); </script> <div id="my-var-name" style="display: none;"></div> 

Access from your extension's JavaScript: 从扩展程序的JavaScript访问:

 var myVarName = $("#my-var-name").text(); 

Add to your content script: 添加到您的内容脚本:

function executeOnPageSpace(code){

  // create a script tag
  var script = document.createElement('script')
  script.id = 'tmpScript'
  // place the code inside the script. later replace it with execution result.
  script.textContent = 
  'document.getElementById("tmpScript").textContent = JSON.stringify(' + code + ')'
  // attach the script to page
  document.documentElement.appendChild(script)
  // collect execution results
  let result = document.getElementById("tmpScript").textContent
  // remove script from page
  script.remove()
  return JSON.parse(result)

}

Now you can do: 现在您可以执行以下操作:

let window = executeOnPageSpace('window')

or even like this: 甚至像这样:

executeOnPageSpace('window.location.href = "http://stackoverflow.com"')

NOTE: I have not tested this for long-running code. 注意:我没有针对长时间运行的代码进行过测试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM