Chrome插件開發(fā)快速入門

前言

周末學(xué)習(xí)了下Chrome插件的開發(fā),總體來(lái)說入門還是比較容易的,動(dòng)手配合一些demo就能了解基本的開發(fā)過程。這篇是一個(gè)學(xué)習(xí)筆記和總結(jié),希望對(duì)大家也有所幫助。

什么是Chrome插件

Chrome插件其實(shí)和一個(gè)普通web應(yīng)用一樣都是由html+css+js打包組成的,插件可以使用Chrome提供的瀏覽器API,增強(qiáng)瀏擴(kuò)展覽器的功能。
Chrome插件通常是.crx后綴的文件,通過谷歌網(wǎng)上應(yīng)用商店下載或者在開發(fā)者模式中可以直接拖入到瀏覽器進(jìn)行安裝

用戶界面網(wǎng)頁(yè)(popup)

點(diǎn)擊插件圖標(biāo)出來(lái)的彈窗其實(shí)就是一個(gè)html頁(yè)面,彈窗要顯示的內(nèi)容,和工具欄小圖標(biāo)在manifest.json文件中配置。

彈窗在每次點(diǎn)擊插件開始運(yùn)行,彈窗關(guān)閉后結(jié)束,可以與background腳本交互。

基礎(chǔ)用法

1.創(chuàng)建manifest.json

任何插件都必須要有這個(gè)文件,用來(lái)描述插件的元數(shù)據(jù),插件的配置信息。

一個(gè)常用配置項(xiàng)如下:

{
// 必須
"manifest_version": 2,
"name": "插件名稱a",
"version": "1.1.2",

// 推薦
"default_locale": "en",
"description": "插件的描述",
"icons": {
 "16": "img/icon.png",   // 擴(kuò)展程序頁(yè)面上的圖標(biāo)
 "32": "img/icon.png",   // Windows計(jì)算機(jī)通常需要此大小。提供此選項(xiàng)可防止尺寸失真縮小48x48選項(xiàng)。
 "48": "img/icon.png",   // 顯示在擴(kuò)展程序管理頁(yè)面上
 "128": "img/icon.png"   // 在安裝和Chrome Webstore中顯示
},

// 可選
"background": {
 "page": "background/background.html",
 "scripts": ["background.js"],
 // 推薦
 "persistent": false
},
"browser_action": {
 "default_icon": "img/icon.png", 
 // 特定于工具欄的圖標(biāo),至少建議使用16x16和32x32尺寸,應(yīng)為方形,
 // 不然會(huì)變形
 "default_title": "懸浮在工具欄插件圖標(biāo)上時(shí)的tooltip內(nèi)容",
 "default_popup": "hello.html"   // 不允許內(nèi)聯(lián)JavaScript。
},
"content_scripts": [ {
 "js": [ "inject.js" ],
 "matches": [ "http://*/*", "https://*/*" ],
 "run_at": "document_start"
 } ],
"permissions": [
 "contextMenus",
 "tabs",
 "http://*/*",
 "https://*/*"
],
"web_accessible_resources": [ "dist/*", "dist/**/*" ]
}

上面的配置項(xiàng)看起來(lái)內(nèi)容較多,主要有以下幾項(xiàng):

  • 定義當(dāng)前插件的名字,描述版本號(hào)等信息。
  • "manifest_version":現(xiàn)在應(yīng)該總是2。
  • background
  • content_scripts
  • permissions:在background或是popup的js里使用一些chrome api,需要授權(quán)才能使用,例如要使用chrome.tabs.xxx的api,就要在permissions引入“tabs”

background、content_scripts的使用后面會(huì)詳細(xì)介紹

我們先使用如下基本信息

manifest.json

 {
    "name": "My QrCode",
    "description" : "My QrCode Extension",
    "version": "1.0",
    "manifest_version": 2,
   
    "browser_action": {
        "default_popup": "./popup.html", 
        "default_icon": "./logo.png"
    },
  }

2.新建popup.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
            <h2>hello world!</h2>
</body>
</html>

