制作一个chrome 插件程序 - archering/basic GitHub Wiki

创建一个chrome extension

创建一个项目结构

 1│  me                                        me
 2│  me\assets                                 ┊┈┈assets
 3│  me\assets\timg.jpg                        ┊    ┊┈┈timg.jpg
 4│  me\background.js                          ┊┈┈background.js
 5│  me\content.js                             ┊┈┈content.js
 6│  me\lib                                    ┊┈┈lib
 7│  me\lib\jquery.min.js                      ┊    ┊┈┈jquery.min.js
 8│  me\manifest.json                          ┊┈┈manifest.json
 9│  me\popup.html                             ┊┈┈popup.html
10│  me\popup.js                               ┊┈┈popup.js

manifest.json

这个文件类似于前端项目中的package.json ,但是地位却比package.json文件高很多。

manifest.json 文件用来告诉chrome显示什么样的图标,在那些页面嵌入那些对应的js文件。

插件的名字,插件的图标,manifest_version should always be 2, because version 1 is unsupported as of January 2014。

{
  "manifest_version": 2, # 只能是2, 1 已经不支持了
  "name": "My Cool Extension", # 鼠标放到图标上显示
  "version": "0.1",
  "background": {    #处理浏览器级别的事件
    "scripts": ["background.js"]
  },
  "content_scripts": [
    {
      "matches": [
        "<all_urls>" 
      ],
      "js": ["jquery-2.1.3.min.js", "content.js"]
    }
  ],
  "browser_action": {
    "default_icon": "icon.png" # 必须是png图片,19x19 即可,大图片会缩放
  },
  "permissions": [
	  "activeTab",// granted permissions according to the activeTab specification.
	  "tabs",//Gives your extension access to privileged fields of the Tab objects 
	  "storage",
	  "notifications", //Gives your extension access to the chrome.notifications API.
	  "background",
	  "nativeMessaging" //Gives your extension access to the native messaging API.
   ]  
}

<all_urls> tells Chrome to inject content.js into every page we visit.

如果不想每一个访问的页面都可以和 content scripts 交互,可以写一个列表,列出那些允许和content script交互

content.js

"a JavaScript file that runs in the context of web pages.” This means that a content.js can interact with web pages that the browser visits.

“browser_action”

When an extension adds a little icon next to your address bar, that’s a browser action. Your extension can listen for clicks on that button and then do something.

A content script has access to the current page, but is limited in the APIs it can access. For example, it cannot listen for clicks on the browser action. We need to add a different type of script to our extension, a background script, which has access to every Chrome API but cannot access the current page

browser action 浏览器级别的动作

content script 只能和指定的页面进行交互, 浏览器级别的 点击,语言切换,tab切换 要通过chrome API 才能交互,这就用到了 background.js

permissions 允许你的chrome extension访问那些api,那些chrome资源

https://developer.chrome.com/extensions/declare_permissions

popup.html

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<script src="popup.js"></script>
	<title>Document</title>
</head>
<body>
    <h1>我想看看</h1>
    <button id="checkPage">change the background color</button>
    <button id="opennew">open a new tab</button>
</body>
</html>

popup 和 content script的通信 可以通过 chrome.tabs.sendMessage

popup.js

document.addEventListener('DOMContentLoaded', function() {
  var checkPageButton = document.getElementById('checkPage');
	
	//点击之后,页面背景变红色
  checkPageButton.addEventListener('click', function() {
	  document.body.setAttribute("style","background-color:red;");//popup.html背景色变为红色
	  	//想当前正活跃的tab页面发送 消息 changeBGC2red
		chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {// 发送信息到 active: true 当前正活跃的tab窗口
			chrome.tabs.sendMessage(tabs[0].id, {type:"changeBGC2red"}, function(response){

			});
		});
	  
  }, false);
	
	
	//建立Long Lived Connections
	var port = chrome.extension.connect({
		  name: "Sample Communication"
	 });	
	
	//点击之后,打开一个新窗口
	document.getElementById("opennew").addEventListener("click",function(){
		
		chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {// 发送信息到 active: true 当前正活跃的tab窗口
			//向background 发送消息,Using Long Lived Connections
			port.postMessage("meme");
		});
		
	});
	
	
	 //接收 background 返回的消息  回话的消息
	 port.onMessage.addListener(function(msg) {
		  console.log("message recieved" + msg);
	 });
	
	
	
	
}, false);

content.js

chrome.runtime.onMessage.addListener(
 function(request, sender,sendResponse) {
	if(request.type == "changeBGC2red"){
		document.body.setAttribute("style","background-color:red");
	}else if( request.type == "open_new_tab" ) {
      chrome.tabs.create({"url": "http://www.hao123.com"});
    }
});

popup 和background 之间的消息可以通过 Long Lived Connections

popup.js

	//建立Long Lived Connections
	var port = chrome.extension.connect({
		  name: "Sample Communication"
	 });	
	
	//点击之后,打开一个新窗口
	document.getElementById("opennew").addEventListener("click",function(){
		
		chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {// 发送信息到 active: true 当前正活跃的tab窗口
			//向background 发送消息,Using Long Lived Connections
			port.postMessage("meme");
		});
		
	});
	
	
	 //接收 background 返回的消息  回话的消息
	 port.onMessage.addListener(function(msg) {
		  console.log("message recieved" + msg);
	 });

background.js

//Using Long Lived Connections   接收来自 popup的消息
chrome.extension.onConnect.addListener(function(port) {
      port.onMessage.addListener(function(msg) {
           if(msg == "meme"){
			  chrome.tabs.create({"url": "http://www.hao123.com"}); //打开一个新的tab页面
		   }
      });
 })

注意:

content script 是注入到页面的context中的,它不能和extension的其他部分进行通信。比如popup的点击动作想要触发当前活动页面(current active tab)DOM发生改变,popup和浏览器的通信。这些就需要借助message passing 机制进行交流了。 具体可以参看下面:

https://developer.chrome.com/extensions/messaging#native-messaging

Communication between extensions and their content scripts works by using message passing. Either side can listen for messages sent from the other end, and respond on the same channel.

(1) one-time requests 对应的API runtime.sendMessage or tabs.sendMessage .

(1)这种通信机制仅仅用于解决,当你需要通知extension的其他部分一个信息(这个信息可以有返回,也可以不需要返回)。

e.g

//Sending a request from a 【content script】 to 【extension 】
chrome.runtime.sendMessage({greeting: "hello"}, function(response) {
  console.log(response.farewell);
});
//Sending a request from the 【extension】(selected tab) to a 【content script】
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
  chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function(response) {
    console.log(response.farewell);
  });
});

无论从那个part发出消息,接收端的写法类似,如下:

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

(2) long-lived connections 对应的API runtime.connect or tabs.connect

e.g

//open a channel from a content script, and send and listen for messages
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"});
});

接收端 。那部分都行,backgound ,popup

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

(3)sending messages between different components in your extension, you can use the messaging API to communicate with other extensions

runtime.onMessageExternal or runtime.onConnectExternal

最后为了开发的方便,chrome为extension提供了开发者模式

(1)地址栏输入 chrome://extensions/

(2) 点击“加载已解压的扩展程序”, 然后选择你的项目目录

(3) 修改之后的代码,需要在chrome://extensions/ ,刷新页面才会重新加载(CTRL + R)

(4)chrome 浏览器同时提供了打包扩展程序按钮,可以生成crx文件。

⚠️ **GitHub.com Fallback** ⚠️