澳门威尼斯人网址Chrome浏览器增添开发系列之一,chrome扩张开发入门

一)      查看扩张程序的详细音信和ID

 

chrome扩展开发入门教程

方今在支付chrome插件,看到壹篇非凡适合入门的学科,特记录一下

经过Chrome 浏览器的“ 工具->越来越多工具->扩展程序”,打开chrome://extensions页面,选中右上角的“开发者形式”,能够查阅扩张程序的详细音信(如名称、概述、占用空间大小、版本和权杖等)和ID。

一.       Google Chrome扩张简介

注:转载

正文首发于
http://liuxianan.com,原来的书文地址:http://blog.liuxianan.com/chrome-plugin-develop.html,转发请注明署名“liuxianan”并在引人注目地点保留原来的书文链接,谢谢!
author: liuxianan

以下是小说内容

2)      查看增添程序的popup页面

谷歌 Chrome增添是1种软件,以增强Chrome浏览器的意义。

写在前方

本身花了接近一个多月的时日断断续续写下这篇博文,并仔细写下全部demo,所以转发务必保留
http://blog.liuxianan.com/chrome-plugin-develop.html
。本文全体涉嫌到的大多数代码均在这一个demo里面:https://github.com/liuxianan/chrome-plugin-demo
,大家能够直接下载下来运维。

除此以外,本文图片较多,请耐心等待加载实现。

本文目录:

image

demo部分截图:

image

通过Chrome 浏览器的“工具 ->愈来愈多工具->扩充程序”,打开chrome://extensions页面,选中右上角的“开发者方式”(必须在开发者情势下才能够看出调试菜单项),那时右键单击地址栏左边的扩张程序图标,采取“审查弹出内容Inspect
popup”,将会打开Developer
Tools窗口,个中能够查看或跟踪popup.html页面包车型大巴有所相关财富,蕴含js、DOM和CSS,如下图所示。同时出示出popup.html页面。

谷歌(Google)Chrome增加使用HTML、JavaScript、CSS和图纸等Web技术开发。

前言

澳门威尼斯人网址 1

谷歌(Google) Chrome扩充与谷歌 Chrome插件分化。谷歌Chrome扩大无需精通浏览器的源代码,而谷歌Chrome插件是更底层的浏览器作用扩展,要求深切驾驭浏览器的源代码。

什么是Chrome插件

从严来讲,大家正在说的东西应该叫Chrome扩张(Chrome Extension),真正意义上的Chrome插件是更底层的浏览器功效扩张,也许需求对浏览器源码有一定控制才有力量去付出。鉴于Chrome插件的叫法已经习惯,本文也全体运用那种叫法,但读者需深知本文所描述的Chrome插件实际上指的是Chrome扩展。

Chrome插件是一个用Web技术开发、用来进步浏览器作用的软件,它实质上便是1个由HTML、CSS、JS、图片等财富整合的贰个.crx后缀的削减包.

私家估算crx可能是Chrome Extension如下三个假名的简写:

image

其余,其实不只是前者技术,Chrome插件还足以包容C++编写的dll动态链接库完毕部分更底层的职能(NPAPI),比如全显示屏截图。

360抢票王插件dll截图

是因为安全原因,Chrome浏览器42上述版本已经6续不再帮衬NPAPI插件,取而代之的是更安全的PPAPI。

 

 

学习Chrome插件开发有怎么样意思

升高浏览器作用,轻松完成属于本人的“定制版”浏览器,等等。

Chrome插件提供了好多实用API供大家利用,包涵但不防止:

  • 书签控制;
  • 下载控制;
  • 窗口控制;
  • 标签控制;
  • 互联网请求控制,各种事件监听;
  • 自定义原生菜单;
  • 八面见光的通讯机制;
  • 等等;

在Developer Tools窗口中,调节和测试常用的有Elements、Sources和Console面板。

二.       谷歌(Google) Chrome扩充的中坚组成

干什么是Chrome插件而不是Firefox插件

  1. Chrome占有率更加高,更多少人用;
  2. 支付更简单;
  3. 采取场景更常见,Firefox插件只好运转在Firefox上,而Chrome除了Chrome浏览器之外,还能运维在拥有webkit内核的国产浏览器,比如360极速浏览器、360平安浏览器、搜狗浏览器、QQ浏览器等等;
  4. 除了,Firefox浏览器也对Chrome插件的运维提供了一定的支撑;

通过Elements面板,可以相比较彰显的页面查看页面包车型地铁构成成分。

GoogleChrome扩充,至少包蕴贰个manifest.json和四个js文件

付出与调节

Chrome插件未有严厉的体系协会需求,只要保险本目录有1个manifest.json即可,也不须求专门的IDE,普通的web开发工具即可。

从右上角菜单->越多工具->扩充程序能够进来
插件管理页面,也足以一直在地方栏输入
chrome://extensions
访问。

image

勾选开发者模式即能够文件夹的款型直接加载插件,不然只好设置.crx格式的公文。Chrome须求插件必须从它的Chrome应用商店安装,此外任何网址下载的都心有余而力不足直接设置,所以,其实我们得以把crx文本解压,然后通过开发者情势直接加载。

支出中,代码有别的变动都必须再一次加载插件,只要求在插件管理页按下Ctrl+R即可,避防万一最佳还把页面刷新一下。

透过Sources面板,可以打开全数涉及的js文件,并设置断点,还足以沃特ch相关的js表明式。跟踪调节和测试进程中,F1一键能够单步调节和测试,Shift+F1一键能够跳过当前运作的函数,F捌键能够回复运行。

  • manifest.json是扩充的调度中心,用于评释种种财富。该公文选用JSON格式定义
  • js文件中定义要推行的操作

