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



我正在网页中寻找一个激活chrome扩展的函数。

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

<script>
hello();
</script>

我的背景页包含hello函数的定义:

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

test.html调用hello();时,我如何确保Chrome扩展的后台页面的hello被调用?

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

  1. 能够从网页中使用hello();。这是通过使用Content脚本注入定义hello的脚本来完成的。注入的函数使用自定义事件或postMessage与内容脚本进行通信
  2. 内容脚本需要与后台进行通信。这是通过chrome.runtime.sendMessage实现的
    如果网页也需要收到回复:
  3. 从后台页面发送回复(sendMessage/onMessage,见下文)
  4. 在内容脚本中,创建自定义事件或使用postMessage向网页发送消息
  5. 在网页中,处理此消息

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

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

  • 在要注入的代码中,只要需要联系内容脚本,就使用sendMessage方法
    用法:sendMessage(<mixed message> [, <function callback>])

contentscript.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

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

如果没有清单文件,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"
}]
}

此扩展在http://jsfiddle.net/jRaPj/show/(包含问题中看到的hello();),并显示一个对话框,上面写着"Background said:null">
打开后台页面,使用localStorage.setItem('whatever', 'Hello!');查看消息是否已正确更改。

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

mainfest.json

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

网页:

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

扩展的后台脚本:

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

否,由于后台页面架构,使用上述代码

有内容脚本

使用内容脚本的演示

manifest.json

正在注册内容脚本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"
}
}

如果你需要更多信息,请告诉我。

最新更新