寫chrome插件前必需要知道的

介紹

瀏覽器插件本質上就是利用前端的html\css\javascript等技術,借用瀏覽器對外提供的API,實現各類不一樣的功能javascript

插件組成

首先先看一下咱們要開發的插件的各個文件組成css

manifest.json :咱們在項目的根文件必需要有一個命名爲manifest.json的文件,它是整個插件的功能入口,用來告訴瀏覽器插件的一些基本信息,及須要加載和執行的資源文件等,裏面包含一些必填項:html

  • name 插件的名字
  • version 插件版本
  • manifest_version manifest的版本
  • description 插件的描述(選填)
{
    "name": "hello extension",
    "description": "Base Level Extension",
    "version": "1.0",
    "manifest_version": 2,
}
複製代碼
  • icons 在擴展程序管理界面,呈現的圖標,能夠設置不一樣的尺寸的選項,用來適配不一樣的場景
{
    "icons": {
        "16": "images/extension_icon16.png",
        "32": "images/extension_icon32.png",
        "48": "images/extension_icon48.png",
        "128": "images/extension_icon128.png"
      },
}
複製代碼
  • background 在擴展程序被開啓時,會首先觸發執行background 選項中指定的js資源,而且一直存在於擴展程序的整個生命週期,直到擴展程序被關閉或者刪除,background一直被用來作任務和狀態的控制管理工做
// scripts 子選項指定了須要執行的js文件的路徑及文件名
{
    "background": {
        "scripts":["background.js"],
        "persistent": false
    }
}
複製代碼

background.js 一般最外層使用監聽事件chrome.runtime.onInstalled.addListener(()=>{})初始化插件,監聽插件安裝成功後,會觸發對應的邏輯開始工做前端

  • permissions 屬性值爲一個數組,申請chrome API的權限,只有在這個選項中申請了才能使用(好比經過 XMLHttpRequest 跨域請求數據、訪問瀏覽器選項卡(tabs)、獲取當前活動選項卡(activeTab)、瀏覽器通知(notifications)、設置插件激活規則(declarativeContent)、相似localStorage的存儲(storage)等)
{
    "permissions": [
        "http://xxx.com/api"
        "tabs",
        "activeTab",
        "notifications",
        "declarativeContent",
        "storage"
    ],
}
複製代碼

與用戶實現UI交互的功能主要有兩個:browser_action、page_action 二者選擇其中一個

  • browser_action 提供的功能面向全部網站,插件圖標一直是激活的狀態
    {
        "browser_action": {
          "default_popup": "popup.html"        // 指定click插件圖標時,展現的頁面
          "default_icon": "images/icon.png", // 指定瀏覽器工具欄展現的插件的圖標 
          "default_title": "display tooltip" // 當鼠標懸浮在插件圖片上方時,展現的文字,叫tooltip;若是沒有這個配置選項,則懸浮時顯示menifest.json中的name選項值
      }
    }
    複製代碼
  • page_action 只針對對應目標網站提供的功能,插件會在background頁設置激活插件的規則,只有知足條件的網頁的插件纔是激活的,其餘網站插件是不可用的,插件的icon是灰的
    background script裏,chrome.runtime.onInstalled.addListener(()=>{})初始化中使用chrome.declarativeContent定義插件被激活的規則
    {
        "page_action":{
            "default_popup": "popup.html", // 指定click插件圖標時,展現的頁面
            "default_icon": "hello_extension.png" // 指定瀏覽器工具欄展現的插件的圖標 
            "default_title": "display tooltip"
    },
    }
    複製代碼
    chrome.runtime.onInstalled.addListener(function() {
        // Replace all rules ...
        chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
        // With a new rule ...
        chrome.declarativeContent.onPageChanged.addRules([
            {
            // That fires when a page's URL contains a 'g' ...
            conditions: [
                new chrome.declarativeContent.PageStateMatcher({
                pageUrl: { urlContains: 'g' }, //url的內容中包含字母g的,插件纔會被激活
                })
            ],
            // And shows the extension's page action.
            actions: [ new chrome.declarativeContent.ShowPageAction() ]
            }
        ]);
        });
    });
    複製代碼

popup.html

popup.html 是使用browser_action或者page_action 指定的default_popup選項,表示點擊插件圖標會觸發的html資源,其與普通的html頁面的區別就是不能使用內聯script,其餘都同樣 it can contain links to stylesheets and script tags, but does not allow inline JavaScript.java