并找個(gè)png的圖作為logo

3.打包擴(kuò)展程序

現(xiàn)在我們就可以看下效果了。

打包擴(kuò)展程序:

打開chrome://extensions/,打開開發(fā)者模式,點(diǎn)擊打包擴(kuò)展程序,選擇我們的開發(fā)目錄

image-20200607172122923.png

注意:第一次打包的時(shí)候,會(huì)生成一個(gè)pem個(gè)人密鑰文件,以后再次打包的時(shí)候就需要密鑰文件了。

image-20200607163732018.png

4.加載已解壓的擴(kuò)展程序

image-20200607165136815.png

選擇剛剛打包出來(lái)的文件即可

現(xiàn)在我們就可以看到效果了:

image-20200607165437236.png

實(shí)現(xiàn)一個(gè)二維碼插件

在上面的基礎(chǔ)上,我們實(shí)現(xiàn)一個(gè)簡(jiǎn)單的當(dāng)前頁(yè)面生成二維碼插件:

popup.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script type="text/javascript" src="jquery.min.js"></script>
    <script type="text/javascript" src="qrcode.min.js"></script>
</head>
<body>
    <div id="qrcode"></div>
    <script type="text/javascript" src="popup.js"></script>
</body>
</html>

這里我們二維碼生成用了這個(gè)開源項(xiàng)目:
https://github.com/davidshimjs/qrcodejs

把項(xiàng)目中的jquery.min.js、qrcode.min.js拷過來(lái)

注意:

由于popup不允許內(nèi)聯(lián)JavaScript,因此需要script標(biāo)簽引入外部腳本

popup.js

let url;

chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
    url = tabs[0].url
    var qrcode = new QRCode(document.getElementById("qrcode"), {
        text: url,
        width: 256,
        height: 256,
        colorDark : "#000000",
        colorLight : "#ffffff",
        correctLevel : QRCode.CorrectLevel.M
    });
});

chrome.tabs.query()這部分用來(lái)獲取當(dāng)前頁(yè)面url

在manifest.json中加入允許:

{
    "name": "My QrCode",
        ...
    "permissions": ["activeTab"]
}

這樣,我們一個(gè)簡(jiǎn)單的生成二維碼插件就完成了

background

問題:
我們想在彈窗中寫一個(gè)計(jì)數(shù)器,每點(diǎn)擊一次加1。但發(fā)現(xiàn)Popup 彈窗無(wú)法記錄數(shù)據(jù)

實(shí)現(xiàn)代碼如下:

popup.html

    <input type="text" id="input" value="0">
    <button id="btn">+1</button>

popup.js

var count = 0;
$(function(){
    $('#input').val(count);
    $('#btn').click(function(){
        count = count+1;
        $('#input').val(count);
    });
})

當(dāng)我們點(diǎn)擊 “+1” ,輸入框中的數(shù)字就會(huì)增加,然后關(guān)閉彈窗,再點(diǎn)開,發(fā)現(xiàn)數(shù)字又變成了0,這說明當(dāng)我們關(guān)閉彈窗時(shí),popup.html就被銷毀了,我們?cè)?code>popup.js 中用count 存儲(chǔ)的全局變量,也被銷毀了。

解法:
由于popup在彈窗關(guān)閉后就銷毀了。如果想要在popup中記錄上次關(guān)閉后的結(jié)果的話,需要引入background

概念

background可以理解為插件運(yùn)行在瀏覽器中的一個(gè)后臺(tái)網(wǎng)站/腳本,注意它是與當(dāng)前瀏覽頁(yè)面無(wú)關(guān)的。
實(shí)際上這部分內(nèi)容的配置情況也會(huì)寫在manifest里,對(duì)應(yīng)的是background配置項(xiàng)。單獨(dú)拿出來(lái)講,是彰顯它的分量很重,也是一個(gè)插件常用的配置。從其中幾個(gè)配置項(xiàng)項(xiàng)去了解一下什么是background script

manifest.json

   "background": {
    "page": "background/background.html",
    "scripts": ["background.js"],
    // 推薦
    "persistent": false
   },

