Chrome插件開發入門(二)——消息傳遞機制

Chrome插件開發入門(二)——消息傳遞機制

 

因爲插件的js運行環境有區別,因此消息傳遞機制是一個重要內容。閱讀了不少博文,你們已經說得很清楚了,直接轉一篇@姬小光 的博文,總結的挺好。後面附一個本身寫過的demo,基本就對消息傳遞可以熟悉了。javascript

在開發 Chrome 擴展時常常須要在頁面之間進行通信,好比 background 與 content script 之間,background 與 popup 之間等等,本文結合官方文檔中的例子介紹了 chrome 擴展開發中消息傳遞的基本實現。html

通常狀況下,咱們會讓 background 來控制一切,將擴展的主要邏輯都放在 background 中比較便於管理。其它頁面能夠經過消息傳遞的機制與 background 進行通信。java

理論上 content script 與 popup 之間也能夠傳遞消息,但不建議這麼作。jquery

對於 background 和 popup 之間,其實能夠直接相互調用對方的方法,也不須要消息傳遞。那麼消息傳遞其實主要就是 content script 和 background 之間進行的了。chrome

在 Chrome 擴展內部的消息傳遞分爲兩種,一種是單次的消息請求,另一種是長鏈接。下面詳細舉例說明。json

簡單的單次請求(Simple one-time requests)

若是隻是想簡單的給擴展的其它頁面發送一次消息,那麼可使用 runtime.sendMessage 或者 tabs.sendMessage 方法,它容許你發送單次的JSON序列化後的數據,能夠從 content script 發送給擴展頁面,反之亦然。也能夠選擇性地傳入一個處理響應的回調函數。併發

從 content script 發送請求代碼以下:異步

contentscript.js ================ chrome.runtime.sendMessage({greeting: "hello"}, function(response) { console.log(response.farewell); });

從擴展頁面發送給 content script 也很相似,只是須要指定發送給那個 tab,下面的例子即爲向選中的 tab 發送消息:函數

background.html =============== chrome.tabs.getSelected(null, function(tab) { chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) { console.log(response.farewell); }); });

注:官方例子中的 getSelected 方法已經被廢棄了,可使用 chrome.tabs.query({active:true}, function(tab) {}) 來替代。post

在消息接收完畢時,須要設置一個  runtime.onMessage 事件監聽器來處理消息,這部分在 content script 和擴展頁面種都是同樣的:

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

注意:若是有多個頁面同時監聽 onMessage 事件,那麼只有第一個調用 sendResponse() 的頁面能夠成功返回響應信息,其它的都會被忽略。

小技巧:當事件監聽器返回時函數就不可用了,不過若是讓函數 return: true 的話,可讓該函數異步響應,直到調用 sendResponse 後才結束,具體說明請見文檔

長鏈接(Long-lived connections)

有時候咱們須要在 content script 和擴展頁面之間保持一個長期的通信信道,那麼你能夠分別使用 runtime.connect 和 tabs.connect 來創建長鏈接信道。能夠選擇性地給信道命名,方便你區分不一樣類型的鏈接。

每一個鏈接創建完成後都會返回一個 runtime.Port 對象,用來在鏈接之間發送和接收消息。

下面的例子展現瞭如何從 content script 創建鏈接,併發送和接收消息:

contentscript.js ================ 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"}); });

從擴展頁面創建鏈接也很相似,只是要指定要鏈接到哪一個tab。最簡單地能夠把上面的鏈接的代碼改爲 tabs.connect 便可。

爲了可以處理鏈接請求,須要設置一個  runtime.onConnect 事件監聽器,在 content script 和擴展頁面中中都是同樣的。當擴展的某一部分調用了 「connect() 」,該事件即被觸發,而後就可使用 runtime.Port 對象來發送和接收消息了。響應鏈接的代碼大體以下所示:

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