中心介绍

通过Console面板,能够查看JavaScript代码(如console.log(),
console.error()等)运营的输出结果,类似于Windows命令行窗口。

谷歌 Chrome扩大,日常还足以回顾图标、页面和CSS等能源

manifest.json

那是一个Chrome插件最重大也是不可缺少的公文,用来安顿全部和插件相关的配备,必须放在根目录。当中,manifest_versionnameversion三个是少不了的,descriptionicons是推荐的。

下边给出的是部分常见的安插项,均有普通话注释,完整的布局文书档案请戳这里

{
    // 清单文件的版本,这个必须写,而且必须是2
    "manifest_version": 2,
    // 插件的名称
    "name": "demo",
    // 插件的版本
    "version": "1.0.0",
    // 插件描述
    "description": "简单的Chrome扩展demo",
    // 图标,一般偷懒全部用一个尺寸的也没问题
    "icons":
    {
        "16": "img/icon.png",
        "48": "img/icon.png",
        "128": "img/icon.png"
    },
    // 会一直常驻的后台JS或后台页面
    "background":
    {
        // 2种指定方式,如果指定JS,那么会自动生成一个背景页
        "page": "background.html"
        //"scripts": ["js/background.js"]
    },
    // 浏览器右上角图标设置,browser_action、page_action、app必须三选一
    "browser_action": 
    {
        "default_icon": "img/icon.png",
        // 图标悬停时的标题,可选
        "default_title": "这是一个示例Chrome插件",
        "default_popup": "popup.html"
    },
    // 当某些特定页面打开才显示的图标
    /*"page_action":
    {
        "default_icon": "img/icon.png",
        "default_title": "我是pageAction",
        "default_popup": "popup.html"
    },*/
    // 需要直接注入页面的JS
    "content_scripts": 
    [
        {
            //"matches": ["http://*/*", "https://*/*"],
            // "<all_urls>" 表示匹配所有地址
            "matches": ["<all_urls>"],
            // 多个JS按顺序注入
            "js": ["js/jquery-1.8.3.js", "js/content-script.js"],
            // JS的注入可以随便一点,但是CSS的注意就要千万小心了,因为一不小心就可能影响全局样式
            "css": ["css/custom.css"],
            // 代码注入的时间,可选值: "document_start", "document_end", or "document_idle",最后一个表示页面空闲时,默认document_idle
            "run_at": "document_start"
        },
        // 这里仅仅是为了演示content-script可以配置多个规则
        {
            "matches": ["*://*/*.png", "*://*/*.jpg", "*://*/*.gif", "*://*/*.bmp"],
            "js": ["js/show-image-content-size.js"]
        }
    ],
    // 权限申请
    "permissions":
    [
        "contextMenus", // 右键菜单
        "tabs", // 标签
        "notifications", // 通知
        "webRequest", // web请求
        "webRequestBlocking",
        "storage", // 插件本地存储
        "http://*/*", // 可以通过executeScript或者insertCSS访问的网站
        "https://*/*" // 可以通过executeScript或者insertCSS访问的网站
    ],
    // 普通页面能够直接访问的插件资源列表,如果不设置是无法直接访问的
    "web_accessible_resources": ["js/inject.js"],
    // 插件主页,这个很重要,不要浪费了这个免费广告位
    "homepage_url": "https://www.baidu.com",
    // 覆盖浏览器默认页面
    "chrome_url_overrides":
    {
        // 覆盖浏览器默认的新标签页
        "newtab": "newtab.html"
    },
    // Chrome40以前的插件配置页写法
    "options_page": "options.html",
    // Chrome40以后的插件配置页写法,如果2个都写,新版Chrome只认后面这一个
    "options_ui":
    {
        "page": "options.html",
        // 添加一些默认的样式,推荐使用
        "chrome_style": true
    },
    // 向地址栏注册一个关键字以提供搜索建议,只能设置一个关键字
    "omnibox": { "keyword" : "go" },
    // 默认语言
    "default_locale": "zh_CN",
    // devtools页面入口,注意只能指向一个HTML文件,不能是JS文件
    "devtools_page": "devtools.html"
}

 

  • 图标经常是1九px*19px的PNG文件
  • 页面平日是HTML文件,用于定义突显给用户的窗口,如popup页面或options页面等

content-scripts

所谓content-scripts,其实正是Chrome插件中向页面注入脚本的一种样式(就算名称叫script,其实还足以总结css的),借助content-scripts咱俩得以兑现通过计划的法子轻松向钦点页面注入JS和CSS(假设急需动态注入,能够参考下文),最普遍的诸如:广告屏蔽、页面CSS定制,等等。

示范配置:

{
    // 需要直接注入页面的JS
    "content_scripts": 
    [
        {
            //"matches": ["http://*/*", "https://*/*"],
            // "<all_urls>" 表示匹配所有地址
            "matches": ["<all_urls>"],
            // 多个JS按顺序注入
            "js": ["js/jquery-1.8.3.js", "js/content-script.js"],
            // JS的注入可以随便一点,但是CSS的注意就要千万小心了,因为一不小心就可能影响全局样式
            "css": ["css/custom.css"],
            // 代码注入的时间,可选值: "document_start", "document_end", or "document_idle",最后一个表示页面空闲时,默认document_idle
            "run_at": "document_start"
        }
    ],
}

