chrome插件

Chrome 插件是什么

其實(shí),這東西應(yīng)該叫Chrome擴(kuò)展(Chrome Extension),Chrome插件這種叫法是大眾的習(xí)慣稱(chēng)呼。

Chrome 插件 目錄結(jié)構(gòu)

├──  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 插件 其實(shí)就是一個(gè)由HTML、CSS、JS、圖片等資源組成的一個(gè)應(yīng)用,本質(zhì)上來(lái)說(shuō)就是webapp。

Chrome 插件 能幫我們做什么?

  • 網(wǎng)絡(luò)請(qǐng)求攔截處理
  • 書(shū)簽控制
  • 窗口控制
  • 通信機(jī)制
  • 右鍵菜單控制
  • 搜索欄快捷操作
  • ...

文件介紹

manifest.json

{
    // 清單文件的版本,這個(gè)必須寫(xiě),而且必須是2
    "manifest_version": 2,
    // 插件的名稱(chēng)
    "name": "demo",
    // 插件的版本
    "version": "1.0.0",
    // 插件描述
    "description": "簡(jiǎn)單的Chrome擴(kuò)展demo",
    // 圖標(biāo),一般偷懶全部用一個(gè)尺寸的也沒(méi)問(wèn)題
    "icons":
    {
        "16": "img/icon.png",
        "48": "img/icon.png",
        "128": "img/icon.png"
    },
    // 會(huì)一直常駐的后臺(tái)JS或后臺(tái)頁(yè)面
    "background":
    {
        // 2種指定方式,如果指定JS,那么會(huì)自動(dòng)生成一個(gè)背景頁(yè)
        "page": "background.html"
        //"scripts": ["js/background.js"]
    },
    // 瀏覽器右上角圖標(biāo)設(shè)置,browser_action、page_action、app必須三選一
    "browser_action": 
    {
        "default_icon": "img/icon.png",
        // 圖標(biāo)懸停時(shí)的標(biāo)題,可選
        "default_title": "這是一個(gè)示例Chrome插件",
        "default_popup": "popup.html"
    },
    // 需要直接注入頁(yè)面的JS
    "content_scripts": 
    [
        {
            //"matches": ["http://*/*", "https://*/*"],
            // "<all_urls>" 表示匹配所有地址
            "matches": ["<all_urls>"],
            // 多個(gè)JS按順序注入
            "js": ["js/jquery-1.8.3.js", "js/content-script.js"],
            // JS的注入可以隨便一點(diǎn),但是CSS的注意就要千萬(wàn)小心了,因?yàn)橐徊恍⌒木涂赡苡绊懭謽邮?            "css": ["css/custom.css"],
            // 代碼注入的時(shí)間,可選值: "document_start", "document_end", or "document_idle",最后一個(gè)表示頁(yè)面空閑時(shí),默認(rèn)document_idle
            "run_at": "document_start"
        },
    ],
    // 權(quán)限申請(qǐng)
    "permissions":
    [
        "contextMenus", // 右鍵菜單
        "tabs", // 標(biāo)簽
        "notifications", // 通知
        "webRequest", // web請(qǐng)求
        "webRequestBlocking",
        "storage", // 插件本地存儲(chǔ)
        "http://*/*", // 可以通過(guò)executeScript或者insertCSS訪問(wèn)的網(wǎng)站
        "https://*/*" // 可以通過(guò)executeScript或者insertCSS訪問(wèn)的網(wǎng)站
    ],
    // 普通頁(yè)面能夠直接訪問(wèn)的插件資源列表,如果不設(shè)置是無(wú)法直接訪問(wèn)的
    "web_accessible_resources": ["js/inject.js"],
    // 該擴(kuò)展的主頁(yè)地址
    "homepage_url": "https://www.baidu.com",
    // 覆蓋瀏覽器默認(rèn)頁(yè)面
    "chrome_url_overrides":
    {
        // 覆蓋瀏覽器默認(rèn)的新標(biāo)簽頁(yè)
        "newtab": "newtab.html"
    },
    // Chrome40以前的插件配置頁(yè)寫(xiě)法
    "options_page": "options.html",
    // Chrome40以后的插件配置頁(yè)寫(xiě)法,如果2個(gè)都寫(xiě),新版Chrome只認(rèn)后面這一個(gè)
    "options_ui":
    {
        "page": "options.html",
        // 添加一些默認(rèn)的樣式,推薦使用
        "chrome_style": true
    },
    // 向地址欄注冊(cè)一個(gè)關(guān)鍵字以提供搜索建議,只能設(shè)置一個(gè)關(guān)鍵字
    "omnibox": { "keyword" : "go" },
    // 默認(rèn)語(yǔ)言
    "default_locale": "zh_CN",
    // devtools頁(yè)面入口,注意只能指向一個(gè)HTML文件,不能是JS文件
    "devtools_page": "devtools.html"
}

