美文网首页
Chrome扩展插件开发

Chrome扩展插件开发

作者: overflow_hidden | 来源:发表于2017-12-26 10:09 被阅读1119次
    1. 简介

    Chrome插件是一个用Web技术开发、用来增强浏览器功能的软件,Chrome浏览器扩展开发算是相当简单的,基本只要掌握HTML+CSS+Javascript,即可快速开发一个属于你的Chrome插件!它其实就是一个由HTML、CSS、JS、图片等资源组成的一个.crx后缀的压缩包.

    2. 学习Chrome插件开发有什么意义?

    增强浏览器功能,轻松实现属于自己的“定制版”浏览器,等等。
    Chrome插件提供了很多实用API供我们使用,包括但不限于:

    • 书签控制;
    • 下载控制;
    • 窗口控制;
    • 标签控制;
    • 网络请求控制,
    • 各类事件监听;
    • 自定义原生菜单;
    • 完善的通信机制;
      等等;
    4. 开发与调试

    Chrome插件没有严格的项目结构要求,只要保证本目录有一个manifest.json即可,普通的web开发工具即可。
    从右上角菜单->更多工具->扩展程序可以进入 插件管理页面,也可以直接在地址栏输入 chrome://extensions 访问。

    5. 核心介绍

    manifest.json是一个Chrome插件最重要也是必不可少的文件,用来配置所有和插件相关的配置,必须放在根目录。

    下面给出的是一些常见的配置项,均有中文注释,完整的配置文档请戳 这里

    {
     //必选
     /*
       指定您的应用包要求的清单文件格式的版本。从 Chrome 18 开始,开发人员应该指定 2
     */
     "manifest_version": 2,
     "name":"我的应用名称",
     "version":"我的应用版本",
    
     //推荐
     /*
       清单文件-默认语言 指定_locales中的子目录,包含该应用默认字符串。
       对于含有 _locales 目录的应用来说这一属性是必需的,
       在没有 _locales 目录的应用中该属性不能存在
     */
     "default_locale":"en", 
    
     /*
       这个描述在安装应用之后可以看见
     */
     "description":"关于应用的描述", 
    
     /*一个或多个代表应用、应用或主题背景的图标*/
     "icons":{
       "16":"icon16.png",
       "48":"icon48.png"
     },
    
     /*
      选择某一个(或者无)
      browser_action(浏览器按钮)
      page_action(页面按钮)
     */
    
     // 如果有 browser_action, 即在 chrome toolbar 的右边添加了一个 icon
     "browser_action": {
       "default_icon": "advicedog.jpg",
       "default_title": "Google Mail",      // tooltip, 光标停留在 icon 上时显示
       "default_popup": "popup.html"  // 如果有 popup 的页面, 则用户点击图标就会渲染此 HTML 页面
     },
    
    
     // 如果并不是对每个网站页面都需要使用插件, 可以使用 page_action(页面按钮) 而不是 browser_action(浏览器按钮)
     // browser_action 应用更加广泛
     // 如果 page_action 并不应用在当前页面, 会显示灰色
    
     "page_action":{
       "default_icon": {                    // 可选
         "19": "images/icon19.png",           // 可选
         "38": "images/icon38.png"            // 可选
       },
       "default_title": "Google Mail",      // 可选,在工具提示中显示
       "default_popup": "popup.html"        // 可选
     },
    
     //可选
     "author":"开发者",
     "automation":"",
    
    
     /*
     后台网页
     1.应用通常需要有一个长时间运行的脚本来管理一些任务或状态,而后台网页就是为这一目的而设立。
     通常情况下,后台页面不需要任何 HTML 标记,这种情况下后台页面可以单独使用 JavaScript文件实现。
     后台页面将由应用系统生成,包含 scripts 属性中列出的每一个文件。
    
     2.page:如果您需要在您的后台页面中指定 HTML,您可以改用 page 属性:
    
     3.persistent:应用和应用通常需要长时间运行的脚本来管理某些任务或状态,这就是事件页面的作用。
     事件页面只在需要时加载,当事件页面不活动时就会卸载,以便释放内存和其他系统资源。
     如何得到事件页面 就是设置一个"persistent"键,如果没有设置,你将得到一个普通的后台页面。
     */
     "background":{
       "scripts":["background.js"],
       "page": "background.html",
       "persistent":false
     },
    
    
     /*
       内容脚本:其实就是向你想要的网页中插入一个脚本代码,执行你想要做的事情
       内容脚本是在网页的上下文中运行的 JavaScript 文件,
       它们可以通过标准的文档对象模型(DOM)来获取浏览器访问的网页详情,或者作出更改。
       
       1.run_at 可选。
       控制 js 中的 JavaScript 文件何时插入,
       可以为 "document_start"、
       "document_end" 或 "document_idle",默认为 "document_idle"。 
    
    
       1.1如果是 "document_start",这些文件将在 css 中指定的文件之后,但是在所有其他 DOM 构造或脚本运行之前插入。 
    
       1.2.如果是 "document_end",文件将在 DOM 完成之后立即插入,但是在加载子资源(如图像与框架)之前插入。 
    
       1.3.如果是 "document_idle",浏览器将在 "document_end" 和刚发生 window.onload 事件这两个时刻之间选择合适的时候插入,
       具体的插入时间取决于文档的复杂程度以及加载文档所花的时间,并且浏览器会尽可能地为加快页面加载速度而优化。 
     
       2.all_frames 可选。
       控制内容脚本运行在匹配页面的所有框架中还是仅在顶层框架中。 默认为 false,意味着仅在顶层框架中运行
       
       content_scripts还有一些其他不是很常用的属性
     */
    
     "content_scripts": [{
       "matches": ["https://*.pingan.com.cn/*"], //匹配的地址网页
       "exclude_matches":[],
       "js": ["jquery.js","ideacome.js"], //插入的js
       "css": ["mystyles.css"], //css改变样式
       "run_at":"document_idle",
       "all_frames": true //该匹配下面的所有窗口
     },{
       "matches": ["*://*/*.png", "*://*/*.jpg", "*://*/*.gif", "*://*/*.bmp"],
       "js": ["js/show-image-content-size.js"] //可以针对不同的规则插入不同的内容
     }],
    
    // 普通页面能够直接访问的插件资源列表,如果不设置是无法直接访问的
    "web_accessible_resources": [
       "images/*.png",
       "style/double-rainbow.css",
       "script/double-rainbow.js",
       "script/main.js",
       "templates/*"
     ],
    
    /**
      如果不是通过 chrome web store 自动更新插件
    
       我们希望扩展能自动升级,理由和让chrome自动升级一样:修改程序bug和安全漏洞 ,增加新功能,提升性能,改善体验。
       一个扩展的manifest文件里面必须指定一个"update_url"来执行升级检测。
    
       扩展可以托管在Chrome Web Store,也可以发布到极速浏览器应用开放平台上。
       如果托管在Chrome Web Store则update_url应该是:http://clients2.google.com/service/update2/crx    
     **/
     "update_url": "https://clients2.google.com/service/update2/crx",
    
    // 插件主页,这个很重要,不要浪费了这个免费广告位
    "homepage_url": "https://www.baidu.com",
    
    /*  
       扩展或app将使用的一组权限。每个权限是一列已知字符串列表中的一个,
       如geolocatioin或者一个匹配模式,来指定可以访问的一个或者多个主机。
       权限可以帮助限定危险,如果你的扩展或者app被攻击。
       一些权限在安装之前,会告知用户
     */
     "permissions":[
       "tabs", //Required if the extension uses the chrome.tabs or chrome.windows module.
       "bookmarks", //使用chrome.bookmarks模块来创建、组织和管理书签
       "http://www.blogger.com/",    
       "http://*.google.com/",    
       "unlimitedStorage", //提供了一个无限的HTML5配额来存储客户端数据,如数据库和本地存储文件。没有这个权限,扩展仅限于5 MB的本地存储
       "history" //历史记录的使用权限  chrome.history 
       "notifications",//提示
       "cookies",//Required if the extension uses the chrome.cookies module.
     ],
    
    /**开发时为扩展指定的唯一标识值。
    注意:通常您并不需要直接使用这个值,而是在您的代码中使用相对路径或者chrome.extension.getURL()得到的绝对路径。
    这个值并不是开发时显式指定的,而是Chrome在安装.crx时辅助生成的。(开发时可以通过上传扩展或者手工打包生成crx文件)。 安装完crx,在Chrome的用户数据目录下的Default/Extensions/<extensionId>/<versionString>/manifest.json文件中,您可以看到这个扩展的key。**/
    
    key:'',
    
    "commands": {
         // commands API 用来添加快捷键
         // 需要在 background page 上添加监听器绑定 handler
       "toggle-feature-foo": {
         "suggested_key": {
           "default": "Ctrl+Shift+Y",
           "mac": "Command+Shift+Y"
         },
         "description": "Toggle feature foo",
         "global": true
           // 当 chrome 没有 focus 时也可以生效的快捷键
           // 仅限 Ctrl+Shift+[0..9]
       },
       "_execute_browser_action": {
         "suggested_key": {
           "windows": "Ctrl+Shift+Y",
           "mac": "Command+Shift+Y",
           "chromeos": "Ctrl+Shift+U",
           "linux": "Ctrl+Shift+J"
         }
       },
       "_execute_page_action": {
         "suggested_key": {
           "default": "Ctrl+Shift+E",
           "windows": "Alt+Shift+P",
           "mac": "Alt+Shift+P"
         }
       },
       ...
     },
     "content_capabilities": ...,
     "optional_permissions": ["tabs"], // 其他需要的 permission, 在使用 chrome.permissions API 时用到, 并非安装插件时需要
    
     "short_name": "Short Name", // 插件名字简写
    
    "storage": {
       "managed_schema": "schema.json"
     }, //  使用 storage.managed api 的话, 需要一个 schema 文件指定存储字段类型等, 类似定义数据库表的 column
    
    ......
    //还有很多其他的配置
    }
    
    5.1 content-scripts

    所谓content-scripts,其实就是Chrome插件中向页面注入脚本的一种形式(虽然名为script,其实还可以包括css的),借助content-scripts我们可以实现通过配置的方式轻松向指定页面注入JS和CSS,最常见的比如:广告屏蔽、页面CSS定制,等等。

    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来帮你调用。

    5.2 background

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

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

    经过测试,其实不止是background,所有的直接通过chrome-extension://id/xx.html这种方式打开的网页都可以无限制跨域。

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

    {
        // 会一直常驻的后台JS或后台页面
        "background":
        {
            // 2种指定方式,如果指定JS,那么会自动生成一个背景页
            "page": "background.html"
            //"scripts": ["js/background.js"]
        },
    }
    

    #######5.3 event-pages
    这里顺带介绍一下event-pages,它是一个什么东西呢?鉴于background生命周期太长,长时间挂载后台可能会影响性能,所以Google又弄一个event-pages,在配置文件上,它与background的唯一区别就是多了一个persistent参数:

    {
        "background":
        {
            "scripts": ["event-page.js"],
            "persistent": false
        },
    }
    

    它的生命周期是:在被需要时加载,在空闲时被关闭,什么叫被需要时呢?比如第一次安装、插件更新、有content-script向它发送消息,等等。

    5.4 popup

    popup是点击browser_action或者page_action图标时打开的一个小窗口网页,焦点离开网页就立即关闭,一般用来做一些临时性的交互。


    image.png

    popup可以包含任意你想要的HTML内容,并且会自适应大小。可以通过default_popup字段来指定popup页面,也可以调用setPopup()方法。

    需要特别注意的是,由于单击图标打开popup,焦点离开又立即关闭,所以popup页面的生命周期一般很短,需要长时间运行的代码千万不要写在popup里面。

    在权限上,它和background非常类似,它们之间最大的不同是生命周期的不同,popup中可以直接通过chrome.extension.getBackgroundPage()获取background的window对象。

    5.5 homepage_url

    开发者或者插件主页设置


    image.png
    5.6 injected-script

    指的是通过DOM操作的方式向页面注入的一种JS。为什么需要通过这种方式注入JS呢?

    这是因为content-script有一个很大的“缺陷”,也就是无法访问页面中的JS,虽然它可以操作DOM,但是DOM却不能调用它,也就是无法在DOM中通过绑定事件的方式调用content-script中的代码(包括直接写onclick和addEventListener2种方式都不行),但是,“在页面上添加一个按钮并调用插件的扩展API”是一个很常见的需求,那该怎么办呢?其实这就是本小节要讲的。

    在content-script中通过DOM方式向页面注入inject-script代码示例:

    // 向页面注入JS
    function injectCustomJs(jsPath)
    {
        jsPath = jsPath || 'js/inject.js';
        var temp = document.createElement('script');
        temp.setAttribute('type', 'text/javascript');
        // 获得的地址类似:chrome-extension://ihcokhadfjfchaeagdoclpnjdiokfakg/js/inject.js
        temp.src = chrome.extension.getURL(jsPath);
        temp.onload = function()
        {
            // 放在页面不好看,执行完后移除掉
            this.parentNode.removeChild(this);
        };
        document.head.appendChild(temp);
    }
    
    manifest.json
    {
        // 普通页面能够直接访问的插件资源列表,如果不设置是无法直接访问的
        "web_accessible_resources": ["js/inject.js"],
    }
    

    6. Chrome插件的7种展示形式

    6.1 browserAction(浏览器右上角)

    通过配置browser_action可以在浏览器的右上角增加一个图标,一个browser_action可以拥有一个图标,一个tooltip(即划过显示title),一个badge(图标上面的文字,有字数限制)和一个popup。


    tooltip,badge,popup
    6.2 pageAction(地址栏右侧)

    pageAction和普通的browserAction一样也是放在浏览器右上角,也可以说地址栏的右侧更为准确。只不过没有点亮时是灰色的,点亮了才是彩色的,灰色时无论左键还是右键单击都是弹出选项:

    // manifest.json
    {
      "name": "测试",
      "description": "........",
      "version": "1.0",
      "permissions": [
        "declarativeContent"
      ],
      "background":{
        "scripts":["background.js"]
      },  
      "page_action": {
        "default_icon": "icon.png",
        "default_title": "我是pageAction",
        "default_popup": "popup.html"
      },
      "manifest_version": 2
    }
    
    
    // background.js
    chrome.runtime.onInstalled.addListener(function(){
        chrome.declarativeContent.onPageChanged.removeRules(undefined, function(){
            chrome.declarativeContent.onPageChanged.addRules([
                {
                    conditions: [
                        // 只有打开百度才显示pageAction
                        new chrome.declarativeContent.PageStateMatcher({pageUrl: {urlContains: 'baidu.com'}})
                    ],
                    actions: [new chrome.declarativeContent.ShowPageAction()]
                }
            ]);
        });
    });
    
    6.3 右键菜单(api地址

    通过开发Chrome插件可以自定义浏览器的右键菜单,主要是通过chrome.contextMenusAPI实现,右键菜单可以出现在不同的上下文,比如普通页面、选中的文字、图片、链接,等等

    //manifest.json
      "permissions": [
        "declarativeContent",
        "contextMenus",
        "tabs"
      ],
      "background":{
        "scripts":["background.js"]
      },  
    
    //background.js
    //可以右键看看
    chrome.contextMenus.create({
        title: "测试右键菜单",
        onclick: function(){alert('您点击了右键菜单!');}
    });
    
    //选择某些文字才出现这个右键菜单
    chrome.contextMenus.create({
        title: '使用度娘搜索:%s', // %s表示选中的文字
        contexts: ['selection'], // 只有当选中文字时才会出现此右键菜单
        onclick: function(params)
        {
            // 注意不能使用location.href,因为location是属于background的window对象
            chrome.tabs.create({url: 'https://www.baidu.com/s?ie=utf-8&wd=' + encodeURI(params.selectionText)});
        }
    });
    
    6.3.2 右键菜单一些基本的api
    hrome.contextMenus.create({
        type: 'normal', // 类型,可选:["normal", "checkbox", "radio", "separator"],默认 normal
        title: '菜单的名字', // 显示的文字,除非为“separator”类型否则此参数必需,如果类型为“selection”,可以使用%s显示选定的文本
        contexts: ['page'], // 上下文环境,可选:["all", "page", "frame", "selection", "link", "editable", "image", "video", "audio"],默认page
        onclick: function(){}, // 单击时触发的方法
        parentId: 1, // 右键菜单项的父菜单项ID。指定父菜单项将会使此菜单项成为父菜单项的子菜单
        documentUrlPatterns: 'https://*.baidu.com/*' // 只在某些页面显示此右键菜单
    });
    // 删除某一个菜单项
    chrome.contextMenus.remove(menuItemId);
    // 删除所有自定义右键菜单
    chrome.contextMenus.removeAll();
    // 更新某一个菜单项
    chrome.contextMenus.update(menuItemId, updateProperties);
    
    6.4. override(覆盖特定页面)

    使用override页可以将Chrome默认的一些特定页面替换掉,改为使用扩展提供的页面。

    //一个扩展只能替代一个页面;
    "chrome_url_overrides":
      {
          "newtab": "newtab.html"
           "history": "history.html",
          "bookmarks": "bookmarks.html"
      }
    
    6.5 option(选项页)

    为了让用户自定义您的应用的行为,您可能会提供一个选项页面。

    所谓选项(options)页,就是插件的设置页面,有2个入口,一个是右键图标有一个“选项”菜单,还有一个在插件管理页面:


    image.png
    //manifest.json
    
    //Chrome40以前的插件配置页写法
    "options_page":"xx.html",
    
    //Chrome40以后的插件配置页写法,只是样式不一样了,以弹出框的形式显示
    "options_ui":
      {
          "page": "options.html",
          // 添加一些默认的样式,推荐使用
          "chrome_style": true
     },
    //为了兼容,建议2种都写,如果都写了,Chrome40以后会默认读取新版的方式;
    
    Chrome40以后的插件配置页写法

    页面内容看你自己发挥了。这边有一个示例可以看看

    6.6 omnibox

    omnibox是向用户提供搜索建议的一种方式。具体看api

    6.7 桌面通知

    Chrome提供了一个chrome.notificationsAPI以便插件推送桌面通知,暂未找到chrome.notifications和HTML5自带的Notification的显著区别及优势。

    在后台JS中,无论是使用chrome.notifications还是Notification都不需要申请权限(HTML5方式需要申请权限),直接使用即可。

    "permissions": [
        "notifications"
      ],
    
    chrome.contextMenus.create({
        title: "测试右键菜单",
        onclick: function(){
          chrome.notifications.create(null, {
              type: 'basic',
              iconUrl: 'icon.png',
              title: '这是标题',
              message: '您刚才点击了自定义右键菜单!'
          });
        }
    });
    
    image.png
    实战1:(platform项目险企报价)

    为了实现险企账号的管理,使得出单人员在各个险企报价时,不需要自己记录管理险企的登录地址,以后手动输入账号密码。
    或者在报价页面插入一些已知的报价填写信息。

    文件目录

    项目文件目录
    • manifest.json 清单文件
      具体配置:
    image.png
    • popup.html :根据上面的描述我们知道,这是点击浏览器按钮会弹出显示。
    • icon.png :browser_action里面配置的icon显示图标
    • ideacome.js: 除了本脚本之外,其他的脚本都是依赖。
      在这个脚本里面我们可以访问其插入的页面的dom元素,cookie,localStorage,发送ajax请求等等操作。来完成我们想要的效果。

    完成上面的工作,我们如何使自己的代码转换成一个可在ChromeL浏览器里面安装扩展程序呢?

    接下来我们需要对我们编写的文件进行打包。应用打包为已签名的 ZIP 文件,文件扩展名为“crx”,如:myextension.crx。

    当您为应用打包时,应用将获得唯一的密钥对,应用的标识符基于公钥的散列,私有密钥用来为每一个版本的应用签名,必须严格保护,不能由公众访问。注意千万不要将您的私有密钥包含在应用中!

    打包步骤:

    • 进入以下URL,打开应用管理页面:
      chrome://extensions
    • 确保右上角的开发者模式复选框已选中。
    • 单击打包应用按钮,出现一个对话框。
    • 在应用根目录字段中,指定应用所在文件夹的路径,例如,C:\myext。(忽略其他字段,您第一次为一个应用打包时不需要指定私有密钥文件。)
    • 单击打包应用。打包程序将创建两个文件:一个 .crx 文件,是实际的可安装的应用;另一个是 .pem 文件,包含私有密钥。

    安装图片:

    确保已经勾选开发者模式 打开扩展页面 将.crx文件拖入扩展页面 点击添加扩展程序即可

    不要丢失私有密钥!确保 .pem 文件保密,并存放在安全的地方。如果您今后需要做如下事情,您需要这一文件:

    • 更新应用: 更新应用与安装步骤一样。不同的是此时密钥已经存在。

    学习参考文件

    1. https://chajian.baidu.com/developer/extensions/api_index.html

    2. http://open.chrome.360.cn/extension_dev/samples.html#a1f7cf79dd555b04fa8d603247a040e644996293

    3. https://developer.chrome.com/extensions/runtime

    相关文章

      网友评论

          本文标题:Chrome扩展插件开发

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