尤其注意,假若未有积极性钦定run_atdocument_start(默认为document_idle),下边那种代码是不会收效的:

document.addEventListener('DOMContentLoaded', function()
{
    console.log('我被执行了!');
});

content-scripts和原有页面共享DOM,可是不共享JS,如要访问页面JS(例如某些JS变量),只好通过injected js来实现。content-scripts不能够访问绝超过四分之二chrome.xxx.api,除了上面那肆种:

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

实则看来此间并非悲观,那些API绝当先五成时候都够用了,非要调用别的API的话,你还足以由此通讯来完成让background来帮你调用(关于通讯,后文有详实介绍)。

好了,Chrome插件给我们提供了如此强大的JS注入成效,剩下的就是发挥您的想象力去奚弄浏览器了。

专注:在此面板中输入location.reload(true),能够另行加载popup页面,从而对popup页面包车型客车开首化进程实行跟踪。

               
注意:控制popup窗口或options窗口的独家是popup.js和options.js文件

background

后台(姑且这么翻译啊),是一个常驻的页面,它的生命周期是插件中持有品种页面中最长的,它随着浏览器的开拓而开辟,随着浏览器的关闭而关闭,所以平日把供给直接运行的、运维就运维的、全局的代码放在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"]
    },
}

急需特别表明的是,纵然你能够通过chrome-extension://xxx/background.html直白打开后台页,不过你打开的后台页和实在直接在后台运行的不得了页面不是同一个,换句话说,你可以打开无数个background.html,然则的确在后台常驻的只有3个,而且以此你永远看不到它的界面,只可以调节和测试它的代码。

 

  • CSS是大面积的概念页面样式的文件

event-pages

这里顺带介绍一下event-pages,它是2个如何事物呢?鉴于background生命周期太长,长日子挂载后台恐怕会影响属性,所以谷歌又弄叁个event-pages,在配置文件上,它与background的唯一分化便是多了2个persistent参数:

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

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

除开配置文件的变迁,代码上也有局地细小变化,个人这些不难询问一下就行了,一般景观下background也不会很开支质量的。

叁)      查看扩充程序的options页面

作为叁个谷歌(Google)Chrome扩大,上述全体文件应当都位于2个根目录之下,各类不一样连串的文书能够放在不相同的子目录下。

popup

popup是点击browser_action或者page_action图标时打开的3个小窗口网页,焦点离开网页就立刻关闭,壹般用来做1些一时的相互。

网易网摘插件popup效果

popup能够涵盖自由你想要的HTML内容,并且会自适应大小。可以透过default_popup字段来钦命popup页面,也能够调用setPopup()方法。

布署格局:

{
    "browser_action":
    {
        "default_icon": "img/icon.png",
        // 图标悬停时的标题,可选
        "default_title": "这是一个示例Chrome插件",
        "default_popup": "popup.html"
    }
}

image

急需特别注意的是,由于单击图标打开popup,主题离开又马上关闭,所以popup页面的生命周期一般非常的短,供给长日子运作的代码千万不要写在popup里面。

在权力上,它和background万分接近,它们之间最大的不一致是生命周期的两样,popup中能够直接通过chrome.extension.getBackgroundPage()获取background的window对象。

推而广之程序的options页面包车型客车进度与popup页面类似,差距仅在于打开Developer
Tools窗口的章程。

 

injected-script

这里的injected-script是本身给它取的,指的是通过DOM操作的法子向页面注入的一种JS。为啥要把那种JS单独拿出来研讨吗?又只怕说为啥必要经过那种格局注入JS呢?

那是因为content-script有1个相当的大的“缺陷”,也正是无法访问页面中的JS,即使它能够操作DOM,不过DOM却无法调用它,也正是无能为力在DOM中通过绑定事件的法子调用content-script中的代码(包蕴直接写onclickaddEventListener2种艺术都10分),可是,“在页面上添加一个按钮并调用插件的增添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);
}

您觉得这么就行了?执行一下您会面到如下报错:

Denying load of chrome-extension://efbllncjkjiijkppagepehoekjojdclc/js/inject.js. Resources must be listed in the web_accessible_resources manifest key in order to be loaded by pages outside the extension.

情趣正是您想要在web中平素访问插件中的财富的话不能够不出示声明才行,配置文件中加进如下:

{
    // 普通页面能够直接访问的插件资源列表,如果不设置是无法直接访问的
    "web_accessible_resources": ["js/inject.js"],
}

至于inject-script何以调用content-script中的代码,前面作者会在特意的3个音讯通讯章节详细介绍。

通过Chrome 浏览器的“ 工具->更加多工具->扩充程序”,打开chrome://extensions页面,对于要翻开的扩张程序,单击“选项options”弹出options页面,在options页面中右键单击并选拔“审查成分”即可。

三.       谷歌 Chrome增加的配置运转

homepage_url

开发者只怕插件主页设置,壹般会在如下二个地点显得:

image

image

肆)      查看扩充程序的文书

谷歌Chrome扩展的周转无需依靠任何Web服务器。Chrome 浏览器能够方便地开始展览布局、测试和平运动转。通过Chrome 浏览器打开chrome://extensions页面能够查看当前Chrome 浏览器安顿的1切扩充,该页面也得以由此Chrome 浏览器的“ ->更加多工具->增加程序”打开。chrome://extensions页面如下:

Chrome插件的8种呈现格局

调剂扩大程序的时候,可以由此如下的不2诀窍平素访问谷歌Chrome增加中的文件:

 澳门威尼斯人网址 2

browserAction(浏览器右上角)

通过布署browser_action能够在浏览器的右上角扩展一个图标,三个browser_action能够拥有3个图标,二个tooltip,一个badge和一个popup

演示配置如下:

"browser_action":
{
    "default_icon": "img/icon.png",
    "default_title": "这是一个示例Chrome插件",
    "default_popup": "popup.html"
}

               
chrome-extension://<extensionID>/<pathToFile>

在chrome://extensions页面中,选中右上角的“开发者形式”,出现开发援救按钮如下:

图标

browser_action图标推荐应用宽高都为19像素的图片,更加大的图标会被缩短,格式随意,1般推荐png,能够由此manifest中default_icon字段配置,也足以调用setIcon()方法。

中间,extensionID能够经过chrome://extensions的ULacrosseL查看。在支付进程中extensionID日常转移,可以选拔@@extension_id替代;1旦打包安排就具有永久的extensionID。

 澳门威尼斯人网址 3

tooltip

修改browser_action的manifest中default_title字段,大概调用setTitle()方法。

image

 

badge

所谓badge尽管在图标上呈现一些文书,能够用来更新1些小的恢宏状态提醒音信。因为badge空间有限,所以只帮忙陆个以下的字符(英文5个,中文1个)。badge不可能通过配备文件来钦命,必须透过代码达成,设置badge文字和颜色能够分别使用setBadgeText()setBadgeBackgroundColor()

chrome.browserAction.setBadgeText({text: 'new'});
chrome.browserAction.setBadgeBackgroundColor({color: [255, 0, 0, 255]});

效果:

image

在开发者情势中,开发职员能够通过“加载已解压缩的扩充程序…”按钮,直接加载并调试GoogleChrome扩张。当然,也能够直接将增添程序所在的目录拖放到chrome://extensions页面中,完结对增加程序的加载。Chrome 浏览器会对加载的扩充程序的manifest.json文件进行语法有效性验证,通过认证的扩大程序将会即时在Chrome 浏览器中生效。

pageAction(地址栏左侧)

所谓pageAction,指的是只有当某个特定页面打开才展现的图标,它和browserAction最大的分化是一个平素都显得,2个只在特定情景才显示。

亟需尤其表达的是早些版本的Chrome是将pageAction放在地址栏的最右面,左键单击弹出popup,右键单击则弹出相关暗许的选项菜单:

image

而新版的Chrome更改了那壹策略,pageAction和一般的browserAction一样也是位于浏览器右上角,只然则没有点亮时是暗灰的,点亮了才是彩色的,浅灰时无论左键照旧右键单击都是弹出选项:

image

切实是从哪一版本开端改的没去仔细考证,反正知道v50.0的时候依然前者,v58.0的时候已改为后代。

调动之后的pageAction我们得以不难地把它当作是足以置灰的browserAction

  • chrome.pageAction.show(tabId) 展现图标;
  • chrome.pageAction.hide(tabId) 隐藏图标;

示范(唯有打开百度才显得图标):

// manifest.json
{
    "page_action":
    {
        "default_icon": "img/icon.png",
        "default_title": "我是pageAction",
        "default_popup": "popup.html"
    },
    "permissions": ["declarativeContent"]
}

// 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()]
            }
        ]);
    });
});

效果图:

image

留神:manifest.json文件仅在加载过程中被读取一回。对manifest.json文件的修改必须透过重新加载才能够生效。

右键菜单

透过付出Chrome插件能够自定义浏览器的右键菜单,重借使通过chrome.contextMenusAPI完结,右键菜单可以出今后分化的上下文,比如平常页面、选中的文字、图片、链接,等等,要是有同贰个插件里面定义了四个菜单,Chrome会自动组合放到以插件名字命名的二级菜单里,如下:

image

在支付过程中,开发职员能够经过“立时更新扩大程序”按钮,查看谷歌Chrome扩张的新星变化。

最简便的右键菜单示例

// manifest.json
{"permissions": ["contextMenus"]}

// background.js
chrome.contextMenus.create({
    title: "测试右键菜单",
    onclick: function(){alert('您点击了右键菜单!');}
});

效果:

image

谷歌Chrome扩展开发达成,开发人士能够通过“打包扩张程序…”将先后打包为1个.crx文件,以便于发表。

累加右键百度查寻

// manifest.json
{"permissions": ["contextMenus", "tabs"]}

// background.js
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)});
    }
});

功效如下:

image

通过Chorme Developer Dashboard (注册必要$伍),能够将谷歌Chrome扩张公布到Chrome Web Store。

语法表明

此地只是简短列举部分常用的,完整API参见:https://developer.chrome.com/extensions/contextMenus

chrome.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);

override(覆盖特定页面)

使用override页能够将Chrome私下认可的局地一定页面替换掉,改为使用扩张提供的页面。

扩阿不都外力·阿布来提以替代如下页面:

  • 历史记录:从工具菜单上点击历史记录时访问的页面,或许从地点栏直接输入
    chrome://history
  • 新标签页:当创立新标签的时候访问的页面,或许从地点栏直接输入
    chrome://newtab
  • 书签:浏览器的书签,或然直接输入
    chrome://bookmarks

注意:

  • 3个恢宏只可以代替二个页面;
  • 不可能代表隐身窗口的新标签页;
  • 网页必须安装title,不然用户可能晤面到网页的UPAJEROL,造成干扰;

上边包车型大巴截图是暗中认可的新标签页和被扩充替换掉的新标签页。

image

代码(注意,贰个插件只好代替1个私下认可页,以下仅为示范):