Content Script 對當前web頁面注入擴展程序代碼,也就是在當前web頁面的上下文環境中,能夠訪問頁面的DOM信息而且修改DOM,具備操做Chrome API的權限,而且能夠把信息傳遞給父級插件

  1. content script工做在一個獨立的空間,它使得不會訪問和調用web page或者其餘content script中定義的變量和函數,二者惟一共享的是DOM
  2. Content Script與Page action 或Browser action通訊的方式是經過傳遞Message的方式,正確的機制應該是:
    • Page action 或Browser action 中的js使用chrome.tabs.sendMessage()發佈一個請求信息,傳遞出去當前的tab頁id及其餘信息
    • 注意:從Page action 或Browser action發佈消息到Content Script必須用chrome.tabs.sendMessage(),從Content Script發佈簡單的信息到Page action 或Browser action 可使用chrome.runtime.sendMessage()
    chrome.tabs.sendMessage(
         tabs[0].id, //當前激活的tab頁id
         {greeting: "hello"}, //須要傳遞的信息
         function(response) { //用來接收反饋的回調函數
         console.log(response.farewell);
     });
    複製代碼
    • Content Script完成初始化,設置chrome.runtime.onMessage().addListener()監聽事件,等待另外一側請求信息的發佈
    chrome.runtime.onMessage.addListener(
     function(request, sender, sendResponse) {
         console.log(sender.tab ?
                     "from a content script:" + sender.tab.url :
                     "from the extension");
         if (request.greeting == "hello")
         sendResponse({farewell: "goodbye"});
     });
    複製代碼
    • Content Script將信息經過Message發佈訂閱的方式,發佈出去
    • Page action 或Browser action 中的jschrome.tabs.sendMessage()最後一個參數是一個回調函數,用來接收另外一側反饋回來的數據,最後同步到UI上
chrome.tabs.sendMessage()
複製代碼
  1. Content script有兩種注入方式:編程式動態注入、聲明式注入jquery

  2. 編程式動態注入:獲取activeTab權限後,使用chrome.tabs.executeScript()來注入js代碼片斷,使用chrome.tabs.insertCSS()注入css代碼片斷web

    //manifest.json
     {
       "name": "My extension",
       ...
       "permissions": [
         "activeTab"
       ],
     }
    複製代碼
在Page action 或Browser action 中的js中實行編程式動態注入content script,其訪問和更改的就是web page上的DOM屬性