content-scripts

Content scripts是在Web頁(yè)面內(nèi)運(yùn)行的javascript腳本。通過(guò)使用標(biāo)準(zhǔn)的DOM,它們可以獲取瀏覽器所訪問(wèn)頁(yè)面的詳細(xì)信息,并可以修改這些信息。我們可以使用它來(lái)進(jìn)行廣告屏蔽、頁(yè)面圖片提取視頻提取等。

配置如下:

{
    // 需要直接注入頁(yè)面的JS
    "content_scripts": 
    [
        {
            //"matches": ["http://*/*", "https://*/*"],
            // "<all_urls>" 表示匹配所有地址
            "matches": ["<all_urls>"],
            // 多個(gè)JS按順序注入
            "js": ["js/jquery-1.8.3.js", "js/content-script.js"],
            // JS的注入可以隨便一點(diǎn),但是CSS的注意就要千萬(wàn)小心了,因?yàn)橐徊恍⌒木涂赡苡绊懭謽邮?            "css": ["css/custom.css"],
            // 代碼注入的時(shí)間,可選值: "document_start", "document_end", or "document_idle",最后一個(gè)表示頁(yè)面空閑時(shí),默認(rèn)document_idle
            "run_at": "document_start"
        }
    ],
}

content-scripts和原始頁(yè)面共享DOM,但是不共享JS,如要訪問(wèn)頁(yè)面JS(例如某個(gè)JS變量),只能通過(guò)injected js來(lái)實(shí)現(xiàn)。
不能使用除了chrome.extension之外的chrome.* 的接口。

不過(guò)Content scripts 可以使用messages機(jī)制與它所在的擴(kuò)展通信,來(lái)間接使用chrome.*接口,或訪問(wèn)擴(kuò)展數(shù)據(jù)。Content scripts還可以通過(guò)共享的DOM來(lái)與web頁(yè)面通信。

background

background后臺(tái)頁(yè)面,在瀏覽器前臺(tái)看不到的頁(yè)面,可以以后臺(tái)進(jìn)程的方式進(jìn)行運(yùn)行,也可以以事件的方式運(yùn)行。需要打開(kāi)擴(kuò)展程序的開(kāi)發(fā)者模式才能看到。

打開(kāi)方式如下:

image.png

配置如下:

{
    // 會(huì)一直常駐的后臺(tái)JS或后臺(tái)頁(yè)面
    "background":
    {
        // 2種指定方式,如果指定JS,那么會(huì)自動(dòng)生成一個(gè)背景頁(yè)
        "page": "background.html"
        //"scripts": ["js/background.js"]
    },
}

所有頁(yè)面共用同一個(gè)background,它與外部通過(guò)消息傳遞。 它的權(quán)限非常高,可以無(wú)限制跨域,也可以通過(guò)chrome.storage持久化去保存一些用戶配置。

popup

