#Chrome扩展程序开发教程--03:消息传递
- 引言
- 1、基本介绍
- 2、简单通信
- 3、长时间通信
- 4、其它通信
- 4.1、Cross-extension messaging
- 4.2、Sending messages from web pages
- 4.3、Native messaging
引言
本系列博客旨在带来最新的Chrome扩展程序开发入门教程。
1、基本介绍
因为 content scripts 是注入到网页中运行的,不能直接和扩展程序其它部分共享环境和变量,所以需要一些方式来与扩展程序的其它部分进行通信。扩展程序中的任何一方都可以监听从另一端发出的消息,并在同一通道上作出回应。消息可以是任何有效的 JSON 对象(null、布尔值、数字、字符串、数组或对象)。
2、简单通信
简单通讯适用于单次的即时消息发送,chrome.runtime对象中内置了一个消息通道,可以直接发送。从 content scripts 向 service worker 发送消息的代码如下所示:
(async () => {
const response = await chrome.runtime.sendMessage({greeting: "hello"});
// do something with response here, not outside the function
console.log(response);
})();
如果需要从 service worker 向 content scripts 发送消息的话,则需要指定 tab 对象:
(async () => {
const [tab] = await chrome.tabs.query({active: true, lastFocusedWindow: true});
const response = await chrome.tabs.sendMessage(tab.id, {greeting: "hello"});
// do something with response here, not outside the function
console.log(response);
})();
无论接收方是 service worker 或 content scripts ,只需要添加接收消息的监听器即可:
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
console.log(sender.tab ?
"from a content script:" + sender.tab.url :
"from the extension");
if (request.greeting === "hello")
sendResponse({farewell: "goodbye"});
}
);
但需要注意的是,如果存在多个接收方,那么只有第一个调用 sendResponse 的接收方返回的消息才能被发送方接收。
3、长时间通信
有些时候,扩展程序中的部分模块之间需要进行长时间稳定通信,此时在用上面那种通信方法就不太合适了。
以下代码为从 content scripts 向 service worker 发送建立连接请求。其中 connect 的时候可以指定 name 属性,用以区分不同目的和功能的连接。
var port = chrome.runtime.connect({name: "knockknock"});
port.postMessage({joke: "Knock knock"});
port.onMessage.addListener(function(msg) {
if (msg.question === "Who's there?")
port.postMessage({answer: "Madame"});
else if (msg.question === "Madame who?")
port.postMessage({answer: "Madame... Bovary"});
});
如果需要从 service worker 向 content scripts 发送建立连接请求,则需要指定 tab 对象,和简单通信中的做法类似。
无论接收方是 service worker 或 content scripts ,只需要添加接收连接的监听器即可:
chrome.runtime.onConnect.addListener(function(port) {
console.assert(port.name === "knockknock");
port.onMessage.addListener(function(msg) {
if (msg.joke === "Knock knock")
port.postMessage({question: "Who's there?"});
else if (msg.answer === "Madame")
port.postMessage({question: "Madame who?"});
else if (msg.answer === "Madame... Bovary")
port.postMessage({question: "I don't get it."});
});
});
这里面的 port 就是连接的双方用来进行通信的对象,但其中有一些细节需要注意一下:
当从 service worker 向 content scripts 发送建立连接请求时,若目标 tab 中存在多个 frame ,且 content scripts 注入到了每个 frame 中,则每个 frame 中的 runtime.onConnect 事件都会被触发。同样的,也可能会出现多个 frame 中的 runtime.connect() 一起调用的情况。
4、其它通信
主要用到的就是上面介绍的两种通信手段,但还存在另外的通信,除非特殊目的,否则不会用到的,因此这里只简单介绍一下:
4.1、Cross-extension messaging
除了在自己的扩展程序中的不同组件之间进行通信外,还可以使用消息传递 API 与其他扩展程序进行通信。
4.2、Sending messages from web pages
与 Cross-extension messaging 一样,扩展程序可以接收和响应来自普通网页的消息。
4.3、Native messaging
扩展程序可以与主机上的应用程序进行通信。