序言
最近開發chrome插件,涉及到消息傳遞機時按照教程去敲代碼,結果總是不對。研究了大半天終於找到原因,現在記錄下。
程序
插件程序參考官網 chrome官網之消息傳遞機制, 不能翻牆的同事也可以參考下這位牛人的文章 [chrome插件開發之消息傳遞機制](http://ju.outofmemory.cn/entry/74567 "chrome插件開發之消息傳遞機制")
感謝這些牛人的分享讓我們學到了很多知識。
這篇大牛的文章中有content向background傳遞消息的按鈕,親測是沒問題。當時沒有background向content傳遞消息的方法,自己動手沒有成功,后來就找到了chrome管網,直接復制官網程序也沒成功。官網的案例程序程序如下,不能翻牆的童鞋可以看這里:
background.js
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function(response) {
console.log(response.farewell);
});
});
content.js
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"});
});
bug
沒有成功的原因看起來像是content頁面的chrome.runtime.onMessage沒有觸發。之前看介紹說content.js等同於頁面上的js,那我就想當然的以為可以在控制台調試content.js了。這樣就可以省去不斷打包插件的過程。
於是就出現了這樣的情景
咩,竟然是undefined
怪不得onMessage不能觸發。難道是瀏覽器版本問題,上網一通百度,stackoverflow上也有人問相同的問題,結果都沒有找到答案,也沒有一處說chrome棄用了onMessage方法。就是說onMessage仍然是可用的。為毛我看不到呢?
在最后放棄前我在公司的技術群上吼了一聲,看其他人有沒有遇到過相同的問題(本人一向低調,能自己百度的東西都不問別人)。后來老大說是我控制台環境不對所以才看不到runtime的其他方法。原來,控制台那里還可以選擇插件環境,點top就可以選擇。選擇了插件環境后,結果真的看到了onMessage方法。
再試下chrome.runtime
問題
現在問題又來啦,既然有onMessage方法,那為啥content沒有響應呢?找個原因又是花幾萬字都說不完的過程了。
廢話少說了,要扣工資了。就是經過大量的測試和實驗,終於找到了原因。
1、案例的background.js代碼中currentWindow是有害的,這個導致background不能發送消息,需要去掉。我也不知道為什么,知道的大神麻煩說下。
2、chrome的background.js是只執行一次的,當你安裝插件后,打開一個頁面看測試結果的時候,其實background已經把消息傳給了content。並且content也成功接收了。但是因為你是打開頁面后才打開發開發者工具的,開發者工具不會顯示之前的消息,所以開發者工具是空白的。之后你再刷新,background都不會再運行,控制台就始終是空白。看起來就好像content中onMessage方法失效了一樣
新代碼如下
background.js
chrome.tabs.onUpdated.addListener(
function(tabId,info,tab){
if(info.status=="complete")
console.log("complete")
chrome.tabs.sendMessage(tabId, {greeting: "inupdate"}, function(response) {
console.log(response);
});
}
)
我的程序每次tab有更新的時候就運行一次background。這樣你打開控制台再刷新就可以看到消息傳遞的結果。如果你想跟案例代碼一樣,讓background只運行一次的話,可以改成這樣。跟案例代碼的區別只是去掉了currentWindow
background.js(去掉了currentWindow)
chrome.tabs.query({active: true}, function(tabs) {
console.log("tabs",tabs)
console.log("tabs[0].id",tabs[0].id)
chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function(response) {
console.log(response);
});
});
之前我有試過使用runtime.sendMessage發送消息。當是這樣子是有問題。
原文如下
chrome.runtime.sendMessage sends a message to all open extension pages (i.e. background, popup, etc.)
chrome.tabs.sendMessage sends a message to all content scripts from the extension in a given tab
大概意思是runtime會發送消息給所有打開的擴展頁面比如背景或者popup,而tabs是給被被打開的標簽頁的所有content發消息。兩側
content.js
content跟官網的案例基本上一樣,我只是添加了一個自己的打印語句
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"});
}
else if(request.greeting =="inupdate"){
sendResponse({farewell:"getUpdate"})
}
});
這樣子就沒問題,background就可以傳遞消息給content了。ps下background的調試技巧。點擊下這里就可以調試background頁面了