chrome插件

Chrome 插件是什么

其实,这东西应该叫Chrome扩展(Chrome Extension),Chrome插件这种叫法是大众的习惯称呼。

Chrome 插件 目录结构

├──  manifest.json
├──  html
│    └── index.html
├── images
│   ├──  icon-128.png
│   └──  icon-16.png
├── scripts
│   └── background.js
├── styles
│   └── main.css
└─_locales
    ├── en
    │   └── messages.json
    │
    └── zh_CN
        └── messages.json

上图可以看出,Chrome 插件 其实就是一个由HTML、CSS、JS、图片等资源组成的一个应用,本质上来说就是webapp。

Chrome 插件 能帮我们做什么?

  • 网络请求拦截处理
  • 书签控制
  • 窗口控制
  • 通信机制
  • 右键菜单控制
  • 搜索栏快捷操作
  • ...

文件介绍

manifest.json

{
    // 清单文件的版本,这个必须写,而且必须是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"
    },
    // 需要直接注入页面的JS
    "content_scripts": 
    [
        {
            //"matches": ["http://*/*", "https://*/*"],
            // "" 表示匹配所有地址
            "matches": [""],
            // 多个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"
        },
    ],
    // 权限申请
    "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"
}

content-scripts

Content scripts是在Web页面内运行的javascript脚本。通过使用标准的DOM,它们可以获取浏览器所访问页面的详细信息,并可以修改这些信息。我们可以使用它来进行广告屏蔽、页面图片提取视频提取等。

配置如下:

{
    // 需要直接注入页面的JS
    "content_scripts": 
    [
        {
            //"matches": ["http://*/*", "https://*/*"],
            // "" 表示匹配所有地址
            "matches": [""],
            // 多个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-scripts和原始页面共享DOM,但是不共享JS,如要访问页面JS(例如某个JS变量),只能通过injected js来实现。
不能使用除了chrome.extension之外的chrome.* 的接口。

不过Content scripts 可以使用messages机制与它所在的扩展通信,来间接使用chrome.*接口,或访问扩展数据。Content scripts还可以通过共享的DOM来与web页面通信。

background

background后台页面,在浏览器前台看不到的页面,可以以后台进程的方式进行运行,也可以以事件的方式运行。需要打开扩展程序的开发者模式才能看到。

打开方式如下:

image.png

配置如下:

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

所有页面共用同一个background,它与外部通过消息传递。 它的权限非常高,可以无限制跨域,也可以通过chrome.storage持久化去保存一些用户配置。

popup

popup是点击browser_action或者page_action图标时打开的一个小窗口网页,焦点离开网页就立即关闭,一般用来做一些临时性的交互。popup的控制台是直接右键popup,选择检查即可。

image.png

popup可以写你想要的HTML内容,不过它的生命周期很短,单击图标打开popup,焦点离开又立即关闭。

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

功能展示

右键菜单

Chrome插件可以对普通页面、选中的文字、图片、链接等元素,在右键的时候,是通过chrome.contextMenusAPI实现一些快捷功能。

右键菜单示例

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

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

效果:

右键菜单

chrome_url_overrides

配置chrome_url_overrides可以替换Chrome特定页面。

配置如下:

"chrome_url_overrides": {
    "newtab": "newtab.html", // 替换鑫打开标签 chrome://newtab
    "history": "history.html", // 替换历史记录  chrome://history
    "bookmarks": "bookmarks.html" // 替换浏览器书签 chrome://bookmarks
}

注意:

  • 一个扩展只能替代一个特定页面;
  • 不能替代隐身窗口的新标签页;
  • 网页必须设置title,以便隐藏网页的URL。

popup动态注入或执行JS

background和popup中无法直接访问页面DOM,但是可以通过chrome.tabs.executeScript来执行脚本,从而实现访问web页面的DOM。

manifest.json配置:

{
    "permissions": [
        "tabs", "http://*/*", "https://*/*"
    ],
}

localStorage中插值

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

function executeScriptToCurrentTab(code) {
  getCurrentTabId((tabId) => {
    chrome.tabs.executeScript(tabId, { code });
  });
}

executeScriptToCurrentTab(`localStorage.setItem('overviewGuideShow', false)`);

消息通信

概览

content-script popup-js background-js
content-script - 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 -

popup和background

popup可以直接调用background中的JS方法,也可以直接访问background的DOM:

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

// popup.js
var background = chrome.extension.getBackgroundPage();
background.test();
alert(bg.document.body.innerHTML); // 获取background的DOM

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

content-script.js

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
    console.log(request);
    sendResponse('收到消息popup或background的消息');
});

content-script主动发消息给后台

content-script.js:

chrome.runtime.sendMessage({greeting: '我是content-script,这是我发送的消息!'}, (response) => {
    console.log('这是后台返回的消息:' + response);
});

background.js 或者 popup.js

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

注意:
popup每次打开都会走一次创建渲染流程,所以在popup未打开的情况下是接收不到content_script发送的消息,只能通过background进行间接发送。

调试

打开扩展程序,勾选开发者模式,选择加载已解压的扩展程序
同时在代码变动后都需要去刷新一下插件。

image.png

也可以用脚手架去开发Chrome插件,相对会更方便一些,脚手架可以帮我们热重载插件。
这里是一个Chrome 脚手架,使用 Vue.js + webpack 来开发和打包Chrome扩展, 支持热重载
https://github.com/jae-jae/chrome-extension-gulu

你可能感兴趣的:(chrome插件)