一個(gè)復(fù)雜的 Chrome 擴(kuò)展程序通常由 content_scripts
,background
,action popup
,side panel
,options page
,devtools
等部分組成,這些部分所負(fù)責(zé)的功能各不相同,所處的運(yùn)行環(huán)境各不相同,所能訪問的 chrome.*
API 也各不相同,也因此經(jīng)常需要通信告訴對(duì)方需要做什么。
下面是我畫的一張圖,簡(jiǎn)單說明各部分關(guān)系:
這些花花綠綠的部分各自運(yùn)行在不同的環(huán)境中,往往需要相互通信,Chrome 為我們提供了兩種通信方式:
接下來就詳細(xì)說說這兩種通信方式。
一次性請(qǐng)求(one-time requests)
如果要向擴(kuò)展程序的另一部分發(fā)送一條消息,有兩個(gè) API 可供調(diào)用:
chrome.runtime.sendMessage(extensionId?, message)
chrome.tabs.sendMessage(tabId, message)
從函數(shù)簽名很容易看出來,一個(gè)是向擴(kuò)展程序的各個(gè)部分發(fā)消息的,另一個(gè)是給某個(gè)瀏覽器的某個(gè)頁簽發(fā)消息的。
為什么設(shè)計(jì)兩個(gè) API?這是因?yàn)?nbsp;content_scripts
是一個(gè)很獨(dú)特的存在!
先說說瀏覽器的的工作原理。
瀏覽器的每個(gè)頁簽都是單獨(dú)的線程。每個(gè)頁簽運(yùn)行在與其他頁簽或擴(kuò)展相隔離的獨(dú)立線程中。如下圖所示
我們?cè)诿總€(gè)頁簽中打開頁面。content_scripts
是一個(gè)很特殊的存在!作為被注入到頁面的腳本,它的生命周期跟隨頁面。而擴(kuò)展程序的其他部分,都有自己的生命周期!如果你在各個(gè)部分查看它們的 location
,就會(huì)發(fā)現(xiàn),只有 content_scripts
的 origin 是頁面的 url 一樣,而其它部分的 location.origin 都是 chrome://your-extention-id
。
知道了 content_scripts
的特殊性后,那么這兩個(gè) API 就很好理解了。
chrome.runtime.sendMessage()
是給擴(kuò)展程序發(fā)消息的,它的第一個(gè)參數(shù)是一個(gè)可選的 extensionId,意味著不但可以給自身擴(kuò)展程序發(fā)消息,還能給別的擴(kuò)展程序發(fā)消息,它發(fā)送的消息可以被擴(kuò)展的任一部分接收到,包括 background
,action popup
,side panel
,options page
,devtools
等等,除了 content_scripts
?。?!
那么想給 content_scripts
發(fā)送消息怎么辦呢???
chrome.tabs.sendMessage()
就是專門用來給 content_scripts
發(fā)消息的!值得注意的是,想要給 content_scripts
發(fā)消息需要指定 tabId,也就是需要指明給哪個(gè)頁簽下的頁面的 content_scripts
發(fā)消息。這個(gè)設(shè)計(jì)很好,因?yàn)槊總€(gè)頁簽的頁面都運(yùn)行了一份 content_scripts
,這就避免了無關(guān)的頁面接收到消息。
發(fā)送消息搞定啦,有方法發(fā)送就得有方法接收才行啊。
接收消息的方法只有一個(gè) API:
chrome.runtime.onMessage.addListener( (message, sender, sendResponse) => boolean | undefined)
在擴(kuò)展程序的任意部分(包括 content_scripts
)都是用這個(gè)接收消息。這很方便。
長(zhǎng)期連接(long-lived connections)
長(zhǎng)期鏈接的 API 和一次性消息的 API 是相互對(duì)應(yīng)的。
要?jiǎng)?chuàng)建一個(gè)可重復(fù)使用的長(zhǎng)期消息傳遞通道,有兩個(gè) API 可以調(diào)用:
chrome.runtime.connect(extensionId?, connectInfo?): Port
chrome.tabs.connect(tabId, connectInfo?): Port
這兩個(gè) API 的設(shè)計(jì)和一次性消息的一樣。
chrome.runtime.connect()
用于和擴(kuò)展程序的任一部分建立消息通道,除了 content_scripts
?。?!
而 chrome.tabs.connect()
是專門用來和 content_scripts
建立消息通道噠!
chrome.{runtime,tabs}.connect()
返回的是一個(gè) Port 對(duì)象。Port 就是被設(shè)計(jì)用來在擴(kuò)展程序的不同部分之間進(jìn)行雙向通信的一個(gè)接口。
作者:dombro
轉(zhuǎn)自:https://www.cnblogs.com/iovec/p/messaging.html
該文章在 2024/1/27 8:51:20 編輯過