"chrome_url_overrides":
{
    "newtab": "newtab.html",
    "history": "history.html",
    "bookmarks": "bookmarks.html"
}

devtools(开发者工具)

预热

运用过vue的应当见过那种类型的插件:

image

没有错,Chrome允许插件在开发者工具(devtools)上动手脚,重要表现在:

  • 自定义2个和七个和ElementsConsoleSources等同级其余面板;
  • 自定义侧边栏(sidebar),近年来不得不自定义Elements面板的侧面栏;

先来看二张简略的demo截图,自定义面板(判断当前页面是或不是利用了jQuery):

image

自定义侧边栏(获取当前页面全体图片):

image

devtools扩大介绍

主页:https://developer.chrome.com/extensions/devtools

来一张官方图片:

image

每打开3个开发者工具窗口,都会成立devtools页面包车型大巴实例,F1二窗口关闭,页面也乘机关闭,所以devtools页面包车型客车生命周期和devtools窗口是同一的。devtools页面能够访问一组有意的DevTools API以及个其余恢弘API,那组有意的DevTools API唯有devtools页面才得以访问,background都无权访问,这几个API蕴涵:

  • chrome.devtools.panels:面板相关;
  • chrome.devtools.inspectedWindow:获取被审批窗口的关于音讯;
  • chrome.devtools.network:获取有关互连网请求的新闻;

一大半恢弘API都无法儿直接被DevTools页面调用,但它能够像content-script1样一向调用chrome.extensionchrome.runtimeAPI,同时它也得以像content-script平等接纳Message交互的艺术与background页面进行通讯。

实例:创制三个devtools扩充

率先,要本着开发者工具开发插件,须求在清单文件宣称如下:

{
    // 只能指向一个HTML文件,不能是JS文件
    "devtools_page": "devtools.html"
}

这个devtools.html在那之中一般如何都未曾,就引进1个js:

<!DOCTYPE html>
<html>
<head></head>
<body>
    <script type="text/javascript" src="js/devtools.js"></script>
</body>
</html>

能够看出来,其实确实代码是devtools.js,html文件是“多余”的,所以这边觉得有些坑,devtools_page干嘛不允许直接内定JS呢?

再来看devtools.js的代码:

// 创建自定义面板,同一个插件可以创建多个自定义面板
// 几个参数依次为:panel标题、图标(其实设置了也没地方显示)、要加载的页面、加载成功后的回调
chrome.devtools.panels.create('MyPanel', 'img/icon.png', 'mypanel.html', function(panel)
{
    console.log('自定义面板创建成功!'); // 注意这个log一般看不到
});

// 创建自定义侧边栏
chrome.devtools.panels.elements.createSidebarPane("Images", function(sidebar)
{
    // sidebar.setPage('../sidebar.html'); // 指定加载某个页面
    sidebar.setExpression('document.querySelectorAll("img")', 'All Images'); // 通过表达式来指定
    //sidebar.setObject({aaa: 111, bbb: 'Hello World!'}); // 直接设置显示某个对象
});

setPage时的功力:

image

以下截图示例的代码:

image

// 检测jQuery
document.getElementById('check_jquery').addEventListener('click', function()
{
    // 访问被检查的页面DOM需要使用inspectedWindow
    // 简单例子:检测被检查页面是否使用了jQuery
    chrome.devtools.inspectedWindow.eval("jQuery.fn.jquery", function(result, isException)
    {
        var html = '';
        if (isException) html = '当前页面没有使用jQuery。';
        else html = '当前页面使用了jQuery,版本为:'+result;
        alert(html);
    });
});

// 打开某个资源
document.getElementById('open_resource').addEventListener('click', function()
{
    chrome.devtools.inspectedWindow.eval("window.location.href", function(result, isException)
    {
        chrome.devtools.panels.openResource(result, 20, function()
        {
            console.log('资源打开成功!');
        });
    });
});

// 审查元素
document.getElementById('test_inspect').addEventListener('click', function()
{
    chrome.devtools.inspectedWindow.eval("inspect(document.images[0])", function(result, isException){});
});

// 获取所有资源
document.getElementById('get_all_resources').addEventListener('click', function()
{
    chrome.devtools.inspectedWindow.getResources(function(resources)
    {
        alert(JSON.stringify(resources));
    });
});

调剂技巧

修改了devtools页面包车型客车代码时,须要先在
chrome://extensions
页面按下Ctrl+R双重加载插件,然后倒闭再打开开发者工具即可,无需刷新页面(而且只刷新页面不刷新开发者工具的话是不会生效的)。

是因为devtools本身正是开发者工具页面,所以差不多未有主意能够一向调节和测试它,直接用
chrome-extension://extid/devtools.html"的秘诀打开页面肯定报错,因为不协理相关特殊API,只可以先自个儿写一些方式屏蔽这个错误,调节和测试通了再放手。

option(选项页)

所谓options页,便是插件的装置页面,有三个入口,一个是右键图标有二个“选项”菜单,还有3个在插件管理页面:

image

image

在Chrome40原先,options页面和其余普通页面没什么分化,Chrome40过后则有了有的生成。

我们先看老版的options

{
    // Chrome40以前的插件配置页写法
    "options_page": "options.html",
}

这些页面里面包车型客车剧情就随你自身表述了,配置之后在插件管理页就相会到三个选项按钮入口,点进去就是打开四个网页,没啥好讲的。

效果:

image

再来看新版的optionsV2

{
    "options_ui":
    {
        "page": "options.html",
        // 添加一些默认的样式,推荐使用
        "chrome_style": true
    },
}

options.html的代码我们从没别的变动,只是布置文件改了,之后效果如下:

image

看起来是否硬汉上了?

几点注意:

  • 为了同盟,建议二种都写,假诺都写了,Chrome40后头会暗许读取新版的方法;
  • 新版options中无法动用alert;
  • 数码存款和储蓄建议用chrome.storage,因为会随用户自动同步;

omnibox

omnibox是向用户提供查找建议的壹种办法。先来看个gif图以便领会一下那东西到底是个什么鬼:

image

登记有些关键字以触发插件自身的探寻建议界面,然后能够Infiniti制发挥了。

先是,配置文件如下:

{
    // 向地址栏注册一个关键字以提供搜索建议,只能设置一个关键字
    "omnibox": { "keyword" : "go" },
}

然后background.js中登记监听事件:

// omnibox 演示
chrome.omnibox.onInputChanged.addListener((text, suggest) => {
    console.log('inputChanged: ' + text);
    if(!text) return;
    if(text == '美女') {
        suggest([
            {content: '中国' + text, description: '你要找“中国美女”吗?'},
            {content: '日本' + text, description: '你要找“日本美女”吗?'},
            {content: '泰国' + text, description: '你要找“泰国美女或人妖”吗?'},
            {content: '韩国' + text, description: '你要找“韩国美女”吗?'}
        ]);
    }
    else if(text == '微博') {
        suggest([
            {content: '新浪' + text, description: '新浪' + text},
            {content: '腾讯' + text, description: '腾讯' + text},
            {content: '搜狐' + text, description: '搜索' + text},
        ]);
    }
    else {
        suggest([
            {content: '百度搜索 ' + text, description: '百度搜索 ' + text},
            {content: '谷歌搜索 ' + text, description: '谷歌搜索 ' + text},
        ]);
    }
});

// 当用户接收关键字建议时触发
chrome.omnibox.onInputEntered.addListener((text) => {
    console.log('inputEntered: ' + text);
    if(!text) return;
    var href = '';
    if(text.endsWith('美女')) href = 'http://image.baidu.com/search/index?tn=baiduimage&ie=utf-8&word=' + text;
    else if(text.startsWith('百度搜索')) href = 'https://www.baidu.com/s?ie=UTF-8&wd=' + text.replace('百度搜索 ', '');
    else if(text.startsWith('谷歌搜索')) href = 'https://www.google.com.tw/search?q=' + text.replace('谷歌搜索 ', '');
    else href = 'https://www.baidu.com/s?ie=UTF-8&wd=' + text;
    openUrlCurrentTab(href);
});
// 获取当前选项卡ID
function getCurrentTabId(callback)
{
    chrome.tabs.query({active: true, currentWindow: true}, function(tabs)
    {
        if(callback) callback(tabs.length ? tabs[0].id: null);
    });
}

// 当前标签打开某个链接
function openUrlCurrentTab(url)
{
    getCurrentTabId(tabId => {
        chrome.tabs.update(tabId, {url: url});
    })
}

桌面通告

Chrome提供了2个chrome.notificationsAPI以便插件推送桌面通告,暂未找到chrome.notifications和HTML5自带的Notification的人所共知分歧及优势。

在后台JS中,无论是使用chrome.notifications还是Notification都不须要报名权限(HTML5艺术索要报名权限),间接动用即可。

最简便的打招呼:

image

代码:

chrome.notifications.create(null, {
    type: 'basic',
    iconUrl: 'img/icon.png',
    title: '这是标题',
    message: '您刚才点击了自定义右键菜单!'
});

通报的体裁能够很丰硕:

image

以此未有深刻钻研,有必要的能够去看官方文书档案。

5种档次的JS相比较

Chrome插件的JS主要能够分成那五类:injected scriptcontent-scriptpopup jsbackground jsdevtools js

权力相比

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

调节情势相比较

JS类型 调节情势 图片表明
injected script 直白普通的F1二即可 无意截图

| content-script | 打开Console,如图切换 |

image

|
| popup-js | popup页面右键审查成分 |

image

|

| background | 插件管理页点击背景页即可 |

image

|
| devtools-js | 暂未找到有效措施 | – |

音讯通讯

通讯主页:https://developer.chrome.com/extensions/messaging

前方我们介绍了Chrome插件中设有的伍种JS,那么它们之间怎么相互通讯呢?上边先来系统概略一下,然后再分类细说。须求领悟的是,popup和background其实大概可以视为一种东西,因为它们可访问的API都同样、通信机制一样、都足以跨域。

互相之间通信大概浏览

注:-代表不存在或许无意义,可能待验证。

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

通讯详细介绍

popup和background

popup能够一向调用background中的JS方法,也得以直接待上访问background的DOM:

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

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

小插曲,明日碰着一个意况,发现popup不能得到background的其它措施,找了半天才发觉是因为background的js报错了,而你一旦不积极查看background的js的话,是看不到错误新闻的,特此提示。

至于background访问popup如下(前提是popup早已开辟):

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

popup只怕bg向content主动发送音讯

background.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:'你好,我是popup!'}, function(response)
{
    console.log('来自content的回复:'+response);
});

content-script.js接收:

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse)
{
    // console.log(sender.tab ?"from a content script:" + sender.tab.url :"from the extension");
    if(request.cmd == 'test') alert(request.value);
    sendResponse('我收到了你的消息!');
});

双面通讯直接发送的都是JSON对象,不是JSON字符串,所以不必解析,很有益于(当然也足以一向发送字符串)。

网上有个别老代码中用的是chrome.extension.onMessage,未有完全查清二者的界别(貌似是外号),不过提议统一使用chrome.runtime.onMessage

content-script主动发信息给后台

content-script.js:

chrome.runtime.sendMessage({greeting: '你好,我是content-script呀,我主动发消息给后台!'}, function(response) {
    console.log('收到来自后台的回复:' + response);
});

background.js 或者 popup.js:

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

注意事项:

  • content_scripts向popup继续努力发新闻的前提是popup必须打开!不然须求利用background作中间转播;
  • 一旦background和popup同时监听,那么它们都足以同时收到消息,不过唯有三个能够sendResponse,二个首发送了,那么其余一个再发送就不算;

injected script和content-script

content-script和页面内的剧本(injected-script理所当然也属于页面内的剧本)之间唯一共享的事物正是页面包车型大巴DOM成分,有二种办法能够达成四头通信:

  1. 能够通过window.postMessagewindow.addEventListener来落实两岸音讯广播发表;
  2. 通过自定义DOM事件来兑现;

第叁种格局(推荐):

injected-script中:

window.postMessage({"test": '你好!'}, '*');

content script中:

window.addEventListener("message", function(e)
{
    console.log(e.data);
}, false);

其次种办法:

injected-script中:

var customEvent = document.createEvent('Event');
customEvent.initEvent('myCustomEvent', true, true);
function fireCustomEvent(data) {
    hiddenDiv = document.getElementById('myCustomEventDiv');
    hiddenDiv.innerText = data
    hiddenDiv.dispatchEvent(customEvent);
}
fireCustomEvent('你好,我是普通JS!');

content-script.js中:

var hiddenDiv = document.getElementById('myCustomEventDiv');
if(!hiddenDiv) {
    hiddenDiv = document.createElement('div');
    hiddenDiv.style.display = 'none';
    document.body.appendChild(hiddenDiv);
}
hiddenDiv.addEventListener('myCustomEvent', function() {
    var eventData = document.getElementById('myCustomEventDiv').innerText;
    console.log('收到自定义事件消息:' + eventData);
});

长连接和短连接

实则上边已经涉嫌到了,那里再独自说圣元下。Chrome插件中有2种通讯形式,多少个是短连接(chrome.tabs.sendMessagechrome.runtime.sendMessage),二个是长连接(chrome.tabs.connectchrome.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: '我是你爸!'});
        });
    }
});

其它补充

动态注入或执行JS

虽然在backgroundpopup中不可能直接待上访问页面DOM,不过能够通过chrome.tabs.executeScript来实施脚本,从而达成访问web页面包车型大巴DOM(注意,那种办法也无法一贯访问页面JS)。

示例manifest.json配置:

{
    "name": "动态JS注入演示",
    ...
    "permissions": [
        "tabs", "http://*/*", "https://*/*"
    ],
    ...
}

JS:

// 动态执行JS代码
chrome.tabs.executeScript(tabId, {code: 'document.body.style.backgroundColor="red"'});
// 动态执行JS文件
chrome.tabs.executeScript(tabId, {file: 'some-script.js'});

动态注入CSS

示例manifest.json配置:

{
    "name": "动态CSS注入演示",
    ...
    "permissions": [
        "tabs", "http://*/*", "https://*/*"
    ],
    ...
}

JS代码:

// 动态执行CSS代码,TODO,这里有待验证
chrome.tabs.insertCSS(tabId, {code: 'xxx'});
// 动态执行CSS文件
chrome.tabs.insertCSS(tabId, {file: 'some-style.css'});

获得当前窗口ID

chrome.windows.getCurrent(function(currentWindow)
{
    console.log('当前窗口ID:' + currentWindow.id);
});

赢妥帖前标签页ID

一般有2种方法:

// 获取当前选项卡ID
function getCurrentTabId(callback)
{
    chrome.tabs.query({active: true, currentWindow: true}, function(tabs)
    {
        if(callback) callback(tabs.length ? tabs[0].id: null);
    });
}

收获当前选项卡id的另壹种艺术,超越4九%时候都好像,唯有少部分时候会区别(例如当窗口最小化时)

// 获取当前选项卡ID
function getCurrentTabId2()
{
    chrome.windows.getCurrent(function(currentWindow)
    {
        chrome.tabs.query({active: true, windowId: currentWindow.id}, function(tabs)
        {
            if(callback) callback(tabs.length ? tabs[0].id: null);
        });
    });
}

地面存款和储蓄

本土存款和储蓄提议用chrome.storage而不是平时的localStorage,差异有少数点,个人认为最重点的二点分别是:

  • chrome.storage是针对性插件全局的,即便你在background中保留的多寡,在content-script也能博获得;
  • chrome.storage.sync能够跟随当前登录用户自动同步,这台电脑修改的设置会自行同步到其余总括机,很有利,倘使未有登录依然未联网则先保存到本地,等登录了再1同至网络;

亟待证明storage权限,有chrome.storage.syncchrome.storage.local二种方法可供选拔,使用示例如下:

// 读取数据,第一个参数是指定要读取的key以及设置默认值
chrome.storage.sync.get({color: 'red', age: 18}, function(items) {
    console.log(items.color, items.age);
});
// 保存数据
chrome.storage.sync.set({color: 'blue'}, function() {
    console.log('保存成功!');
});

webRequest

透过webRequest种类API能够对HTTP请求举行任意地修改、定制,那里经过beforeRequest来不难演示一下它的冰山一角:

//manifest.json
{
    // 权限申请
    "permissions":
    [
        "webRequest", // web请求
        "webRequestBlocking", // 阻塞式web请求
        "storage", // 插件本地存储
        "http://*/*", // 可以通过executeScript或者insertCSS访问的网站
        "https://*/*" // 可以通过executeScript或者insertCSS访问的网站
    ],
}


// background.js
// 是否显示图片
var showImage;
chrome.storage.sync.get({showImage: true}, function(items) {
    showImage = items.showImage;
});
// web请求监听,最后一个参数表示阻塞式,需单独声明权限:webRequestBlocking
chrome.webRequest.onBeforeRequest.addListener(details => {
    // cancel 表示取消本次请求
    if(!showImage && details.type == 'image') return {cancel: true};
    // 简单的音视频检测
    // 大部分网站视频的type并不是media,且视频做了防下载处理,所以这里仅仅是为了演示效果,无实际意义
    if(details.type == 'media') {
        chrome.notifications.create(null, {
            type: 'basic',
            iconUrl: 'img/icon.png',
            title: '检测到音视频',
            message: '音视频地址:' + details.url,
        });
    }
}, {urls: ["<all_urls>"]}, ["blocking"]);

国际化

插件根目录新建多个名称为_locales的公文夹,再在底下新建1些语言的文件夹,如enzh_CNzh_TW,然后再在各样文件夹放入3个messages.json,同时必须在清单文件中设置default_locale

_locales\en\messages.json内容:

{
    "pluginDesc": {"message": "A simple chrome extension demo"},
    "helloWorld": {"message": "Hello World!"}
}

_locales\zh_CN\messages.json内容:

{
    "pluginDesc": {"message": "一个简单的Chrome插件demo"},
    "helloWorld": {"message": "你好啊,世界!"}
}

manifest.jsonCSS文件中经过__MSG_messagename__引入,如:

{
    "description": "__MSG_pluginDesc__",
    // 默认语言
    "default_locale": "zh_CN",
}

JS中则直接chrome.i18n.getMessage("helloWorld")

测试时,通过给chrome建立3个两样的火速方式chrome.exe --lang=en来切换语言,如:

image

英文效果:

image

中文效果:

image

API总结

正如常用用的1对API系列:

  • chrome.tabs
  • chrome.runtime
  • chrome.webRequest
  • chrome.window
  • chrome.storage
  • chrome.contextMenus
  • chrome.devtools
  • chrome.extension

经验计算

查看已设置插件路径

已设置的插件源码路径:C:\Users\用户名\AppData\Local\Google\Chrome\User Data\Default\Extensions,每二个插件被放在以插件ID为名的公文夹里面,想要学习有个别插件的有个别成效是哪些兑现的,看人家的源码是最佳的章程了:

image

怎样查看有个别插件的ID?进入
chrome://extensions
,然后勾线开发者形式即可看到了。

image

尤其注意background的报错

众多时候你意识你的代码会不可捉摸的失效,找来找去又找不到原因,那时打开background的支配台才意识原先某些地点写错了导致代码没生效,正式由于background报错的隐蔽性(必要积极打开对应的控制台才能看出错误),所以特别注意这一点。

哪些让popup页面不关门

在对popup页面审查成分的时候popup会被勒迫打开不可能关闭,唯有控制台关闭了才方可关闭popup,原因非常粗略:假诺popup关闭了控制台就没用了。那种格局在壹些景况下很实用!

不支持内联JavaScript的履行

约等于不援救将js直接写在html中,比如:

<input id="btn" type="button" value="收藏" onclick="test()"/>

报错如下:

Refused to execute inline event handler because it violates the following Content Security Policy directive: "script-src 'self' blob: filesystem: chrome-extension-resource:". Either the 'unsafe-inline' keyword, a hash ('sha256-...'), or a nonce ('nonce-...') is required to enable inline execution.

缓解方法就是用JS绑定事件:

$('#btn').on('click', function(){alert('测试')});

另外,对于A标签,这样写href="javascript:;"然后用JS绑定事件尽管控制台会报错,可是不受影响,当然抑郁症伤者不堪的话只好写成href="#"了。

比方那样写:

<a href="javascript:;" id="get_secret">请求secret</a>

报错如下:

Refused to execute JavaScript URL because it violates the following Content Security Policy directive: "script-src 'self' blob: filesystem: chrome-extension-resource:". Either the 'unsafe-inline' keyword, a hash ('sha256-...'), or a nonce ('nonce-...') is required to enable inline execution.

流入CSS的时候必须小心

由于通过content_scripts流入的CSS优先级相当高,大致紧跟于浏览器暗中认可样式,稍不理会大概就会潜移默化局地网址的来得效果,所以尽或者不要写一些震慑全局的样式。

故此强调那个,是因为这几个带来的标题特别隐匿,不太简单找到,可能您正在写某些网页,昨日体制照旧不错的,怎么前几日就忽然相当了?然后你辛劳苦苦找来找去,找了半天才发现竟是是因为插件里面包车型客车八个体裁影响的!

image

装进与揭橥

包装的话一贯在插件管理页有叁个卷入按钮:

image

下一场会转变叁个.crx文本,要颁发到谷歌应用商店的话须要首先登场录你的谷歌账号,然后花五个$注册为开发者,本人太穷,就懒得亲自表明了,有发布必要的投机去整吧。

image

参考

法定资料

引入查看官方文档,固然是英文,不过全且新,国内的国语资料都相比旧(注意以下全体急需翻墙):

其③方材料

一对国语资料,不是特地推荐:

附图

附图:Chrome高清png格式logo:

image

相关文章