popup是點(diǎn)擊browser_action或者page_action圖標(biāo)時(shí)打開(kāi)的一個(gè)小窗口網(wǎng)頁(yè),焦點(diǎn)離開(kāi)網(wǎng)頁(yè)就立即關(guān)閉,一般用來(lái)做一些臨時(shí)性的交互。popup的控制臺(tái)是直接右鍵popup,選擇檢查即可。

image.png

popup可以寫(xiě)你想要的HTML內(nèi)容,不過(guò)它的生命周期很短,單擊圖標(biāo)打開(kāi)popup,焦點(diǎn)離開(kāi)又立即關(guān)閉。

在權(quán)限上,它和background非常類(lèi)似,它們之間最大的不同是生命周期的不同,popup中可以直接通過(guò)chrome.extension.getBackgroundPage()獲取background的window對(duì)象。

功能展示

右鍵菜單

Chrome插件可以對(duì)普通頁(yè)面、選中的文字、圖片、鏈接等元素,在右鍵的時(shí)候,是通過(guò)chrome.contextMenusAPI實(shí)現(xiàn)一些快捷功能。

右鍵菜單示例

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

// background.js
chrome.contextMenus.create({
    title: "右鍵菜單",
    onclick: function(){alert('您點(diǎn)擊了右鍵菜單!');}
});

效果:

右鍵菜單

chrome_url_overrides

配置chrome_url_overrides可以替換Chrome特定頁(yè)面。

配置如下:

"chrome_url_overrides": {
    "newtab": "newtab.html", // 替換鑫打開(kāi)標(biāo)簽 chrome://newtab
    "history": "history.html", // 替換歷史記錄  chrome://history
    "bookmarks": "bookmarks.html" // 替換瀏覽器書(shū)簽 chrome://bookmarks
}

注意:

  • 一個(gè)擴(kuò)展只能替代一個(gè)特定頁(yè)面;
  • 不能替代隱身窗口的新標(biāo)簽頁(yè);
  • 網(wǎng)頁(yè)必須設(shè)置title,以便隱藏網(wǎng)頁(yè)的URL。

popup動(dòng)態(tài)注入或執(zhí)行JS

background和popup中無(wú)法直接訪問(wèn)頁(yè)面DOM,但是可以通過(guò)chrome.tabs.executeScript來(lái)執(zhí)行腳本,從而實(shí)現(xiàn)訪問(wèn)web頁(yè)面的DOM。

manifest.json配置:

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

localStorage中插值

// 獲取當(dāng)前選項(xiàng)卡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可以直接調(diào)用background中的JS方法,也可以直接訪問(wèn)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主動(dòng)發(fā)消息

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('來(lái)自content的回復(fù):'+response);
});

content-script.js

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

content-script主動(dòng)發(fā)消息給后臺(tái)

content-script.js:

chrome.runtime.sendMessage({greeting: '我是content-script,這是我發(fā)送的消息!'}, (response) => {
    console.log('這是后臺(tái)返回的消息:' + response);
});

background.js 或者 popup.js

// 監(jiān)聽(tīng)來(lái)自content-script的消息
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
    console.log(request, sender, sendResponse);
    sendResponse('我是后臺(tái),我已收到你的消息:' + JSON.stringify(request));
});

注意:
popup每次打開(kāi)都會(huì)走一次創(chuàng)建渲染流程,所以在popup未打開(kāi)的情況下是接收不到content_script發(fā)送的消息,只能通過(guò)background進(jìn)行間接發(fā)送。

調(diào)試

打開(kāi)擴(kuò)展程序,勾選開(kāi)發(fā)者模式,選擇加載已解壓的擴(kuò)展程序。
同時(shí)在代碼變動(dòng)后都需要去刷新一下插件。

image.png

也可以用腳手架去開(kāi)發(fā)Chrome插件,相對(duì)會(huì)更方便一些,腳手架可以幫我們熱重載插件。
這里是一個(gè)Chrome 腳手架,使用 Vue.js + webpack 來(lái)開(kāi)發(fā)和打包Chrome擴(kuò)展, 支持熱重載
https://github.com/jae-jae/chrome-extension-gulu

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容