```js
chrome.runtime.onMessage.addListener(
  function(message, callback) {
    if (message == 「changeColor」){
      chrome.tabs.executeScript({
        code: 'document.body.style.backgroundColor="orange"'
      });
    }
 });
 // 你也能夠注入一個文件
 chrome.runtime.onMessage.addListener(
  function(message, callback) {
    if (message == 「runContentScript」){
      chrome.tabs.executeScript({
        file: 'contentScript.js'
      });
    }
 });
複製代碼
  1. 聲明式注入,在manifest.json中使用content_scripts來定義
{
      "name": "My extension",
      ...
      "content_scripts": [
      {
          "matches": ["http://*.nytimes.com/*"],
          "css": ["myStyles.css"],
          "js": ["contentScript.js"]
      }
      ],
      ...
  }
複製代碼
  • matches:必填 數組,用來匹配注入Content Script的頁面地址。可使用通配符來指代:'*'指代任意長度字符;'?'指代單個字符
  • css:選填 數組,在頁面的任何DOM建立和展現以前,按照數組中定義的順序,依次注入
  • js:選填 數組,按照數組中定義的順序,依次注入
  • run_at:Content Script注入的時機
    • 若是是document_start, 文件將在全部CSS加載完畢,可是沒有建立DOM而且沒有運行任何腳本的時候注入
    • 若是是document_end,則文件將在建立完DOM以後,但尚未加載相似於圖片或frame等的子資源前馬上注入
    • 若是是document_idle,瀏覽器會在document_end和發出window.onload事件之間的某個時機注入。具體的時機取決與文檔加載的複雜度,爲加快頁面加載而優化
{
    "content_scripts" : [{
      "matches" : ["*://*/*"],
      "js" : ["content.js", "jquery.js"],
      "css" : ["style.css"],
      "run_at" : "document_end"
  }],
}
複製代碼
  • options_page 設置插件的選項頁面,配置了此選項後,在插件上鼠標右鍵時,會有一個‘選項’按鈕,點擊後會進入options_page對應的頁面chrome

    {
        "options_page":"options.html"
    }
    複製代碼

  • chrome_url_overrides 設置可替換的chrome默認頁面編程

    • newtab:新建標籤時打開的頁面
    • bookmarks:書籤頁面
    • history:歷史記錄
    {
        "chrome_url_overrides":{
          "newtab": "newTab.html"
      }
    }
    複製代碼

經常使用到的Chrome API

chrome.tabs

  1. chrome.tabs.create(object createProperties, function callback) 建立新的標籤。注: 無需請求manifest的標籤權限,此方法也能夠被使用。 Parameters createProperties ( object )json

    • windowId ( optional integer ) 建立新標籤的目標窗口。默認是當前窗口 。
    • index ( optional integer ) 標籤在窗口中的位置。 值在零至標籤數量之間。
    • url ( optional string ) 標籤導航的初始頁面。完整的URL 必須包含一個前綴 (如 'www.google.com', 不能寫爲 'www.google.com')。 相對 URL則與擴展所在的頁面相對, 默認值爲新標籤頁面。
    • selected ( optional boolean ) 標籤是否成爲選中標籤。默認爲true。
    • pinned ( optional boolean ) 標籤是否被固定。默認值爲false。
    • callback ( optional function )

    Callback function 回調 參數 應該以下定義:

    function(Tab tab) {...}; tab ( Tab ) 所建立的標籤的細節,包含新標籤的ID。

  2. chrome.tabs.executeScript(integer tabId, object details, function callback) 向頁面注入JavaScript 腳本執行 Parameters

    1. tabId ( optional integer ) 運行腳本的標籤ID;默認爲當前窗口所選中的標籤。
    2. details ( object ) 要執行的腳本內容,可選code或者file,但不能同時選二者。
      • code ( optional string ) 要執行的腳本代碼。
      • file ( optional string ) 要執行的腳本文件。
      • allFrames ( optional boolean ) true的時候,給全部frame執行腳本。默認爲false,只給頂級frame執行腳本。
    3. callback ( optional function ) 全部腳本執行後會被調用的回調。
  3. chrome.tabs.query(object queryInfo, function callback) 獲取通過特定過濾條件篩選的標籤頁信息,若是沒有特定過濾條件則是獲取全部標籤頁信息

    1. queryInfo 爲特定的屬性,用來對標籤頁進行過濾。 經常使用的屬性有:(全部屬性均爲boolean值)

      • active 標籤在他們的窗口中是不是激活狀態
      • currentWindow 標籤是否在當前窗口
      chrome.tabs.query({
              active:true,
              currentWindow:true
          },function(tabs){
              //...
          })
      複製代碼
    2. callback 是獲取到特定標籤頁信息後的回調函數,參數爲標籤的信息

chrome.contextMenus 當前頁面,選中內容後右鍵展現的內容

  1. 在manifest.json中設置權限{"permissions": ["contextMenus", "storage"]}
  2. 放在background.js中,初始化以後的回調函數中,使用chrome.contextMenus.create({})建立內容目錄
    chrome.runtime.onInstalled.addListener(function() {
     //...
         chrome.contextMenus.create({
             "id": "sampleContextMenu",
             "title": "Sample Context Menu",
             "contexts": ["selection"]
         });
     });
    複製代碼

插件安裝

  1. 進入擴展程序管理界面 chrome://extensions
  2. 開啓'開發者模式'
  3. 能夠選擇'加載已解壓的擴展程序',將本地開發目錄上傳上去便可
  4. 可使用'打包擴展程序',生成.ctx後綴的擴展程序,就能夠發佈到google應用市場了

插件調試

注意:

  • 每次刷新頁面,都會執行browser_action或page_action 指定的popup.html資源
  • background指定的js資源只在插件安裝時執行,以後就一直存在進程中,不會重複執行

調試步驟

  1. 在瀏覽器工具欄右鍵插件圖標
  2. 點擊'審查彈出內容',進入控制檯
  3. 切換到Source欄,便可看到browser_action或page_action 指定的資源,設置斷點
  4. 切換到Console欄,輸入location.reload(),發現原有的頁面從新進行了加載,同時browser_action或page_action 指定的資源也從新執行了一遍,並在設置的斷點處停下來,等待debug

參考連接

chrome擴展程序
如何從零寫一個Chrome擴展

相關文章
相關標籤/搜索