javascript 从站点调用 Chrome 扩展的后台功能

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13777887/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 19:44:55  来源:igfitidea点击:

Call background function of Chrome extension from a site

javascriptgoogle-chromegoogle-chrome-extensioncontent-script

提问by Wouter van Reeven

I am looking for a function inside a webpage te activate a chrome extension.

我正在寻找一个网页内的功能 te 激活 chrome 扩展。

Imagine that http://www.example.com/test.htmlcontains:

想象一下http://www.example.com/test.html包含:

<script>
hello();
</script>

And my background page contains the definition of the hellofunction:

我的后台页面包含hello函数的定义:

function hello() {
    alert("test");
}

How can I make sure that the Chrome extension's background page's hellois called when test.htmlcalls hello();?

如何确保在hello调用时test.html调用Chrome 扩展程序的后台页面hello();

回答by Rob W

Before a web page is able to call a background page's function, the following problems need to be solved:

在网页能够调用后台页面的功能之前,需要解决以下问题:

  1. Be able to use hello();from a web page. This is done by injectinga script defining hellousing Content scripts. The injected function communicates with the content script using a custom event or postMessage.
  2. The content script needs to communicate with the background. This is implemented through chrome.runtime.sendMessage.
    If the web page needs to receive a reply as well:
  3. Send a reply from the background page (sendMessage/ onMessage, see below).
  4. In the content script, create a custom event or use postMessageto send a message to the web page.
  5. In the web page, handle this message.
  1. 能够hello();从网页使用。这是通过注入hello使用内容脚本定义的脚本来完成的。注入的函数使用自定义事件或postMessage.
  2. 内容脚本需要与后台通信。这是通过chrome.runtime.sendMessage.
    如果网页也需要接收回复:
  3. 从后台页面发送回复(sendMessage/ onMessage,见下文)。
  4. 在内容脚本中,创建自定义事件或用于postMessage向网页发送消息。
  5. 在网页中,处理此消息。

All of these methods are asynchronous, and have to be implemented through callback functions.

所有这些方法都是异步的,必须通过回调函数来实现。

These steps need to be designed carefully. Here's a generic implementation which implements all of the above steps. What you need to know about the implementation:

这些步骤需要仔细设计。这是一个实现上述所有步骤的通用实现。您需要了解的有关实施的信息:

  • In the code-to-be-injected, use the sendMessagemethod whenever the content script need to be contacted.
    Usage: sendMessage(<mixed message> [, <function callback>])
  • 在要注入的代码中,sendMessage只要需要联系内容脚本就使用该方法。
    用法:sendMessage(<mixed message> [, <function callback>])

contentscript.js

内容脚本.js

// Random unique name, to be used to minimize conflicts:
var EVENT_FROM_PAGE = '__rw_chrome_ext_' + new Date().getTime();
var EVENT_REPLY = '__rw_chrome_ext_reply_' + new Date().getTime();

var s = document.createElement('script');
s.textContent = '(' + function(send_event_name, reply_event_name) {
    // NOTE: This function is serialized and runs in the page's context
    // Begin of the page's functionality
    window.hello = function(string) {
        sendMessage({
            type: 'sayhello',
            data: string
        }, function(response) {
            alert('Background said: ' + response);
        });
    };

    // End of your logic, begin of messaging implementation:
    function sendMessage(message, callback) {
        var transporter = document.createElement('dummy');
        // Handles reply:
        transporter.addEventListener(reply_event_name, function(event) {
            var result = this.getAttribute('result');
            if (this.parentNode) this.parentNode.removeChild(this);
            // After having cleaned up, send callback if needed:
            if (typeof callback == 'function') {
                result = JSON.parse(result);
                callback(result);
            }
        });
        // Functionality to notify content script
        var event = document.createEvent('Events');
        event.initEvent(send_event_name, true, false);
        transporter.setAttribute('data', JSON.stringify(message));
        (document.body||document.documentElement).appendChild(transporter);
        transporter.dispatchEvent(event);
    }
} + ')(' + JSON.stringify(/*string*/EVENT_FROM_PAGE) + ', ' +
           JSON.stringify(/*string*/EVENT_REPLY) + ');';
document.documentElement.appendChild(s);
s.parentNode.removeChild(s);


// Handle messages from/to page:
document.addEventListener(EVENT_FROM_PAGE, function(e) {
    var transporter = e.target;
    if (transporter) {
        var request = JSON.parse(transporter.getAttribute('data'));
        // Example of handling: Send message to background and await reply
        chrome.runtime.sendMessage({
            type: 'page',
            request: request
        }, function(data) {
            // Received message from background, pass to page
            var event = document.createEvent('Events');
            event.initEvent(EVENT_REPLY, false, false);
            transporter.setAttribute('result', JSON.stringify(data));
            transporter.dispatchEvent(event);
        });
    }
});

background.js

背景.js

chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
    if (message && message.type == 'page') {
        var page_message = message.message;
        // Simple example: Get data from extension's local storage
        var result = localStorage.getItem('whatever');
        // Reply result to content script
        sendResponse(result);
    }
});

A Chrome extension is not complete without a manifest file, so here's the manifest.jsonfile which I used to test the answer:

没有清单文件的 Chrome 扩展程序是不完整的,所以这是manifest.json我用来测试答案的文件:

{
    "name": "Page to background and back again",
    "version": "1",
    "manifest_version": 2,
    "background": {
        "scripts": ["background.js"]
    },
    "content_scripts": [{
        "matches": ["http://jsfiddle.net/jRaPj/show/*"],
        "js": ["contentscript.js"],
        "all_frames": true,
        "run_at": "document_start"
    }]
}

This extension was tested at http://jsfiddle.net/jRaPj/show/(containing hello();as seen in the question), and shows a dialog saying "Background said: null".
Open the background page, use localStorage.setItem('whatever', 'Hello!');to see that the message is correctly changed.

此扩展程序在http://jsfiddle.net/jRaPj/show/(包含hello();问题中所见)进行了测试,并显示了一个对话框,上面写着“背景说:空”。
打开后台页面,使用localStorage.setItem('whatever', 'Hello!');查看消息是否正确更改。

回答by ahmed

There is a builtin solution to Send messages from web pagesto the extension

有一个内置的解决方案可以将消息从网页发送到扩展程序

mainfest.json

mainfest.json

"externally_connectable": {
  "matches": ["*://*.example.com/*"]
}

Web page:

网页:

// 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);
  });

Extension's background script:

扩展的后台脚本:

chrome.runtime.onMessageExternal.addListener(
  function(request, sender, sendResponse) {
    if (sender.url == blacklistedWebsite)
      return;  // don't allow this web page access
    if (request.openUrlInEditor)
      openUrl(request.openUrlInEditor);
  });

回答by Sudarshan

No, with your above code because of background page(s) architecture

不,由于后台页面架构,使用上面的代码

Yes with content scripts

是的,内容脚本

Demonstration Using Content Scripts

使用内容脚本进行演示

manifest.json

清单文件.json

Registering content scripts myscripts.js

注册内容脚本 myscripts.js

{
"name": "NFC",
"description": "NFC Liken",
"version": "0.1",
"manifest_version": 2,
"permissions": ["tabs", "http://*/", "https://*/"],
"content_scripts": {
    "matches": "http://www.example.com/*",
    "js": [ "myscript.js"]
  },
"browser_action": {
"default_icon": "sync-icon.png",
"default_title": "I Like I Tag"
}
}

Let me know if you need more information.

如果您需要更多信息,请与我们联系。