zoukankan      html  css  js  c++  java
  • ChromeExtension那些事儿

    Chrome Extension是什么呢?

    简而言之,就是Chrome扩展,它是基于Chrome浏览器的,我们可以理解它为一个独立运行在Chrome浏览器下的APP,当然核心编程语言就是JavaScript咯,然后结合HTML以及CSS来开发。重点是,这个“APP”功能强大,可以独自运行,亦可以与打开的网页、Chrome控制面板(DevTools)、第三方插件等等进行通信,且,Google允许ChromeExtension不必受限于跨域限制,结合以上种种优点,固,我们可以使用ChromeExtension,结合自身业务,开发出许多提高工作效率的工具。

    部署ChromeExtension也很简单,如下:

    好了,现在来听听属于ChromeExtension它的故事。

    一、概要及manifest.json

    ChromeExtension是Chrome提出来的一个概念,其实正如上文所说,核心编程语言就是JavaScript,然后提供一切通信、存储接口,大致就差不多了。

    需要注意的是,ChromeExtension都包含一个Manifest文件——manifest.json,这个文件可以告诉Chrome关于这个扩展的相关信息,它是整个扩展的入口,也是Chrome扩展必不可少的部分。且必须包含name、version和manifest_version属性,其他常用的可选属性还有browser_action、page_action、background、permissions、options_page、content_scripts。

    所以我们可以保留一份manifest.json模板,当编写新的扩展时直接填入相应的属性值就OK了。

    manifest.json模板及相关属性解释如下:

    {
        "manifest_version": 2,
        //定义chrome扩展的名称
        "name": "My Extension",
        //定义chrome扩展的版本
        "version": "versionString",
        "default_locale": "en",
        //定义chrome扩展的描述
        "description": "A plain text description",
        //定义了扩展相关图标文件的位置
        "icons": {
            "16": "images/icon16.png",
            "48": "images/icon48.png",
            "128": "images/icon128.png"
        },
        /*
          Browser Actions将扩展图标置于Chrome浏览器工具栏中,地址栏的右侧。如果声明了popup页面,当用户点击图标时,在图标的下侧会打开这个页面。同时图标上面还可以附带badge——一个带有显示有限字符空间(只能显示4字节长度信息)的区域——用以显示一些有用的信息,如未读邮件数等。且Badge目前只能够通过JavaScript设定显示的内容,同时Chrome还提供了更改badge背景的方法。如果不定义badge的背景颜色,默认将使用红色。例如,显示了一个背景颜色为蓝色,内容为“Dog”的badge:
          chrome.browserAction.setBadgeBackgroundColor({color: '#0000FF'});
          chrome.browserAction.setBadgeText({text: 'Dog'});
        */
        "browser_action": {
            //通过setIcon方法可以动态更改扩展的图标,chrome.browserAction.setIcon(details, callback)
            "default_icon": {
                "19": "images/icon19.png",
                "38": "images/icon38.png"
            },
            //定义了当用户鼠标悬停于扩展图标上所显示的文字,chrome.browserAction.setTitle({title: 'This is a new title'})
            "default_title": "Extension Title",
            /*
              定义了当用户单击扩展图标时所显示页面的文件位置, 值得注意的是Chrome不允许将JavaScript代码段直接内嵌入HTML文档,所以我们需要通过外部引入的方式引用JS文件。由于其在关闭后,就相当于用户关闭了相应的标签页,这个页面不会继续运行。当用户再次打开这个页面时,所有的DOM和js空间变量都将被重新创建,所以不要在popup页面的js空间变量中保存数据,而是利用localStorage和chrome.storage将数据保存在用户的硬盘上。
            */
            "default_popup": "popup.html"
        },
        /*
          Page Actions与Browser Actions非常类似,除了Page Actions没有badge外,其他Browser Actions所有的方法Page Actions都有。另外的区别就是,Page Actions并不像Browser Actions那样一直显示图标,而是可以在特定标签特定情况下显示或隐藏,所以它还具有独有的show和hide方法。
            chrome.pageAction.show(integer tabId);
            chrome.pageAction.hide(integer tabId);
            另,tabId为标签(下面会具体讲解)id,可以通过tabs接口获取。
        */
        "page_action": {
            "default_icon": {
                "19": "images/icon19.png",
                "38": "images/icon38.png"
            },
            "default_title": "Extension Title",
            "default_popup": "popup.html"
        },
        /*
          在Manifest中指定background域可以使扩展常驻后台。background可以包含三种属性,分别是scripts、page和persistent。如果指定了scripts属性,则Chrome会在扩展启动时自动创建一个包含所有指定脚本的页面;如果指定了page属性,则Chrome会将指定的HTML文件作为后台页面运行。通常我们只需要使用scripts属性即可,除非在后台页面中需要构建特殊的HTML——但一般情况下后台页面的HTML我们是看不到的。persistent属性定义了常驻后台的方式——当其值为true时,表示扩展将一直在后台运行,无论其是否正在工作;当其值为false时,表示扩展在后台按需运行,这就是Chrome后来提出的Event Page。Event Page可以有效减小扩展对内存的消耗,如非必要,请将persistent设置为false。注意,persistent的默认值为true。
        */
        "background": {
            "scripts": ["background.js"]
        },
        /*
          可以指定将哪些脚本何时注入到哪些页面中,当用户访问这些页面后,相应脚本即可自动运行,从而对页面DOM进行操作。属性值为数组类型,数组的每个元素可以包含matches、exclude_matches、css、js、run_at、all_frames、include_globs和exclude_globs等属性其中matches属性定义了哪些页面会被注入脚本,exclude_matches则定义了哪些页面不会被注入脚本,css和js对应要注入的样式表和JavaScript,run_at定义了何时进行注入,all_frames定义脚本是否会注入到嵌入式框架中,include_globs和exclude_globs则是全局URL匹配,最终脚本是否会被注入由matches、exclude_matches、include_globs和exclude_globs的值共同决定.
    
        注意:content_scripts中的脚本只是共享页面的DOM(DOM中的自定义属性不会被共享),而并不共享页面内嵌JavaScript的命名空间。也就是说,如果当前页面中的JavaScript有一个全局变量a,content_scripts中注入的脚本也可以有一个全局变量a,两者不会相互干扰。当然你也无法通过content_scripts访问到页面本身内嵌JavaScript的变量和函数。
        */
        "content_scripts": [
            {
                "matches": ["http://www.google.com/*"],
                "css": ["mystyles.css"],
                "js": ["jquery.js", "myscript.js"]
            }
        ],
        /*
          有一些扩展允许用户进行个性化设置,这样就需要向用户提供一个选项页面。Chrome通过Manifest文件的options_page属性为开发者提供了这样的接口,可以为扩展指定一个选项页面。当用户在扩展图标上点击右键,选择菜单中的“选项”后,就会打开这个页面
        */
        "options_page": "options.html",
        /*
          浏览器出于安全考虑是不允许跨域, 但这个规则如果同样限制Chrome扩展应用,就会使其能力大打折扣,所以Google允许Chrome扩展应用不必受限于跨域限制。但出于安全考虑,需要在Manifest的permissions属性中声明需要跨域的权限。
        */
        "permissions": [
            "*://www.google.com/*"
        ],
        // 为notification服务,桌面通知功能
        "web_accessible_resources": [
            "images/*.png"
        ]
    }
    二、存储

    对于网站来说,用户的设置通常保存在Cookies中,或者保存在网站服务器的数据库中。对于JavaScript来说,一些数据可以保存在变量中。
    但,如果用户重新启动浏览器,这些数据就会消失。那么如何在扩展中保存用户的设置呢?我们可以使用HTML5新增的localStorage接口。
    当然,Chrome为扩展应用提供了存储API,以便将扩展中需要保存的数据写入本地磁盘。Chrome提供的存储API可以说是对localStorage的改进,它与localStorage相比有以下区别:
      1.如果储存区域指定为sync,数据可以自动同步;
      2.content_scripts可以直接读取数据,而不必通过background页面;
      3.在隐身模式下仍然可以读出之前存储的数据;
      4.读写速度更快;
      5.用户数据可以以对象的类型保存。
    对于第二点需要说明一下。首先localStorage是基于域名的,而content_scripts是注入到用户当前浏览页面中的,如果content_scripts直接读取localStorage,所读取到的数据是用户当前浏览页面所在域中的。所以通常的解决办法是“content_scripts”通过runtime.sendMessage和“background”通信,由“background”读写扩展所在域(通常是chrome-extension://extension-id/)的localStorage,然后再传递给content_scripts。

    使用Chrome存储API必须要在Manifest的permissions中声明"storage",之后才有权限调用。Chrome存储API提供了2种储存区域,分别是sync和local。两种储存区域的区别在于,sync储存的区域会根据用户当前在Chrome上登陆的Google账户自动同步数据,当无可用网络连接可用时,sync区域对数据的读写和local区域对数据的读写行为一致。对于每种储存区域,Chrome又提供了5个方法,
    分别是get、getBytesInUse、set、remove和clear,如下:

    /*
    StorageArea为sync或则local
    例, chrome.storage.sync.get(...)
    */
    chrome.storage.StorageArea.get(keys, function(result){
      console.log(result);
    });
    chrome.storage.StorageArea.getBytesInUse(keys, function(bytes){
      console.log(bytes);
    });
    chrome.storage.StorageArea.set(items, function(){
      //do something
    });
    chrome.storage.StorageArea.remove(keys, function(){
      //do something
    });
    chrome.storage.StorageArea.clear(function(){
      //do something
    });

    Chrome同时还为存储API提供了一个onChanged事件,当存储区的数据发生改变时,这个事件会被触发,如下:

    /*
    callback会接收到两个参数,第一个为changes,第二个是StorageArea。changes是个对象,键为更改的属性名称,值包含两个属性,分别为oldValue和newValue
    */
    chrome.storage.onChanged.addListener(function(changes, areaName){
      console.log('Value in '+areaName+' has been changed:');
      console.log(changes);
    });
    三、通信

    Chrome提供了4个有关ChromeExtension页面间相互通信的接口,分别是runtime.sendMessageruntime.onMessageruntime.connectruntime.onConnect。

    且,Chrome提供的大部分API是不支持在"content_scripts"中运行的,但runtime.sendMessageruntime.onMessage可以在"content_scripts"中运行,所以扩展的其他页面也可以同content_scripts相互通信。

    /*
    extensionId(optional)为所发送消息的目标扩展,如果不指定这个值,则默认为发起此消息的扩展本身;
    message(required)为要发送的内容,类型随意,内容随意
    options(optional)
    callback(optional)用于接收返回结果
    */
    chrome.runtime.sendMessage(extensionId, message, options, callback)
    /*
    callback(required)接收到的参数有三个,分别是message、sender和sendResponse。
    其中sender对象包含4个属性,分别是tab、id、url和tlsChannelId,tab是发起消息的标签(下节会详讲)
    */ chrome.runtime.onMessage.addListener(callback)

     例如,popup.html与backgroud可以如下通信:

    //popup.html
    chrome.runtime.sendMessage('Hello', function(response){
        document.write(response);
    });
    
    //background
    chrome.runtime.onMessage.addListener(function(message, sender, sendResponse){
        if(message == 'Hello'){
            sendResponse('Hello from background.');
        }
    });

    查看popup.html页面会发现有输出“Hello from background.”

    四、标签

    标签的意思就是在浏览器中打开的一个个页面,如下:

    Chrome通过tabs方法提供了管理标签的方法与监听标签行为的事件,大多数方法与事件是无需声明特殊权限的,但有关标签的urltitlefavIconUrl的操作(包括读取),都需要声明tabs权限。

    "permissions": [
        "tabs"
    ]

    获取标签信息。Chrome提供了三种获取标签信息的方法,分别是getgetCurrentqueryget方法可以获取到指定id的标签,getCurrent则获取运行的脚本本身所在的标签,query可以获取所有符合指定条件的标签。

    以getCurrent为例,代码如下:

    chrome.tabs.getCurrent(function(tab){
        console.log(tab);
    });

    重点是,ChromeExtension也可以与指定的标签通信(标签中注入了"content_scripts"),方法如下:

    chrome.tabs.sendMessage(tabId, message, function(response){
        console.log(response);
    });
    五、拓展阅读

    [1]. Chrome Extensions

    [2]. Chrome扩展及应用开发

  • 相关阅读:
    Unity 3(一):简介与示例
    MongoDB以Windows Service运行
    动态SQL中变量赋值
    网站发布IIS后堆栈追踪无法获取出错的行号
    GridView Postback后出错Operation is not valid due to the current state of the object.
    Visual Studio 2010 SP1 在线安装后,找到缓存在本地的临时文件以便下次离线安装
    SQL Server 问题之 排序规则(collation)冲突
    IIS 问题集锦
    linux下安装mysql(ubuntu0.16.04.1)
    apt-get update 系列作用
  • 原文地址:https://www.cnblogs.com/giggle/p/8082672.html
Copyright © 2011-2022 走看看