page

可以理解為這個(gè)后臺(tái)網(wǎng)站的主頁(yè),在這個(gè)主頁(yè)中,有引用的腳本,其中一般都會(huì)有一個(gè)專門來(lái)管理插件各種交互以及監(jiān)聽瀏覽器行為的腳本,一般都起名為background.js。這個(gè)主頁(yè),不一定要求有。

scripts

這里的腳本其實(shí)跟寫在page里html引入的腳本目的一樣,個(gè)人的理解是,page的html在沒有的情況下,那么腳本就需要通過這個(gè)屬性引入了;
如果在存在page的情況下,一般在這里引入的腳本是專門為插件服務(wù)的腳本,而那些第三方腳本如jquery還是在page里引用比較好,或許這是一個(gè)眾人的“潛規(guī)則”吧

persistent

所謂的后臺(tái)腳本,在chrome擴(kuò)展中又分為兩類,分別運(yùn)行于后臺(tái)頁(yè)面(background page)和事件頁(yè)面(event page)中。兩者區(qū)別在于,

前者(后臺(tái)頁(yè)面)持續(xù)運(yùn)行,生存周期和瀏覽器相同,即從打開瀏覽器到關(guān)閉瀏覽器期間,后臺(tái)腳本一直在運(yùn)行,一直占據(jù)著內(nèi)存等系統(tǒng)資源,persistent設(shè)為true;

后者(事件頁(yè)面)只在需要活動(dòng)時(shí)活動(dòng),在完全不活動(dòng)的狀態(tài)持續(xù)幾秒后,chrome將會(huì)終止其運(yùn)行,從而釋放其占據(jù)的系統(tǒng)資源,而在再次有事件需要后臺(tái)腳本來(lái)處理時(shí),重新載入它,persistent設(shè)為false。

保持后臺(tái)腳本持久活動(dòng)的唯一場(chǎng)合是擴(kuò)展使用chrome.webRequest API來(lái)阻止或修改網(wǎng)絡(luò)請(qǐng)求。webRequest API與非持久性后臺(tái)頁(yè)面不兼容。

popup與background的通信

popup與background的交流,常見于popup要獲取background里的某些“東西”

通信方式:

popup:

var bg = chrome.extension.getBackgroundPage();
bg.someMethod();    //someMethod()是background中的一個(gè)方法

實(shí)現(xiàn)一個(gè)計(jì)數(shù)器

對(duì)于計(jì)數(shù)器的例子來(lái)說:

manifest.json

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

background.js

var count = 0;

popup.js

var bg = chrome.extension.getBackgroundPage(); 
$(function(){
    $('#input').val(bg.count);
    $('#btn').click(function(){
        bg.count = bg.count+1;
        $('#input').val(bg.count);
    });
})

這樣,按鈕的點(diǎn)擊次數(shù)就可以記錄下來(lái)了

content script

概念

向符合條件的網(wǎng)頁(yè)插入該js腳本,對(duì)網(wǎng)頁(yè)做一些處理。它具有獨(dú)立而富有包容性。

  • 獨(dú)立,指它的工作空間,命名空間,域等是獨(dú)立的,不會(huì)說跟插入到的頁(yè)面的某些函數(shù)和變量發(fā)生沖突;

  • 包容性,指插件把自己的一些腳本(content script)插入到符合條件的頁(yè)面里,作為頁(yè)面的腳本,因此與插入的頁(yè)面共享dom的,即用dom操作是針對(duì)插入的網(wǎng)頁(yè)的,在這些腳本里使用的window對(duì)象跟插入頁(yè)面的window是一樣的。主要用在消息傳遞上(使用postMessage和onmessage)

配置也會(huì)寫在manifest里,對(duì)應(yīng)的是content_scripts配置項(xiàng)。

manifest.json

   "content_scripts": [ {
    "js": [ "inject.js" ],
    "matches": [ "http://*/*", "https://*/*" ],
    "run_at": "document_start"
    } ],

js

