Chrome 擴展crx開發


Chrome擴展提供的入口

  • 左鍵 crx,popup
  • 右鍵 crx,homelink + option
  • 右鍵上下文菜單

Chrome擴展的文件結構

Chrome擴展就是一個文件夾下包括一堆符合規范的文件。首先是清單文件manifest.json,指定了該擴展的整體布局和結構。實例:

    {
// 清單文件的版本,這個必須寫,而且必須是2
"manifest_version": 2,
// 插件的名稱
"name": "leocrx_demo",
// 插件的版本
"version": "0.1",
// 插件描述
"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": "this is browser_action.default_title",
    "default_popup": "popup.html",
    "badge":"這是badge"
},
// 當某些特定頁面打開才顯示的圖標
/*"page_action":
{
    "default_icon": "img/icon.png",
    "default_title": "我是pageAction",
    "default_popup": "page_action_popup.html"
},*/
// 需要直接注入頁面的JS
"content_scripts": 
[
    {
        //"matches": ["http://*/*", "https://*/*"],
        // "<all_urls>" 表示匹配所有地址
        "matches": ["<all_urls>"],
        // 多個JS按順序注入
        "js": ["js/hello_content.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":
[
"nativeMessaging",
    "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?homepage_url",
// 覆蓋瀏覽器默認頁面
//"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 js

manifest.json中的content script可以配置run_at為document_start表示DOM加載之前執行,或者document_end表示頁面DOM加載結束后執行,或者document_idle表示頁面空閑時加載。content script可以理解為向DOM注入js或者css的入口准備。

popup js是指在popup頁面中加載執行的js,邏輯上這個可以看做chrome://crx-id/這個server context下面的一個頁面,這個頁面chrome://crx-id/popup.html提供獨立的操作空間。

background js

在manifest.json中配置background,提供了chrome://crx-id/下面的另一個頁面chrome://crx-id/background.html,這個頁面是不顯示的,只是在后台運行,這是和popup.html頁面的唯一區別。我理解chrome提供這兩種頁面給開發者選擇,是因為有的開發者可能不不需要為crx最終客戶提供可見的popup頁面。從功能上面講,有了popup.html就可以實現所有的功能。

devtool js

這個主要是修改chrome調試部分的功能。訪問chrome api。

下面是總結的表格。

JS種類 可訪問的API DOM訪問情況 JS訪問情況 直接跨域 常見用法
injected script 和普通JS無任何差別,不能訪問任何擴展API 可以訪問 可以訪問 不可以 作為DOM的一部分,操作DOM
content script 只能訪問 extension、runtime等部分API 可以訪問 不可以 不可以 作為inject js的入口操作
popup js 可訪問絕大部分API,除了devtools系列 不可直接訪問 不可以 可以 操作popup DOM和chrome的API,擴展本身的數據管理
background js 可訪問絕大部分API,除了devtools系列 不可直接訪問 不可以 可以 操作bg DOM和chrome API,管理CRX本身的數據
devtools js 只能訪問 devtools、extension、runtime等部分API 可以 可以 不可以 devtools部分的修改

調試方法打開popup.html或者background.html所代表的頁面,右鍵審查元素

通信

background和popup通信

前文已經說過,這兩個頁面是一脈相承的,所以chrome為他們之間的代碼層面的訪問調用提供了簡單的方式。

    // popup.js
var bg = chrome.extension.getBackgroundPage();
bg.test(); // 訪問bg的函數
alert(bg.document.body.innerHTML); // 訪問bg的DOM

//bg.js
var views = chrome.extension.getViews({type:'popup'});
if(views.length > 0) {
    console.log(views[0].location.href);
}

bg和content之間通信

他們的js中收消息都是通過

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse))

發送的方式略有區別

//content js
chrome.runtime.sendMessage(msgjson, function(response) {
});

//bg js
chrome.tabs.query({active: true, currentWindow: true}, function(tabs)
{
    chrome.tabs.sendMessage(tabs[0].id, message, function(response)
    {
        if(callback) callback(response);
    });
});

content js和inject js, 其他

還有其他相關略去,參考https://www.cnblogs.com/liuxianan/p/chrome-plugin-develop.html#%E6%89%93%E5%8C%85%E4%B8%8E%E5%8F%91%E5%B8%83

chrome擴展自身數據存儲

通過HTML5的localStorage完成,chrome也有特殊的api,chrome.storage

API總結

  • chrome.tabs
  • chrome.runtime
  • chrome.webRequest
  • chrome.window
  • chrome.storage
  • chrome.contextMenu
  • chrome.devtools
  • chrome.extension

不支持內聯js

在popup.html和backgrou.html中不支持嵌入的js代碼,甚至定義標簽的onclick也不可以,只能在js中顯式綁定。

Chrome擴展與本地進程通信

chrome擴展crx提供的能力是:

本地程序向chrome注冊可以被那些crx調用和通信,注冊的方式是通過配置清單文件customizenamed.json:

{
    "allowed_origins" : [ "chrome-extension://fakmdcpkljckjjmemeninkejdibeiobe/" ],
    "description" : "Leo Test Native fire Native Message Host",
    "name" : "com.leo.test",
    //"path" : "C:\\ProgramFiles\\Python27\\python.exe",
    //"path" : "C:\\Users\\leo\\source\\repos\\ConsoleApp1\\ConsoleApp1\\bin\\Debug\\ConsoleApp1.exe",
     "path" : "C:\\D\\dist\\leonative.exe",
     //必須是stdio
    "type" : "stdio"
}

其中的kv含義顯而易見,主要是定義了path指定的可執行文件可以被那些crx調用和通信。
chrome如何找到這個json文件並load? chrome約定了兩種實現

  • windows平台,在注冊表中添加key,HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Google\Chrome\NativeMessagingHosts\ com.leo.test,value為json的路徑
  • POSIX平台,把json文件放置到特定路徑/etc/opt/chrome/native-messaging-hosts/下,文件名為com.leo.test.json

這樣chrome通過load文件customizenamed.json,可以找到需要啟動的本地可執行程序。

與本地進程通信的協議

本地程序需要是專用的程序。
因為chrome啟動本地程序的時候,傳入的啟動args是固定的:

[arg 0]  chrome-extension://fakmdcpkljckjjmemeninkejdibeiobe/
[arg 1] --parent-window=1057900

真正的啟動命令可能是yourexecutable chrome-extension://fakmdcpkljckjjmemeninkejdibeiobe/ --parent-window=1057900

啟動后,chrome(實際上應該是crx對應的進程)向本地進程yourexecutable的stdin寫入消息,從其stdout讀取消息,完成crx和本地進程之間的通信。

本地進程通信消息協議

crx與本地通信的消息協議參見 https://developer.chrome.com/apps/nativeMessaging#native-messaging-host-protocol

要點是,消息的頭部插入4byte標記消息字節數,意味着一條消息不可能超過4GB,而從native進程發送到crx的消息則規定不超過1MB。
本地進程通過args知道自己是本crx啟動的,開始從stdin讀取4byte,轉為int,讀取后續消息。

//bg.js
//connect to native host and get the communicatetion port
function connectToNativeHost()
{
    var msg = 'hello msg'
    var nativeHostName = "com.leo.test";
    console.log(nativeHostName);
    port = chrome.runtime.connectNative(nativeHostName);
    port.onMessage.addListener(onNativeMessage);
    port.onDisconnect.addListener(onDisconnected);
    port.postMessage(msg);
 }

可執行文件

customizenamed.json中指定的可執行文件不可以是.py腳本源文件,而必須是一個exe文件,因為實際上執行.py文件的cmd是 python xx.p。而chrome應該是通過win32的CreateProcess啟動本地進程,構造cmd作為參數傳遞給該API,如果是一個.py源文件,不符合win32可執行文件格式。

workaround方案:通過pyinstaller把py程序打包成一個win32的可執行exe文件。

由於linux上ld對腳本第一行#!的直接支持,可能在Linux上面是可以指定.py文件的。
實驗驗證:

  • Linux可以通過#!識別腳本這是一個可執行文件,這是系統層ld-*.so加載鏈接器提供的支持。

使用場景

本地App需要提供crx支持,那么安裝App的時候需要部署com.leo.test.json文件(Linux平台)或者添加注冊表Key-Value指定json文件路徑(Windows平台)。
客戶安裝crx即可按預定方案調用App。

如果crx需要本地App支持,稍微復雜,需要倒逼客戶安裝App,這種方式也可以,但是基本不是很現實的場景。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM