chrome 插件开发

教程:

  1. https://segmentfault.com/a/1190000006949838
  2. https://segmentfault.com/a/1190000005071240
  3. https://blog.csdn.net/austin_link?t=1
  4. https://crxdoc-zh.appspot.com/extensions/getstarted (官方文档中文)
  5. https://www.cnblogs.com/liuxianan/p/chrome-plugin-develop.html#%E6%A0%B8%E5%BF%83%E4%BB%8B%E7%BB%8D,这个写的非常详细认真
  6. http://www.cnblogs.com/champagne/p/, 这个是系列教程

一 注意点

  1. chrome 不允许扩展中的HTML页面直接嵌入 js脚本,所有的脚本必须作为外部src引入。
  2. manifest.json 是一个非常重要的配置文件,常用的配置项必须要了解。
  3. background.js / content-script.js , 这些文件名字不能改了,改了之后调用 chrome 开头的一些 api 就会报 null 的错误。

二 配置 manifest.json

 "browser_action": { 
//插件加载后生成图标
        "default_icon": "cc.gif",
// 鼠标悬浮到图表上显示的文字
        "default_title": "Hello CC", 
// 点击图标展示的 html 页面
        "default_popup": "popup.html" 
}, 
// 运行插件需要的权限
    "permissions": [ 
        //指定插件生效的 Url 模式
        "http://*/", 
        "bookmarks", 
        "tabs", 
        "history" 
    ], 
// 插件运行的后台环境
    "background":{//background script即插件运行的环境
// 2 种方式
        "page":"background.html"
        // "scripts": ["js/jquery-1.9.1.min.js","js/background.js"]//数组.chrome会在扩展启动时自动创建一个包含所有指定脚本的页面
    }, 
// document 插件向页面注入的 js/css 脚本.可以实现广告屏蔽、页面 css 定制
     "content_scripts": [{  
  //满足什么条件的 url 执行该插件
         "matches": ["http://*/*","https://*/*"],   
// 注入js脚本
         "js": ["js/jquery-1.9.1.min.js", "js/js.js"],   
// 注入css
"css": ["css/custom.css"],
//插件执行的时间,"document_start","document_end",
// "document_idle",表示页面空闲时
         "run_at": "document_start",  
    }] 
  • 与 browser_action 对应的还有一个 page_action,browser_action 对所有的页面生效,而 page_action 只针对特定的页面生效,page_action 与 browser_action 只能存在一个。
  • "manifest_version": 2,因为一些乱七八糟的原因,这个值必须是2.
  • popup是点击browser_action或者page_action图标时打开的一个小窗口网页,焦点离开网页就立即关闭,一般用来做一些临时性的交互。需要特别注意的是,由于单击图标打开popup,焦点离开又立即关闭,所以popup页面的生命周期一般很短,需要长时间运行的代码千万不要写在popup里面。
    在权限上,它和background非常类似,它们之间最大的不同是生命周期的不同,popup中可以直接通过chrome.extension.getBackgroundPage()获取background的window对象。

background

background.后台(姑且这么翻译吧),是一个常驻的页面,它的生命周期是插件中所有类型页面中最长的,它随着浏览器的打开而打开,随着浏览器的关闭而关闭,所以通常把需要一直运行的、启动就运行的、全局的代码放在background里面.

background的权限非常高,几乎可以调用所有的Chrome扩展API(除了devtools),而且它可以无限制跨域,也就是可以跨域访问任何网站而无需要求对方设置CORS。

配置中,background可以通过page指定一张网页,也可以通过scripts直接指定一个JS,Chrome会自动为这个JS生成一个默认的网页

三 调试

扩展程序 -> 加载已解压的扩展程序
如果修改了扩展源文件,有的时候更新一下可以生效,有的时候需要把插件删除,重装一下。

四 content_scripts,注入 JS 和 CSS

在 content_scripts 配置的文件 js 文件中,可以直接操作dom,如果写了啥 chrome.tabs 之类的会显示无效 ....

content_scripts和原始页面共享DOM,但是不共享JS,如要访问页面JS(例如某个JS变量),只能通过injected js来实现。content-scripts不能访问绝大部分chrome.xxx.api,除了下面这4种:

chrome.extension(getURL , inIncognitoContext , lastError , onRequest , sendRequest)
chrome.i18n
chrome.runtime(connect , getManifest , getURL , id , onConnect , onMessage , sendMessage)
chrome.storage

其实看到这里不要悲观,这些API绝大部分时候都够用了,非要调用其它API的话,你还可以通过通信来实现让background来帮你调用(关于通信,后文有详细介绍)。

五 五种类型的 JS 对比

chrome 插件的 JS 主要可以分为这 5 类,injected script, content-script, popup js, background.jsdevtools.js

5.1 权限对比

js 种类 可访问的 API DOM访问情况 JS访问情况 直接访问
injected js 和普通的JS无任何差别,不能访问任何扩展API 可以访问 可以访问 不可以
content script 只能访问 extension/ runtime 等部分 API 可以访问 不可以 不可以
popup js 可以访问绝大部分 API,除了 devtools 不可以直接访问 不可以 可以
backgroundjs 可以访问绝大部分 API,除了 devtools 不可以直接访问 不可以 可以
devtools js 只能访问 devtools/ extension/ runtime 等部分 API 可以 可以 不可以

六 消息通信

Chrome 插件中存在 5 种js,那么它们之间如何通信呢?popup 和 background 其实几乎可以视为同一种东西,因为它们可访问的 API 的 一样、通信机制都一样、都可以跨域。

6.1 互相通信概览

injected-script content-script popup-js background-js
injected-script -- window.postMessage -- --
content-script window.postMessage -- chrome.runtime.sendMessage chrome.runtime.connect chrome.runtime.sendMessage chrome.runtime.connect
popup-js -- chrome.tabs.sendMessage chrome.tabs.connect -- chrome.extension.getBackgroundPage
background-js -- chrome.tabs.sendMessage chrome.tabs.connect chrome.extension.getViews --
devtools-js chrome.devtools.inspectedWindow.eval -- chrome.runtime.sendMessage chrome.runtime.sendMessage

6.2 通信详细介绍

6.2.1 popup 和 background

popup 可以直接调用 background 中的 js 方法,也可以直接访问 background 的 DOM:

// background.js
function test(){
  alert('我是 background');
}

// popup.js
let bg = chrome.extension.getBackgroundPage();
// 访问bg 的函数
bg.test();
// 访问 bg 的 DOM
alert(bg.document.body.innerHTML);

background 访问 popup, 需要 popup 已经打开:

let views = chrome.extension.getViews({type:'popup'});
if(views.length > 0){
  console.log(views[0].location.href);
}

6.2.2 popup 和 background 向 content 主动发送消息

backgroud.js 或者 popup.js

function sendMessageToContentScript(message,callback){
  chrome.tabs.query({active:true, currentWindow: true}, function(tabs){
    chrome.tabs.sendMessage(tabs[0].id, message, function(response){
      if(callback){
        callback(response)
    }
})
})
}

// 调用
sendMessageToContentScript({cmd:'test', value:'nihao'},function(response){
  console.log("来自 content 的回复:" + response);
})

content-script.js 接受消息:

chrome.runtime.onMessage.addListener((request,sender,sendResponse){
  if (request.cmd === "test"){
      alert(request.value);
    }
  sendResponse("我收到了你的消息");
})

6.2.3 content-script 主动发消息给后台

content-script.js

chrome.runtime.sendMessage({greeting: '你好,我主动发消息'},(response)=>{
  console.log("收到来自后台的回复"+ response);
})

background.js 或 popup.js

// 监听来自 content-script 的消息
chrome.runtime.onMessage.addListener((request, sender, sendResponse)=>{
  console.log(request, sender, sendResponse);
  sendResponse('我是后台' + JSON.stringify(request));
})

参数说明:

  • request 是接受的数据
  • sender 是一个对象,包含了许多关于发出者的信息:
    • tab,关于 tab 的一些信息。
    • frameId
    • id , 猜测是唯一标识符
    • url,发送者的url。
  • sendResponse, 是个回调函数而已。

注意事项:

  • content_scripts向popup主动发消息的前提是popup必须打开!否则需要利用background作中转;
  • 如果background和popup同时监听,那么它们都可以同时收到消息,但是只有一个可以sendResponse,一个先发送了,那么另外一个再发送就无效;

6.2.4 injected script 和 content-script

content-script 和 页面内的脚本(injected-script 自然也属于页面内的脚本)之间唯一共享的东西就是 页面 的 DOM元素。
injected-script:

window.postMessgae({"test":"nihao"},"*")

content script:

window.addEventListener("message",(e)=>{
  console.log(e.data);
})

6.3 长连接

Chrome插件中有2种通信方式,一个是短连接(chrome.tabs.sendMessage和chrome.runtime.sendMessage),一个是长连接(chrome.tabs.connect和chrome.runtime.connect)。

短连接的话就是挤牙膏一样,我发送一下,你收到了再回复一下,如果对方不回复,你只能重新发,而长连接类似WebSocket会一直建立连接,双方可以随时互发消息。
popup.js:

getCurrentTabId((tabId) => {
    var port = chrome.tabs.connect(tabId, {name: 'test-connect'});
    port.postMessage({question: '你是谁啊?'});
    port.onMessage.addListener(function(msg) {
        alert('收到消息:'+msg.answer);
        if(msg.answer && msg.answer.startsWith('我是'))
        {
            port.postMessage({question: '哦,原来是你啊!'});
        }
    });
});

content-script.js:

// 监听长连接
chrome.runtime.onConnect.addListener(function(port) {
    console.log(port);
    if(port.name == 'test-connect') {
        port.onMessage.addListener(function(msg) {
            console.log('收到长连接消息:', msg);
            if(msg.question == '你是谁啊?') port.postMessage({answer: '我是你爸!'});
        });
    }
});
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,607评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,239评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,960评论 0 355
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,750评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,764评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,604评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,347评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,253评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,702评论 1 315
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,893评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,015评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,734评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,352评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,934评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,052评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,216评论 3 371
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,969评论 2 355