要插入到頁(yè)面里的腳本。例子很常見,例如在一個(gè)別人的網(wǎng)頁(yè)上,你要打開你做的擴(kuò)展,對(duì)別人的網(wǎng)頁(yè)做一些處理或者獲取一些數(shù)據(jù)等,那怎么跟別人的頁(yè)面建立起聯(lián)系呢?就是通過把js里的這些腳本嵌入都別人的網(wǎng)頁(yè)里。

matches

必需。匹配規(guī)則組成的數(shù)組,用來(lái)匹配頁(yè)面url的,符合條件的頁(yè)面將會(huì)插入js的腳本。當(dāng)然,有可以匹配的自然會(huì)有不匹配的——exclude_matches。匹配規(guī)則:

developer.chrome.com/extensions/…

run_at

js配置項(xiàng)里的腳本何時(shí)插入到頁(yè)面里呢,這個(gè)配置項(xiàng)來(lái)控制插入時(shí)機(jī)。有三個(gè)選擇項(xiàng):

  • document_start
  • document_end
  • document_idle(默認(rèn))

document_ start

style樣式加載好,dom渲染完成和腳本執(zhí)行前

document_end

dom渲染完成后,即DOMContentLoaded后馬上執(zhí)行

document_idle

在DOMContentLoaded 和 window load之間,具體是什么時(shí)刻,要視頁(yè)面的復(fù)雜程度和加載時(shí)間,并針對(duì)頁(yè)面加載速度進(jìn)行了優(yōu)化。

popup與content script通信

popup與content script通信 和 background與contentscript通信用法是一致的

發(fā)送消息:

chrome.runtime.sendMessege(
    message,
    function(response) {…}
)

第一個(gè)參數(shù)message為發(fā)送的消息(基礎(chǔ)數(shù)據(jù)類型),回調(diào)函數(shù)里的第一個(gè)參數(shù)為background接收消息后返回的消息(如有)

接受消息:

chrome.runtime.onMessege.addListener(
    function(request, sender, sendResponse) {…}
)

監(jiān)聽發(fā)來(lái)的消息,request表示發(fā)來(lái)的消息,sendResponse是一個(gè)函數(shù),用于對(duì)發(fā)來(lái)的消息進(jìn)行回應(yīng),如 sendResponse('我已收到你的消息:'+JSON.stringify(request));

這里需要注意的是,默認(rèn)情況下sendResponse函數(shù)的執(zhí)行是同步的,如果在這個(gè)監(jiān)聽消息的處理函數(shù)的同步執(zhí)行流程里沒有發(fā)現(xiàn)sendResponse,則默認(rèn)返回undefined,假設(shè)我們是要經(jīng)過一個(gè)異步處理之后才調(diào)用sendResponse,已經(jīng)為時(shí)已晚了。因此,我們可能需要異步執(zhí)行sendResponse,這時(shí)我們?cè)谶@個(gè)監(jiān)聽函數(shù)里的添加return true就能實(shí)現(xiàn)了。

實(shí)現(xiàn)一個(gè)搜索請(qǐng)求

實(shí)現(xiàn)一個(gè)向百度搜索框發(fā)送關(guān)鍵詞,并提交搜索請(qǐng)求。

這個(gè)功能其實(shí)沒什么用,主要是為了了解content_scripts和popup通信的流程

manifest.json

    "content_scripts": [
        {
            "matches": ["https://www.baidu.com/*"],
            "js": ["jquery.min.js","search-in-baidu.js"]
        }
    ],

上述配置表示當(dāng)頁(yè)面 url 地址匹配到 “https://www.baidu.com/*” 模式時(shí)才向頁(yè)面中注入jquery.min.js, search-in-baidu.js 兩個(gè)js 文件

一個(gè)插件里content-script有多個(gè)(一個(gè)頁(yè)面一個(gè)),那么怎么向特定的content-script發(fā)送消息?

首先我們需要知道要向哪個(gè)content scripts發(fā)送消息,一般一個(gè)頁(yè)面一份content scripts,而一個(gè)頁(yè)面對(duì)應(yīng)一個(gè)瀏覽器tab,每個(gè)tab都有自己的tabId,因此首先要獲取要發(fā)送消息的tab對(duì)應(yīng)的tabId。

/**
 * 獲取當(dāng)前選項(xiàng)卡id
 * @param callback - 獲取到id后要執(zhí)行的回調(diào)函數(shù)
 */
function getCurrentTabId(callback) {
    chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
        if (callback) {
            callback(tabs.length ? tabs[0].id: null);
        }
    });
}

當(dāng)知道了tabId后,就使用該api進(jìn)行發(fā)送消息

chrome.tabs.sendMessage(tabId, message, function(response) {...});

其中message為發(fā)送的消息,回調(diào)函數(shù)的response為content scripts接收到消息后的回傳消息

在我們這個(gè)需求中:

popup.js

$(function(){
    var state = $('#state');
    $('#send').click(function () {//給對(duì)象綁定事件
        chrome.tabs.query({active:true, currentWindow:true}, function (tab) {//獲取當(dāng)前tab
            //向tab發(fā)送請(qǐng)求
            chrome.tabs.sendMessage(tab[0].id, { 
                action: "send",
                keyword: $('#keyword').val()
            }, function (response) {
                console.log(response);
                state.html(response.state)
            });
        });
    });
    $('#submit').click(function () {
        chrome.tabs.query({active:true, currentWindow:true}, function (tab) {
            chrome.tabs.sendMessage(tab[0].id, {  
               action: "submit"   
            }, function (response) {
                state.html(response.state)
            });
        });
    })
})

search-in-baidu.js

var kw = $('#kw');
var form = $('#form');
chrome.runtime.onMessage.addListener(
    function (request, sender, sendResponse) {
        if (request.action == "send") {
            kw.val(request.keyword)
            sendResponse({state:'關(guān)鍵詞填寫成功!'});
        }
        if (request.action == "submit") {
            form.submit();
            sendResponse({state:'提交成功!'});
        }
    }
);

實(shí)現(xiàn)效果:

www.baidu.com中,使用插件,輸入想要搜索的關(guān)鍵詞,點(diǎn)擊發(fā)送->點(diǎn)擊提交,就查詢出來(lái)了。

image-20200607230601203.png

image-20200607230642078.png
image-20200607230655872.png

開發(fā)調(diào)試

image-20200607231951536.png
  • 開發(fā)過程中,如果有報(bào)錯(cuò),直接點(diǎn)擊錯(cuò)誤就能看到具體報(bào)錯(cuò)

  • 修改代碼后插件沒有自動(dòng)更新的話也可以手動(dòng)點(diǎn)擊刷新按鈕

  • popup調(diào)試:

    右鍵插件圖標(biāo),審查彈出內(nèi)容

image-20200607232711406.png
  • backgroud script調(diào)試:

    點(diǎn)擊背景頁(yè),就可以看到backgroud script進(jìn)行調(diào)試了,而且,還能在控制臺(tái)調(diào)用chrome api。請(qǐng)求也可以在這里看到。

  • content script調(diào)試:
    平常我們打開F12選擇到source選項(xiàng)的時(shí)候,一般都會(huì)顯示在"page"下,選擇content script,里邊的就是各個(gè)擴(kuò)展的內(nèi)容腳本了。

image-20200607232212373.png

總結(jié)

chrome擴(kuò)展開發(fā)入門還是比較容易的,主要有一下幾個(gè)基本概念

  • manifest.json
  • popup
  • background
  • content script

了解后在實(shí)際開發(fā)中查閱相關(guān)資料即可

參考

更詳細(xì)的popup、background、content script的通信方法可以看這篇:

一篇文章教你順利入門和開發(fā)chrome擴(kuò)展程序(插件)

其他:

谷歌(Chrome)瀏覽器插件開發(fā)教程

Chrome 擴(kuò)展開發(fā)教程(2) ——Background的用法

Chrome 擴(kuò)展開發(fā)教程(3)——content_scripts用法

官網(wǎng)教程:https://developer.chrome.com/extensions/getstarted

?著作權(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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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