或許有時你還想知道鏈接什麼時候關閉,那麼你能夠監聽 runtime.Port.onDisconnect 事件,當通信的任意一端調用  runtime.Port.disconnect,或者包含該端口的頁面已被卸載。onDisconnect 事件能夠保證在每一個端口上只觸發一次。

另外,消息傳遞還包括不一樣擴展之間的消息傳遞,還有 Chrome 與本地程序之間的消息傳遞,這裏就不介紹了,感興趣的同窗能夠直接查看官方文檔

—————————————–分割線——————————————-

demo:

幾個最基本的文件

在這裏,先假設你們對chrome插件開發的最基本知識已有所掌握。例如什麼是manifest.json,什麼是background.html等。

manifest.json

{ "name": "A browser action with a popup that changes the page color.", "version": "1.0", "permissions":["tabs","<all_urls>"], "browser_action": { "default_icon": "icon.png" }, "background": { "page": "background.html" }, "content_scripts": [ { "matches": ["<all_urls>"], "js" : ["jquery-1.7.1.js","injectscript.js"] } ], "manifest_version": 2 }

background.html

<!DOCTYPE html> <html> <head> <title>bg</title> <script type="text/javascript" src="http://blog.chenqiushi.com/2014/03/31/chrome%e6%8f%92%e4%bb%b6%e5%bc%80%e5%8f%91%e5%85%a5%e9%97%a8%ef%bc%88%e4%ba%8c%ef%bc%89-%e6%b6%88%e6%81%af%e4%bc%a0%e9%80%92%e6%9c%ba%e5%88%b6/bg.js"><script> </head> <body> hello <body> </html>

這裏引用了一個後臺處理程序,bg.js,後面會講到。

擴展程序發送請求數據到內容腳本,內容腳本給出迴應

擴展程序後臺腳本bg.js

(function(){ chrome.browserAction.onClicked.addListener(function(tab) { // 擴展向內容腳本發送消息 chrome.tabs.sendMessage(tab.id,{ greeting: "hello to content script!" }, function(response) { console.log(response.farewell); }); }); })();

內容腳本injectscript.js

(function(){ console.log("injected"); var resOK = { farewell: "content script send response back..." }; var resError = { farewell: "content script hasError!" }; chrome.extension.onMessage.addListener(function(request, sender, sendResponse) { console.log("Request comes from extention " + sender.tab.url); if (request.greeting === "hello to content script!"){ sendResponse(resOK); }else{ sendResponse(resError); } }); })();

擴展程序向內容腳本發送一條消息hello to content script!,內容腳本接收到這條消息後去判斷是否是那句話,若是是,就返回resOK對象,若是不是,就返回resError對象。

這時,擴展程序收到內容腳本的一條迴應,至此,此番通話就結束了。

看一下結果截圖

擴展程序到內容腳本

內容腳本發送請求數據到擴展程序,擴展程序給出迴應

擴展程序後臺腳本bg.js

(function(){ var resOK = { farewell: "extension send response back..." }; var resError = { farewell: "extension hasError!" }; chrome.extension.onMessage.addListener(function(request, sender, sendResponse) { console.log("Request comes from content script " + sender.tab.url); if (request.greeting === "hello to extention!"){ sendResponse(resOK); }else{ sendResponse(resError); } }); })();

內容腳本injectscript.js

(function(){ console.log("injected"); chrome.extension.sendMessage({greeting: "hello to extention!"}, function(response) { console.log(response.farewell); }); })();

內容腳本向擴展程序發送一條消息hello to extention!,擴展程序接收到這條消息後去判斷是否是那句話,若是是,就返回resOK對象,若是不是,就返回resError對象。

這時,內容腳本收到擴展程序的一條迴應,至此,此番通話就結束了。

特別應該注意的是:擴展程序向內容腳本發送請求數據時用的是chrome.tabs.sendMessage,反過來,用的是chrome.extension.sendMessage

看一下結果截圖

內容腳本到擴展程序

若是之後還有一些chrome插件的學習總結,還會寫在這裏。

demo地址:
點擊下載demo

相關文章
相關標籤/搜索