开发一个简单的chrome插件

    科技2024-07-31  32

    chrome插件文件组成

    核心manifest.jsonmanifest.json文件中配置的内容:比如注入的JS CSS 以及插件的功能HTML配置的图标文件

    一个简单提取网页内容的插件

    1.插件代码结构

    2.manifest.json文件

    { // 清单文件的版本,这个必须写,而且必须是2 "manifest_version": 2, // 插件的名称 "name": "亚马逊开发票", // 插件的版本 "version": "1.0.0", // 插件描述 "description": "亚马逊开发票关键信息显示,方便获取重要信息,快速开发票。", // 图标,一般偷懒全部用一个尺寸的也没问题 "icons": { "16": "img/icon.png", "48": "img/icon.png", "128": "img/icon.png" }, // 会一直常驻的后台JS或后台页面 // 浏览器右上角图标设置,browser_action、page_action、app必须三选一 "browser_action": { "default_icon": "img/icon.png", // 图标悬停时的标题,可选 "default_title": "亚马逊开发票关键信息显示,方便获取重要信息,快速开发票。", "default_popup": "popup.html" }, // 需要直接注入页面的JS "content_scripts": [ { "matches": ["https://sellercentral.amazon.co.uk/*"], // 多个JS按顺序注入 "js": [ "js/hello.js","js/aws.js"], // 代码注入的时间,可选值: "document_start", "document_end", or "document_idle",最后一个表示页面空闲时,默认document_idle "run_at": "document_start" } ] }

    3.配置注入的两个JS

    "js": [ "js/hello.js","js/aws.js"]

    hello.js

    (function(){ console.log("执行了") })();

    aws.js

    (function(){ var orderId=$('[data-test-id=order-id-value]').text(); var addr=""; var userName=$('[data-test-id=buyer-name-with-link]').text(); var productName=$('a div.more-info-column-word-wrap-break-word').text(); var Proceeds=""; var quantity=$('table.a-keyvalue td:eq(4)').text(); var date=$('[data-test-id=order-summary-purchase-date-value]').text(); var len=$('[data-test-id=shipping-section-buyer-address] span').length; for(var i=0;i<len;i++){ addr+=$('[data-test-id=shipping-section-buyer-address] span:eq('+i+')').text(); if(i!=(len-1)){ addr+="\n"; } } var totalLen=$('table.a-keyvalue td:eq(6) div.a-row').length; for(var j=0;j<totalLen;j++){ Proceeds+=$('table.a-keyvalue td:eq(6) div.a-row:eq('+j+')').text(); if(j!=(totalLen-1)){ Proceeds+="\n"; } } $("#MYO-app").append(`<h3>orderId</h3><textarea style="font-size: 16px;">${orderId}</textarea>`) $("#MYO-app").append(`<h3>addr</h3><textarea style="font-size: 16px;">${addr}</textarea>`) $("#MYO-app").append(`<h3>userName</h3><textarea style="font-size: 16px;">${userName}</textarea>`) $("#MYO-app").append(`<h3>productName</h3><textarea style="font-size: 16px;">${productName}</textarea>`) $("#MYO-app").append(`<h3>quantity</h3><textarea style="font-size: 16px;">${quantity}</textarea>`) $("#MYO-app").append(`<h3>Proceeds</h3><textarea style="font-size: 16px;">${Proceeds}</textarea>`) $("#MYO-app").append(`<h3>date</h3><textarea style="font-size: 16px;">${date}</textarea>`) })();

    4.加入图标文件

    img/icon.png

    5.导入到浏览器测试

     

     

     

    下面就来仔细看看这个配置文件

    1. manifest.json

    这是一个Chrome插件最重要也是必不可少的文件,用来配置所有和插件相关的配置,必须放在根目录。其中,manifest_version、name、version3个是必不可少的,description和icons是推荐的。

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

    { // 清单文件的版本,这个必须写,而且必须是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" }

     

    2. 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_at为document_start(默认为document_idle),下面这种代码是不会生效的:

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

    content-scripts和原始页面共享DOM,但是不共享JS,如要访问页面JS(例如某个JS变量),只能通过injected js来实现。content-scripts不能访问绝大部分chrome.xxx.api,除了下面这4种:

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

    其实看到这里不要悲观,这些API绝大部分时候都够用了,非要调用其它API的话,你还可以通过通信来实现让background来帮你调用(关于通信,后文有详细介绍)。

    好了,Chrome插件给我们提供了这么强大的JS注入功能,剩下的就是发挥你的想象力去玩弄浏览器了。

    3. 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,但是真正在后台常驻的只有一个,而且这个你永远看不到它的界面,只能调试它的代码。

    4. event-pages

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

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

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

    除了配置文件的变化,代码上也有一些细微变化,个人这个简单了解一下就行了,一般情况下background也不会很消耗性能的。

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

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

    配置方式:

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

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

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

    6. injected-script

    这里的injected-script是我给它取的,指的是通过DOM操作的方式向页面注入的一种JS。为什么要把这种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); }

    你以为这样就行了?执行一下你会看到如下报错:

    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中的代码,后面我会在专门的一个消息通信章节详细介绍。

    7. homepage_url

    开发者或者插件主页设置,一般会在如下2个地方显示:

     

    参考:https://www.cnblogs.com/liuxianan/p/chrome-plugin-develop.html

    Processed: 0.009, SQL: 8