Chrome插件是一个用Web技术开发、用来增强浏览器功能的软件,Chrome浏览器扩展开发算是相当简单的,基本只要掌握HTML+CSS+Javascript,即可快速开发一个属于你的Chrome插件!它其实就是一个由HTML、CSS、JS、图片等资源组成的一个.crx后缀的压缩包.
增强浏览器功能,轻松实现属于自己的“定制版”浏览器,等等。
Chrome插件提供了很多实用API供我们使用,包括但不限于:
书签控制;
下载控制;
窗口控制;
标签控制;
网络请求控制,
各类事件监听;
自定义原生菜单;
完善的通信机制;
等等;
Chrome插件没有严格的项目结构要求,只要保证本目录有一个manifest.json即可,普通的web开发工具即可。
从右上角菜单->更多工具->扩展程序可以进入 插件管理页面,也可以直接在地址栏输入 chrome://extensions 访问。
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......//还有很多其他的配置}
所谓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来帮你调用。
后台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向它发送消息,等等。
popup是点击browser_action或者page_action图标时打开的一个小窗口网页,焦点离开网页就立即关闭,一般用来做一些临时性的交互。
popup可以包含任意你想要的HTML内容,并且会自适应大小。可以通过default_popup字段来指定popup页面,也可以调用setPopup()方法。
需要特别注意的是,由于单击图标打开popup,焦点离开又立即关闭,所以popup页面的生命周期一般很短,需要长时间运行的代码千万不要写在popup里面。
在权限上,它和background非常类似,它们之间最大的不同是生命周期的不同,popup中可以直接通过chrome.extension.getBackgroundPage()获取background的window对象。
开发者或者插件主页设置
指的是通过DOM操作的方式向页面注入的一种JS。为什么需要通过这种方式注入JS呢?
这是因为content-script有一个很大的“缺陷”,也就是无法访问页面中的JS,虽然它可以操作DOM,但是DOM却不能调用它,也就是无法在DOM中通过绑定事件的方式调用content-script中的代码(包括直接写onclick和addEventListener2种方式都不行),但是,“在页面上添加一个按钮并调用插件的扩展API”是一个很常见的需求,那该怎么办呢?其实这就是本小节要讲的。
在content-script中通过DOM方式向页面注入inject-script代码示例:
// 向页面注入JSfunction 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"], }
通过配置browser_action可以在浏览器的右上角增加一个图标,一个browser_action可以拥有一个图标,一个tooltip(即划过显示title),一个badge(图标上面的文字,有字数限制)和一个popup。
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.jschrome.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()] } ]); }); });
通过开发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)}); } });
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);
使用override页可以将Chrome默认的一些特定页面替换掉,改为使用扩展提供的页面。
//一个扩展只能替代一个页面;"chrome_url_overrides": { "newtab": "newtab.html" "history": "history.html", "bookmarks": "bookmarks.html" }
为了让用户自定义您的应用的行为,您可能会提供一个选项页面。
所谓选项(options)页,就是插件的设置页面,有2个入口,一个是右键图标有一个“选项”菜单,还有一个在插件管理页面:
//manifest.json//Chrome40以前的插件配置页写法"options_page":"xx.html",//Chrome40以后的插件配置页写法,只是样式不一样了,以弹出框的形式显示"options_ui": { "page": "options.html", // 添加一些默认的样式,推荐使用 "chrome_style": true },//为了兼容,建议2种都写,如果都写了,Chrome40以后会默认读取新版的方式;
页面内容看你自己发挥了。这边有一个示例可以看看
omnibox是向用户提供搜索建议的一种方式。具体看api
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: '您刚才点击了自定义右键菜单!' }); } });
为了实现险企账号的管理,使得出单人员在各个险企报价时,不需要自己记录管理险企的登录地址,以后手动输入账号密码。
或者在报价页面插入一些已知的报价填写信息。
文件目录
manifest.json
清单文件
具体配置:
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 文件,包含私有密钥。
安装图片:
不要丢失私有密钥!确保 .pem 文件保密,并存放在安全的地方。如果您今后需要做如下事情,您需要这一文件:
更新应用: 更新应用与安装步骤一样。不同的是此时密钥已经存在。