美文网首页
chrome 插件开发

chrome 插件开发

作者: 智勇双全的小六 | 来源:发表于2018-07-12 11:38 被阅读0次

    教程:

    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: '我是你爸!'});
            });
        }
    });
    

    相关文章

      网友评论

          本文标题:chrome 插件开发

          本文链接:https://www.haomeiwen.com/subject/dcvhpftx.html