chrome插件開發-消息機制中的bug與解決方案


序言

最近開發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了。這樣就可以省去不斷打包插件的過程。
於是就出現了這樣的情景

runtime

咩,竟然是undefined

怪不得onMessage不能觸發。難道是瀏覽器版本問題,上網一通百度,stackoverflow上也有人問相同的問題,結果都沒有找到答案,也沒有一處說chrome棄用了onMessage方法。就是說onMessage仍然是可用的。為毛我看不到呢?

在最后放棄前我在公司的技術群上吼了一聲,看其他人有沒有遇到過相同的問題(本人一向低調,能自己百度的東西都不問別人)。后來老大說是我控制台環境不對所以才看不到runtime的其他方法。原來,控制台那里還可以選擇插件環境,點top就可以選擇。選擇了插件環境后,結果真的看到了onMessage方法。

插件環境

再試下chrome.runtime

插件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頁面了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM