本文從瀏覽器架構(gòu)演進(jìn)、插件運(yùn)行機(jī)制、插件基本介紹和一些常見的插件實(shí)現(xiàn)思路幾個(gè)方向聊聊Chrome插件。
瀏覽器架構(gòu)演進(jìn)
單進(jìn)程瀏覽器時(shí)代
單進(jìn)程瀏覽器是指瀏覽器的所有功能模塊都是運(yùn)行在同一個(gè)進(jìn)程里,這些模塊包含了網(wǎng)絡(luò)、插件、JavaScript 運(yùn)行環(huán)境、渲染引擎和頁面等。在 2007 年之前,市面上瀏覽器都是單進(jìn)程的。
單進(jìn)程瀏覽器的架構(gòu) 很多功能模塊運(yùn)行在一個(gè)進(jìn)程里,是導(dǎo)致單進(jìn)程瀏覽器不穩(wěn)定、不流暢和不安全的一個(gè)主要因素。
不穩(wěn)定:早期瀏覽器需要借助于插件來實(shí)現(xiàn)諸如 Web 視頻、Web 游戲等各種強(qiáng)大的功能,但是插件是最容易出問題的模塊,并且還運(yùn)行在瀏覽器進(jìn)程之中,所以一個(gè)插件的意外崩潰會(huì)引起整個(gè)瀏覽器的崩潰。除了插件之外,渲染引擎模塊也是不穩(wěn)定的,通常一些復(fù)雜的 JavaScript 代碼就有可能引起渲染引擎模塊的崩潰。和插件一樣,渲染引擎的崩潰也會(huì)導(dǎo)致整個(gè)瀏覽器的崩潰。
不流暢:所有頁面的渲染模塊、JavaScript 執(zhí)行環(huán)境以及插件都是運(yùn)行在同一個(gè)線程中的,這就意味著同一時(shí)刻只能有一個(gè)模塊可以執(zhí)行。如果一個(gè)腳本非常耗時(shí),它就會(huì)獨(dú)占整個(gè)線程,這樣導(dǎo)致其他運(yùn)行在該線程中的頁面沒有機(jī)會(huì)去執(zhí)行任務(wù),導(dǎo)致整個(gè)瀏覽器失去響應(yīng),變卡頓。
不安全:當(dāng)你在頁面運(yùn)行一個(gè)插件時(shí),插件可以操作系統(tǒng)資源,如果是個(gè)惡意插件,那么它就可以釋放病毒、竊取你的賬號(hào)密碼,引發(fā)安全性問題。
多進(jìn)程瀏覽器時(shí)代
早期架構(gòu)
2008 年 Chrome 發(fā)布時(shí)的進(jìn)程架構(gòu) 從圖中可以看出,早期的架構(gòu)已經(jīng)對(duì)瀏覽器的能力進(jìn)行了拆分,主要拆分為三類:瀏覽器進(jìn)程、插件進(jìn)程和渲染進(jìn)程。每個(gè)頁面是運(yùn)行在單獨(dú)的渲染進(jìn)程中的,同時(shí)頁面里的插件也是運(yùn)行在單獨(dú)的插件進(jìn)程之中,進(jìn)程之間是通過 IPC 機(jī)制進(jìn)行通信。 這就解決了單進(jìn)程時(shí)代瀏覽器的各種問題:
解決不穩(wěn)定:由于進(jìn)程是相互隔離的,所以當(dāng)一個(gè)頁面或者插件崩潰時(shí),影響到的僅僅是當(dāng)前的頁面進(jìn)程或者插件進(jìn)程,并不會(huì)影響到瀏覽器和其他頁面。
解決不流暢:JavaScript運(yùn)行在渲染進(jìn)程中,所以即使JavaScript阻塞了渲染進(jìn)程,也只會(huì)影響當(dāng)前的渲染頁面,并不會(huì)影響瀏覽器和其他頁面,因?yàn)槠渌撁娴哪_本運(yùn)行在它們自己的渲染進(jìn)程中。
解決不安全:Chrome把插件進(jìn)程和渲染進(jìn)程鎖在沙箱里面,沙箱里面的程序可以運(yùn)行,但是不能在硬盤上寫入任何數(shù)據(jù),也不能在敏感位置讀取任何數(shù)據(jù),這樣即使在渲染進(jìn)程或者插件進(jìn)程里面執(zhí)行了惡意程序,惡意程序也無法突破沙箱去獲取系統(tǒng)權(quán)限。
近期架構(gòu)
相較之前,近期的架構(gòu)又有了很多新的變化。
近期Chrome進(jìn)程架構(gòu) 從圖中可以看出,最新的 Chrome 瀏覽器包括:1 個(gè)瀏覽器主進(jìn)程、1 個(gè) GPU 進(jìn)程、1 個(gè)網(wǎng)絡(luò)進(jìn)程、多個(gè)渲染進(jìn)程和多個(gè)插件進(jìn)程。
瀏覽器進(jìn)程:主要負(fù)責(zé)界面顯示、用戶交互、子進(jìn)程管理,同時(shí)提供存儲(chǔ)等功能??梢岳斫鉃g覽器進(jìn)程是一個(gè)統(tǒng)一的"調(diào)度大師"去調(diào)度其他進(jìn)程,比如我們?cè)诘刂窓谳斎雞rl時(shí),瀏覽器進(jìn)程首先會(huì)調(diào)用網(wǎng)絡(luò)進(jìn)程。
渲染進(jìn)程:核心任務(wù)是將HTML、CSS和JavaScript轉(zhuǎn)換為用戶可以交互的網(wǎng)頁,排版引擎Blink和JavaScript引擎V8都是運(yùn)行在該進(jìn)程中,默認(rèn)情況下,Chrome會(huì)為每個(gè) Tab 標(biāo)簽創(chuàng)建一個(gè)渲染進(jìn)程。出于安全考慮,渲染進(jìn)程都是運(yùn)行在沙箱模式下。
GPU進(jìn)程:其實(shí),Chrome 剛開始發(fā)布的時(shí)候是沒有 GPU 進(jìn)程的。而 GPU 的使用初衷是為了實(shí)現(xiàn) 3D CSS 的效果,只是隨后網(wǎng)頁、Chrome 的 UI 界面都選擇采用 GPU 來繪制,這使得 GPU 成為瀏覽器普遍的需求。最后,Chrome 在其多進(jìn)程架構(gòu)上也引入了 GPU 進(jìn)程。
網(wǎng)絡(luò)進(jìn)程:主要負(fù)責(zé)頁面的網(wǎng)絡(luò)資源加載,之前是作為一個(gè)模塊運(yùn)行在瀏覽器進(jìn)程里面的,直至最近才獨(dú)立出來,成為一個(gè)單獨(dú)的進(jìn)程。
插件進(jìn)程:主要是負(fù)責(zé)插件的運(yùn)行,因插件易崩潰,所以需要通過插件進(jìn)程來隔離,以保證插件進(jìn)程崩潰不會(huì)對(duì)瀏覽器和頁面造成影響。
當(dāng)前架構(gòu)
目前Chrome瀏覽器的架構(gòu)正在發(fā)生一些改變,稱為面向服務(wù)的架構(gòu)(SOA),目的是將和瀏覽器本身(Chrome)相關(guān)的部分拆分為一個(gè)個(gè)不同的服務(wù),服務(wù)化之后,這些功能既可以放在不同的進(jìn)程里面運(yùn)行也可以合并為一個(gè)單獨(dú)的進(jìn)程運(yùn)行。 這樣做的主要原因是讓Chrome在不同性能的硬件上有不同的表現(xiàn)。當(dāng)Chrome運(yùn)行在一些性能比較好的硬件時(shí),瀏覽器進(jìn)程相關(guān)的服務(wù)會(huì)被放在不同的進(jìn)程運(yùn)行以提高系統(tǒng)的穩(wěn)定性。相反如果硬件性能不好,這些服務(wù)就會(huì)被放在同一個(gè)進(jìn)程里面執(zhí)行來減少內(nèi)存的占用。
面向服務(wù)的架構(gòu)
插件運(yùn)行機(jī)制
在運(yùn)行機(jī)制前,我們先來回顧一下打開頁面會(huì)發(fā)生什么:
打開頁面發(fā)生了什么
用戶新增一個(gè)tab,此時(shí)系統(tǒng)瀏覽器進(jìn)程、渲染進(jìn)程、GPU 進(jìn)程、網(wǎng)絡(luò)進(jìn)程會(huì)被創(chuàng)建好;
用戶輸入url,瀏覽器進(jìn)程檢查url,組裝協(xié)議,構(gòu)成完整的url;
瀏覽器進(jìn)程通過進(jìn)程間通信(IPC)把url請(qǐng)求發(fā)送給網(wǎng)絡(luò)進(jìn)程;
網(wǎng)絡(luò)進(jìn)程接收到url請(qǐng)求后檢查本地緩存是否緩存了該請(qǐng)求資源,如果有則將該資源返回給瀏覽器進(jìn)程;
如果沒有,網(wǎng)絡(luò)進(jìn)程向web服務(wù)器發(fā)起http請(qǐng)求(網(wǎng)絡(luò)請(qǐng)求);
網(wǎng)絡(luò)進(jìn)程解析響應(yīng)流程;
檢查狀態(tài)碼,非200執(zhí)行狀態(tài)碼對(duì)應(yīng)的處理邏輯;
200響應(yīng)處理:檢查響應(yīng)類型Content-Type,如果是字節(jié)流類型,則將該請(qǐng)求提交給下載管理器,不再進(jìn)行后續(xù)的渲染,如果是html則通知瀏覽器進(jìn)程準(zhǔn)備渲染進(jìn)程進(jìn)行渲染;
準(zhǔn)備渲染進(jìn)程
瀏覽器進(jìn)程檢查當(dāng)前url是否和之前打開的渲染進(jìn)程根域名是否相同,如果相同,則復(fù)用原來的進(jìn)程,如果不同,則開啟新的渲染進(jìn)程;
傳輸數(shù)據(jù)、更新狀態(tài)
渲染進(jìn)程準(zhǔn)備好后,瀏覽器向渲染進(jìn)程發(fā)起“提交文檔”的消息,渲染進(jìn)程接收到消息和網(wǎng)絡(luò)進(jìn)程建立傳輸數(shù)據(jù)的“管道”;
渲染進(jìn)程接收完數(shù)據(jù)后,向?yàn)g覽器發(fā)送確認(rèn)消息;
瀏覽器進(jìn)程接收到確認(rèn)消息后更新瀏覽器界面狀態(tài):安全、地址欄url、前進(jìn)后退的歷史狀態(tài)、更新web頁面;
打開插件發(fā)生了什么
插件的運(yùn)行相較于頁面會(huì)有簡化
我們打開瀏覽器,新增一個(gè)空白tab頁
tab欄空白處右鍵,選擇任務(wù)管理器,打開任務(wù)管理器面板
可以看到運(yùn)行了6個(gè)進(jìn)程,分別是瀏覽器進(jìn)程、GPU進(jìn)程、網(wǎng)絡(luò)進(jìn)程、存儲(chǔ)進(jìn)程、渲染進(jìn)程和擴(kuò)展進(jìn)程。
擴(kuò)展進(jìn)程中運(yùn)行Extension Page,主要包括backgrount.html和popup.html;
backgrount.html中沒有任何內(nèi)容,是通過background.js創(chuàng)建生成,當(dāng)瀏覽器打開時(shí),會(huì)自動(dòng)加載插件的background.js文件,它獨(dú)立于網(wǎng)頁并且一直運(yùn)行在后臺(tái),它主要通過調(diào)用瀏覽器提供的API和瀏覽器進(jìn)行交互;
popup.html有內(nèi)容的,跟我們普通的web頁面一樣,由html、css、Javascript組成,它是按需加載的,需要用戶去點(diǎn)擊地址欄的按鈕去觸發(fā),才能彈出頁面;
渲染進(jìn)程主要運(yùn)行Web Page,當(dāng)打開頁面時(shí),會(huì)將content_script.js加載并注入到該網(wǎng)頁的環(huán)境中,它和網(wǎng)頁中引入的Javascript一樣,可以操作該網(wǎng)頁的DOM Tree,改變頁面的展示效果;
GPU進(jìn)程主要為插件界面的渲染提供硬件能力支持;
網(wǎng)絡(luò)進(jìn)程主要處理插件中的外部資源請(qǐng)求,比如nexydy插件依賴到一些外部js;
存儲(chǔ)進(jìn)程為插件提供本地存儲(chǔ)能力,比如使用chrome.storage.local進(jìn)行持久化存儲(chǔ);
瀏覽器進(jìn)程在這里更多起到橋梁作用,作為中轉(zhuǎn)可以實(shí)現(xiàn)Extension Page和content_script.js之間的消息通信。
插件基本介紹
版本發(fā)展
chrome插件存在三個(gè)版本,分別是Manifest V1、Manifest V2和Manifest V3。 其中MV1版本已經(jīng)被廢棄了,目前市面上存在MV2和MV3版本,以MV2為主流,在被MV3慢慢取代。 時(shí)間線:
Manifest V2新特性
https://developer.chrome.com/docs/extensions/mv2/manifestVersion/#manifest-v1-changes
設(shè)置了默認(rèn)的內(nèi)容安全策略`script-src 'self'; object-src 'self';`。有關(guān)內(nèi)容安全策略的詳細(xì)配置,可以參考MDN文檔;
默認(rèn)情況下,插件包內(nèi)的資源不再可供外部網(wǎng)站使用。需要通過清單web_accessible_resources屬性將其顯式列入白名單;
browser action API更改;
page action API更改;
chrome.extension代替chrome.self來指向插件本身;
chrome.extension.getTabContentses和chrome.extension.getExtensionTabs廢棄,使用extension.getViews替代;
Port.tab廢棄,使用runtime.Port替代;
Manifest V3新特性
Service worker替換Background Page;
網(wǎng)絡(luò)請(qǐng)求修改廢棄webRequest API使用新的declarativentrequest API來處理;
不再允許執(zhí)行遠(yuǎn)程托管的代碼,只能執(zhí)行擴(kuò)展包內(nèi)包含的JS;
Promises 已經(jīng)被添加到許多方法中,但仍支持回調(diào)作為替代方法;
Browser Action API和Page Action API被統(tǒng)一為單獨(dú)的Action API;
Web可訪問的資源,可以只對(duì)指定的站點(diǎn)和擴(kuò)展可用;
內(nèi)容安全策略(CSP),現(xiàn)在可以為單個(gè)對(duì)象中的不同執(zhí)行上下文指定單獨(dú)的CSP;
executeScript的變化,不能再執(zhí)行任意字符串,只能執(zhí)行腳本文件和函數(shù);
切換MV3會(huì)帶來的問題
由于background不再支持page頁面配置background.html,因此也無法調(diào)用window對(duì)象上的XMLHttpRequest來構(gòu)建ajax請(qǐng)求,也就是說我們不能像V2版本一樣,在background.html中使用XMLHttpRequest來發(fā)送請(qǐng)求了,而是需要使用fetch來獲取接口數(shù)據(jù);
由于service workers是短暫的,在不使用時(shí)會(huì)終止,這意味著它們?cè)谡麄€(gè)插件運(yùn)行期間會(huì)不斷的啟動(dòng)、運(yùn)行和終止,也就是不穩(wěn)定的;因此我們可能需要對(duì)V2中background.js的代碼邏輯進(jìn)行一些改造,以往我們會(huì)習(xí)慣將一些數(shù)據(jù)直接存儲(chǔ)到全局變量,比如像下面這樣:
// V2 background.js let saveUserName = ""; // 其他頁面,比如content-script或者popup中存儲(chǔ)數(shù)據(jù) chrome.runtime.onMessage.addListener(({ type, name }) => { if (type === "set-name") { saveUserName = name; } }); // 點(diǎn)擊popup時(shí)展示數(shù)據(jù) chrome.action.onClicked.addListener((tab) => { // 這里saveUserName可能為空字符串 console.log(saveUserName, "saveUserName"); });
因此在V3中,需要對(duì)這種全局變量數(shù)據(jù)進(jìn)行改造,改造的方式也很簡單,就是將數(shù)據(jù)持久化保存到storage中,需要用到的地方隨用隨?。?/p>
// V3 service worker chrome.runtime.onMessage.addListener(({ type, name }) => { if (type === "set-name") { chrome.storage.local.set({ name }); } }); chrome.action.onClicked.addListener(async (tab) => { const { name } = await chrome.storage.local.get(["name"]); chrome.tabs.sendMessage(tab.id, { name }); });
由webRequest API切換至declarativentrequest API,很多代碼邏輯需要重構(gòu);
為什么切換MV3?
從Manifest V1到Manifest V2,可以看到Chrome想提高插件的隱私和安全,同時(shí)也優(yōu)化了不少API。 而Manifest V3除了安全性更完善外,還在性能上下了功夫。Manifest V3 的核心非常明確,就是限制擴(kuò)展對(duì)系統(tǒng)資源的使用。一直以來高資源占用都是 Chrome 為人詬病的痛點(diǎn),而且擴(kuò)展由于在后臺(tái)運(yùn)行,如果出現(xiàn)問題,更是難以定位和管理。 雖然增加了諸多限制,但Manifest V3還是有優(yōu)點(diǎn)的:
Service Worker 使擴(kuò)展不再能常駐后臺(tái),讓擴(kuò)展所占用的資源可以被回收,降低了瀏覽器整體的開銷;
限制規(guī)則的數(shù)量,相當(dāng)于控制了單一擴(kuò)展在規(guī)則計(jì)算方面的資源使用上限;
這些變化可以讓 Chrome 變得更加流暢,對(duì)于用戶來說是好事。
展示形式
Chrome插件有以下常見的8中展現(xiàn)形式:
browserAction(瀏覽器右上角)
在瀏覽器右上角擴(kuò)展程序一欄顯示,包含一個(gè)圖標(biāo)、名稱和popup
山海關(guān)插件popup
pageAction(地址欄右側(cè))
pageAction指的是在當(dāng)某些特定頁面打開才顯示的圖標(biāo)。在早些版本的Chrome是將pageAction放在地址欄的最右邊,左鍵單擊彈出popup,右鍵單擊則彈出相關(guān)默認(rèn)的選項(xiàng)菜單。而新版的Chrome更改了這一策略,pageAction和普通的browserAction一樣也是放在瀏覽器右上角,只不過沒有點(diǎn)亮?xí)r是灰色的,點(diǎn)亮了才是彩色的,灰色時(shí)無論左鍵還是右鍵單擊都是彈出選項(xiàng)。
右鍵菜單
通過開發(fā)Chrome插件可以自定義瀏覽器的右鍵菜單,主要是通過chrome.contextMenus API實(shí)現(xiàn),右鍵菜單可以出現(xiàn)在不同的上下文,比如普通頁面、選中的文字、圖片、鏈接,等等。
掘金插件右鍵菜單
override(覆蓋特定頁面)
使用override可以將Chrome默認(rèn)的一些特定頁面替換掉,改為使用擴(kuò)展提供的頁面。 擴(kuò)展可以替代如下頁面:
歷史記錄:從工具菜單上點(diǎn)擊歷史記錄時(shí)訪問的頁面,或者從地址欄直接輸入chrome://history
新標(biāo)簽頁:當(dāng)創(chuàng)建新標(biāo)簽的時(shí)候訪問的頁面,或者從地址欄直接輸入chrome://newtab
書簽:瀏覽器的書簽,或者直接輸入 chrome://bookmarks
掘金插件替換了新標(biāo)簽頁
devtools(開發(fā)者工具)
Chrome允許插件在開發(fā)者工具(devtools)上開發(fā),主要表現(xiàn)在:
自定義一個(gè)和多個(gè)和Elements、Console、Sources等同級(jí)別的面板;
自定義側(cè)邊欄(sidebar),目前只能自定義Elements面板的側(cè)邊欄;
React Developer Tools
option(選項(xiàng)頁)
插件的設(shè)置頁面,可以在右上角入口右鍵,有一個(gè)選項(xiàng)標(biāo)簽。
omnibox
omnibox是向用戶提供搜索建議的一種方式,可以在搜索欄輸入特定的標(biāo)識(shí)然后按Tab進(jìn)入搜索。
JSON Viewer插件
桌面通知
Chrome提供了一個(gè)chrome.notificationsAPI以便插件推送桌面通知,暫未找到chrome.notifications和HTML5自帶的Notification的顯著區(qū)別及優(yōu)勢(shì)。 在后臺(tái)JS中,無論是使用chrome.notifications還是Notification都不需要申請(qǐng)權(quán)限(HTML5方式需要申請(qǐng)權(quán)限),直接使用即可。
核心介紹
manifest.json
這是一個(gè)Chrome插件最重要也是必不可少的文件,用來配置所有和插件相關(guān)的配置,必須放在根目錄。其中,manifest_version、name、version3個(gè)是必不可少的。 Manifest V2
{ // 清單文件的版本,這里先使用2演示 "manifest_version": 2, // 插件的名稱 "name": "...", // 插件的版本 "version": "1.0.0", // 插件描述 "description": "...", // 圖標(biāo),一般偷懶全部用一個(gè)尺寸的也沒問題 "icons": { "16": "img/icon.png", "48": "img/icon.png", "128": "img/icon.png" }, // 會(huì)一直常駐的后臺(tái)JS或后臺(tái)頁面 "background": { "scripts": ["js/background.js"] }, // 瀏覽器右上角圖標(biāo)設(shè)置,browser_action、page_action、app必須三選一 "browser_action": { "default_icon": "img/icon.png", "default_title": "...", "default_popup": "popup.html" }, // 當(dāng)某些特定頁面打開才顯示的圖標(biāo) "page_action": { "default_icon": "img/icon.png", "default_title": "...", "default_popup": "popup.html" }, // 需要直接注入頁面的JS "content_scripts": [{ "matches": [""], "js": ["js/content-script.js"], "css": ["css/custom.css"], // 代碼注入的時(shí)機(jī),document_start, document_end, document_idle,默認(rèn)document_idle "run_at": "document_start" }, ], // 權(quán)限申請(qǐng) "permissions": [ "contextMenus", // 右鍵菜單 "tabs", // 標(biāo)簽 "notifications", // 通知 "webRequest", // web請(qǐng)求 "webRequestBlocking", "storage", // 插件本地存儲(chǔ) "https://*/*" // 可以通過executeScript或者insertCSS訪問的網(wǎng)站 ], // 普通頁面能夠直接訪問的插件資源列表,如果不設(shè)置是無法直接訪問的 "web_accessible_resources": ["js/inject.js"], "homepage_url": "...", // 插件主頁 "chrome_url_overrides": { // 覆蓋瀏覽器默認(rèn)頁面 "newtab": "newtab.html" }, "options_ui": { // 插件選項(xiàng)頁 "page": "options.html", "chrome_style": true }, "omnibox": { "keyword" : "..." }, // 向地址欄注冊(cè)一個(gè)關(guān)鍵字以提供搜索建議,只能設(shè)置一個(gè)關(guān)鍵字 "default_locale": "zh_CN", // 默認(rèn)語言 "devtools_page": "devtools.html", // devtools頁面入口,注意只能指向一個(gè)HTML文件,不能是JS文件 "content_security_policy": "...", // 安全策略 "web_accessible_resources": [ // 可以加載的資源 RESOURCE_PATHS ] }
Manifest V3(僅展示與V2版本的不同點(diǎn))
{ "manifest_version": 3, "background": { "service_worker": js/background.js" }, "action": { //browser_action 和 page_action,統(tǒng)一為 Action "default_icon": "img/icon.png", "default_title": "這是一個(gè)示例Chrome插件", "default_popup": "popup.html" } "content_security_policy": { "extension_pages": "...", "sandbox": "..." }, "web_accessible_resources": [{ "resources": [RESOURCE_PATHS] }] }
content-scripts
是Chrome插件中向頁面注入腳本的一種形式(雖然名為script,其實(shí)還可以包括css的),借助content-scripts我們可以實(shí)現(xiàn)通過配置的方式輕松向指定頁面注入JS和CSS。 content-scripts和原始頁面共享DOM,但不共享JS。如要訪問頁面JS(例如某個(gè)JS變量),只能通過injected js來實(shí)現(xiàn)。content-scripts不能訪問絕大部分chrome API,除了下面這4種:
chrome.extension
chrome.i18n
chrome.runtime
chrome.storage
這些API絕大部分時(shí)候都?jí)蛴昧?,有需要調(diào)用其它API的話,可以通過通信讓background或service worker來幫忙調(diào)用
background
后臺(tái)是一個(gè)常駐的頁面,它的生命周期是插件中所有類型頁面中最長的,它隨著瀏覽器的打開而打開,隨著瀏覽器的關(guān)閉而關(guān)閉,所以通常把需要一直運(yùn)行的、啟動(dòng)就運(yùn)行的、全局的代碼放在background里面。 background的權(quán)限非常高,幾乎可以調(diào)用所有的Chrome擴(kuò)展API(除了devtools),而且它可以無限制跨域,可以跨域訪問任何網(wǎng)站而無需要求對(duì)方設(shè)置CORS。 background的概念在MV3版本中變?yōu)榱藄ervice worker,區(qū)別在于生命周期變短了,service worker是短暫的基于事件的腳本,所以不適合用來保存全局變量。
popup
popup是點(diǎn)擊右上角圖標(biāo)時(shí)打開的一個(gè)小窗口網(wǎng)頁,焦點(diǎn)離開網(wǎng)頁就立即關(guān)閉,一般用來做一些臨時(shí)性的交互。權(quán)限級(jí)別和background差不多,就是生命周期比較短。
injected-script
chrome插件中其實(shí)沒有injected-script這一概念,這是開發(fā)者們?cè)陂_發(fā)過程中衍生出來的一種概念,指的是通過DOM操作的方式向頁面注入的一種JS。 因?yàn)閏ontent-script無法訪問頁面中的JS,雖然可以操作DOM,但是DOM卻不能調(diào)用它,也就是無法在DOM中通過綁定事件的方式調(diào)用content-script中的代碼。但是在網(wǎng)頁中增加一個(gè)按鈕來調(diào)用插件的能力是一個(gè)比較常見的需求,所以誕生了injected-script。
插件通信機(jī)制
講通信機(jī)制之前,先回顧一下插件中存在的腳本類型。 Chrome插件的JS主要可以分為這5類:injected script、content-script、popup js、background js和devtools js。
權(quán)限對(duì)比
JS種類 | 可訪問的API | DOM訪問情況 | JS訪問情況 | 直接跨域 |
injected | 和普通JS無任何差別,不能訪問任何擴(kuò)展API | 可以訪問 | 可以訪問 | 不可以 |
content | 只能訪問 extension、runtime等部分API | 可以訪問 | 不可以 | 不可以 |
popup | 可訪問絕大部分API,除了devtools系列 | 不可直接訪問 | 不可以 | 可以 |
background | 可訪問絕大部分API,除了devtools系列 | 不可直接訪問 | 不可以 | 可以 |
devtools | 只能訪問 devtools、extension、runtime等部分API | 可以 | 可以 | 不可以 |
通過權(quán)限對(duì)比可以看到,每一種腳本在權(quán)限上都不相同,所以各種腳本間的相互通信就非常重要,這也是插件能夠?qū)崿F(xiàn)眾多功能的基礎(chǔ)。
通信概覽
injected | content | popup | background | |
injected | - | window.postMessage | - | - |
content | window.postMessage | - | chrome.runtime.sendMessage chrome.runtime.connect | chrome.runtime.sendMessage chrome.runtime.connect |
popup | - | chrome.tabs.sendMessage chrome.tabs.connect | - | chrome.extension. getBackgroundPage |
background | - | chrome.tabs.sendMessage chrome.tabs.connect | chrome.extension.getViews | - |
devtools | chrome.devtools. inspectedWindow.eval | - | chrome.runtime.sendMessage | chrome.runtime.sendMessage |
一些常見插件的實(shí)現(xiàn)思路
埋點(diǎn)日志檢測(cè)
一般業(yè)務(wù)中都會(huì)進(jìn)行一些埋點(diǎn)上報(bào),埋點(diǎn)的本質(zhì)就是發(fā)送一些帶特定參數(shù)的請(qǐng)求,前端本地調(diào)試的時(shí)候想實(shí)時(shí)查看埋點(diǎn)信息通常需要去查看上報(bào)接口的入?yún)?,或者去?duì)應(yīng)的埋點(diǎn)平臺(tái)查看,這樣非常不方便。 基于這個(gè),我們可以使用插件來幫助我們快速的可視化查看埋點(diǎn)信息:
頁面注入小工具
插件的另一個(gè)常見用法就是往頁面注入一些工具代碼,比如去除頁面廣告工具。
總結(jié)
隨著瀏覽器不斷的發(fā)展,Chrome逐漸把一些基礎(chǔ)服務(wù)獨(dú)立出來,類似于一個(gè)跨平臺(tái)的線上操作系統(tǒng)。
Chrome插件提供的能力很豐富,比如代碼注入、跨域請(qǐng)求、持久化方案、各種通信機(jī)制等,開發(fā)者可以發(fā)揮想象,組裝不同能力以適應(yīng)不同場景的需求,基本可以實(shí)現(xiàn)現(xiàn)代web所能支持的所有功能。
Chrome插件MV2版本將在24年1月全面廢棄,需要盡快遷移至MV3版本。
審核編輯:黃飛
-
操作系統(tǒng)
+關(guān)注
關(guān)注
37文章
7021瀏覽量
124672 -
瀏覽器
+關(guān)注
關(guān)注
1文章
1040瀏覽量
35957 -
Chrome
+關(guān)注
關(guān)注
0文章
346瀏覽量
18393 -
javascript
+關(guān)注
關(guān)注
0文章
525瀏覽量
54351 -
進(jìn)程
+關(guān)注
關(guān)注
0文章
206瀏覽量
14178
原文標(biāo)題:從瀏覽器原理出發(fā)聊聊Chrome插件
文章出處:【微信號(hào):OSC開源社區(qū),微信公眾號(hào):OSC開源社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
Chrome 15正式版瀏覽器登場
安裝了chrome瀏覽器,但還是很卡
Chrome瀏覽器將在ARM內(nèi)核運(yùn)行,Google Andr
視頻監(jiān)控系統(tǒng)跨瀏覽器插件的研究與實(shí)現(xiàn)
四大瀏覽器續(xù)航對(duì)決,結(jié)果Chrome瀏覽器完勝
Chrome成為瀏覽器市場的霸主 微軟Edge慘淡收?qǐng)?/a>
谷歌瀏覽器 Chrome 發(fā)布 Linux 版本即將跟進(jìn)
Chrome瀏覽器隱私設(shè)置重新設(shè)計(jì)后有什么不同
五大Chrome神級(jí)插件,讓Chrome瀏覽器更加好用十倍
Chrome瀏覽器插件v1.9.0發(fā)布 使用了最簡單的JavaScript代碼解析

評(píng)論