强大大

导航

chrome插件开发-消息机制中的bug与解决方案

序言

最近开发chrome插件,涉及到消息传递机时按照教程去敲代码,结果总是不对。研究了大半天终于找到原因,现在记录下。

程序

插件程序参考官网 chrome官网之消息传递机制, 不能FQ的同事也可以参考下这位牛人的文章 [chrome插件开发之消息传递机制](http://ju.outofmemory.cn/entry/74567 "chrome插件开发之消息传递机制")

感谢这些牛人的分享让我们学到了很多知识。

这篇大牛的文章中有content向background传递消息的按钮,亲测是没问题。当时没有background向content传递消息的方法,自己动手没有成功,后来就找到了chrome管网,直接复制官网程序也没成功。官网的案例程序程序如下,不能FQ的童鞋可以看这里:

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页面了

posted on 2016-09-28 14:43  强大大  阅读(5646)  评论(3编辑  收藏  举报