每個(gè)瀏覽器都有其自己的粉絲、批評(píng)者、優(yōu)勢(shì)和劣勢(shì)。它們的共同點(diǎn)是人們將越來越多的時(shí)間花費(fèi)于其中。本系列文章將介紹如何為 Chrome、Firefox、Internet Explorer 和 Safari 構(gòu)建一個(gè)瀏覽器擴(kuò)展。您可以為每個(gè)瀏覽器構(gòu)建相同的基礎(chǔ)擴(kuò)展,感受擴(kuò)展每個(gè)瀏覽器是什么樣子,執(zhí)行這些常見任務(wù)是困難還是簡(jiǎn)單,以及發(fā)布您的擴(kuò)展會(huì)涉及到什么。在本文中,您將構(gòu)建一個(gè) Chrome 擴(kuò)展。
開始之前
對(duì)于本文,您需要下載和安裝 Google Chrome V19 或更高版本(本文示例是基于 V19 的)。您也需要一些可以編輯 HTML、CSS 和 JavaScript 的工具。如果您有使用 Chrome 或者 Chrome 擴(kuò)展的經(jīng)驗(yàn)將會(huì)很有幫助的。花一點(diǎn)時(shí)間瀏覽 Chrome Web Store(請(qǐng)參閱?參考資料)。看看提供的擴(kuò)展并先行試用一番,這將為本文提供一些相關(guān)背景。
為什么構(gòu)建瀏覽器擴(kuò)展?
您想要構(gòu)建一個(gè)瀏覽器擴(kuò)展有幾個(gè)原因,瀏覽器擴(kuò)展的常見應(yīng)用是在一個(gè)瀏覽器和另一應(yīng)用程序或服務(wù)之間創(chuàng)建一個(gè)交互。Evernote、1Password 和 Adobe Shadow 都是這樣做的,就像許多其他擴(kuò)展一樣。或者,您想要將一些新功能添加到缺乏該功能的瀏覽器,通過添加開發(fā)人員工具或者屏幕截圖實(shí)用程序即可。有些開發(fā)人員編寫具有專門用途的擴(kuò)展,如體育得分追蹤器、特定網(wǎng)站增強(qiáng)和天氣預(yù)報(bào)等。人們可以使用擴(kuò)展做很多不同事情。您要做什么呢?
您要構(gòu)建什么擴(kuò)展?
要在 Chrome 中演示構(gòu)建擴(kuò)展流程,需要編寫一個(gè)名為 Gawkblocker 的擴(kuò)展。Gawkblocker 將允許您鎖定某些您出于各種原因試圖不去訪問的域。Gawkblocker 包含以下組件:
- 一個(gè)彈出窗口(顯示您將要鎖定的域)
- 一個(gè)可見瀏覽器圖標(biāo)(擴(kuò)展入口點(diǎn))
- 一個(gè)選項(xiàng)頁面(配置您想要鎖定以及您想要訪問的域)
一般來說,Gawkblocker 將為每個(gè)選項(xiàng)卡或窗口附加一個(gè)監(jiān)聽器,當(dāng)選項(xiàng)卡 URL 發(fā)生變化時(shí),擴(kuò)展將比較 URL 和鎖定域列表。如果 URL 與一個(gè)鎖定域匹配,請(qǐng)求將被重定向到一個(gè)擴(kuò)展頁面(參見?圖 1)。
圖 1. Gawkblocker 擴(kuò)展
Gawkblocker 以特定的方式擴(kuò)展至瀏覽器,來進(jìn)行一些將在其他擴(kuò)展中進(jìn)行的特定工作。您需要回答這些問題:
- 在瀏覽器 UI 中擁有一席之地有多難?
- 在瀏覽器會(huì)話之間持久化數(shù)據(jù)涉及到什么?
- 不同擴(kuò)展部分彼此如何通信?
- 您對(duì)用戶數(shù)據(jù)的研究有多深入?
構(gòu)建 Gawkblocker 的流程應(yīng)該可以回答這些問題。
您的參考文檔是什么?
您的參考文檔是 Chrome Extension docs(參閱?參考資料)。編寫 Chrome 擴(kuò)展的大部分文檔是非常全面的,一個(gè)關(guān)于如何構(gòu)建 “Hello World” 的簡(jiǎn)單單頁教程將為您提供有關(guān)如何組合擴(kuò)展的超級(jí)簡(jiǎn)單概述,但是不太適用于深入研究該主題的人員。
Chrome 擴(kuò)展剖析
一個(gè)典型 Chorme 擴(kuò)展由一個(gè)清單文件和一些背景頁面、UI 頁面和內(nèi)容腳本組合而組成。
每一個(gè)均是以一個(gè)清單文件 manifest.json 開始。該文件包含 Chrome 需要了解如何加載您擴(kuò)展的信息,如標(biāo)題、描述、所需權(quán)限和圖標(biāo)引用。
背景頁面是一個(gè)在其自己上下文中啟動(dòng)并運(yùn)行的單一頁面,無論打開多少個(gè)選項(xiàng)卡或窗口。一個(gè)擴(kuò)展只能有一個(gè)背景頁面。對(duì)于想要一個(gè)進(jìn)程以在 Chorme 所有頁面中運(yùn)行持久化的擴(kuò)展來說,它們是很有用的。
UI 頁面指的是擴(kuò)展呈現(xiàn)給用戶的任何頁面。UI 頁面可能是一個(gè)彈出窗口、一個(gè)選項(xiàng)頁面、一個(gè)部分?jǐn)U展頁面、或者一個(gè)覆蓋默認(rèn) Chrome 頁面(如新選項(xiàng)卡?頁面)。
內(nèi)容腳本是您添加到 Web 頁面進(jìn)行交互的 JavaScript 文件。內(nèi)容腳本在其自己獨(dú)立的上下文中執(zhí)行,但是它們可以訪問頁面的 DOM。內(nèi)容腳本也可使用一個(gè)特定消息傳遞 API 與擴(kuò)展中的其他頁面進(jìn)行通信。
對(duì)于 Gawkblocker,您將使用一個(gè)清單文件、一個(gè)包含某些核心功能的 JavaScript 文件(便于攜帶的一些東西)、一個(gè)背景頁面、一個(gè)選項(xiàng)頁面、一個(gè)彈出窗口、一個(gè)重定向登錄頁面和一個(gè)或兩個(gè)圖標(biāo)。如果您想看看活動(dòng)的擴(kuò)展是否如上所述,可以從 Chrome Web Store 下載一個(gè)運(yùn)行中的 Gawkblocker 擴(kuò)展。
Gawkblocker 清單文件
清單 1?是 Gawkblocker 的 manifest.json 文件的一個(gè)副本
清單 1. Gawkblocker 的 manifest.json 文件
{ "name": "GawkBlocker", "version": "1.7", "description": "Tired of taking the Nerd Bait? Use GawkBlocker!", "background_page" : "background.html", "options_page": "options.html", "icons": { "16" : "images/GB-19.png", "48" : "images/GB-48.png", "128" : "images/GB-128.png" }, "browser_action": { "default_icon": "images/GB-19.png", "default_title": "GawkBlocker", "default_popup": "popup.html" }, "permissions": ["tabs"] }
詳細(xì)看看這些條目。
- version
- 當(dāng)您上傳一個(gè)新版本擴(kuò)展到 Chrome Web Store 時(shí),需要增加版本號(hào),否則會(huì)上傳失敗。
- icon
- 圖標(biāo)屬性包含一個(gè)可用圖標(biāo)列表,按大小排列。Chrome 尋找特定大小的圖標(biāo)以在不同的上下文中使用。清單 1?指定與擴(kuò)展相關(guān)的圖標(biāo)文件路徑。
- browser_action
- 當(dāng)您指定一個(gè) browser_action 時(shí),將告訴 Chrome 您想要將一個(gè)圖標(biāo)放在 URL 欄右邊(Chrome 將該 URL 稱之為 Omnibar),單擊圖標(biāo)將執(zhí)行某一操作。在本例中,單擊瀏覽器活動(dòng)按鈕將打開一個(gè)彈出窗口。
當(dāng)您的擴(kuò)展應(yīng)用于任何 Web 頁面時(shí),只需要指定一個(gè) browser_action。如果您想要一個(gè)備選方案,僅適用于特定頁面或特定類型的頁面,那么指定一個(gè) page_action。不能同時(shí)指定 page_action 和 browser_action,只能選擇其中一個(gè)。 - permissions
- 在此用例中,您需要請(qǐng)求的惟一權(quán)限是 ‘選項(xiàng)卡’,該權(quán)限將為您提供一些關(guān)于單個(gè)選項(xiàng)卡的信息(您真正需要的是 URL)。這里提供了很多權(quán)限,但是您只能請(qǐng)求您需要的權(quán)限。Chrome 和 Android 處理權(quán)限的方式非常類似,在用戶安裝您的擴(kuò)展時(shí),Chrome 會(huì)明確顯示擴(kuò)展所請(qǐng)求的權(quán)限,而在安裝 Android 應(yīng)用程序時(shí)幾乎以相同的方式向您提示一列權(quán)限。
現(xiàn)在您已經(jīng)了解了該清單,接下來我們看看為 Gawkblocker 提供功能的文件。
Gawkblocker 核心類
大多數(shù) Gawkblocker 所做的一切都是由單個(gè)核心 JavaScript 文件控制的。在該文件中,您可以定義一個(gè) Storage Manager 對(duì)象 (SM) 來處理會(huì)話間的持久化數(shù)據(jù)(現(xiàn)在對(duì)于?localStorage
?來說這只是一個(gè)包裝器),和一個(gè)處理常見功能(管理鎖定站點(diǎn)列表和選項(xiàng))的 Gawkblocker 對(duì)象 (GB)。請(qǐng)參見?清單 2。
清單 2. 定義一個(gè) Storage Manager 對(duì)象和 Gawkblocker 對(duì)象
var SM = (function () { var my = {}; my.get = function (key) { return localStorage.getItem(key); } ... return my; }()); var GB = (function (SM) { var my = {}; my.blockTheseSites = { "gawker.com" : "Gawker Media", "io9.com" : "SciFi Blog", "gizmodo.com" : "Gadget Blog", ... } if (!SM.get("blocklist")) { SM.put("blocklist", JSON.stringify(my.blockTheseSites)); } my.getBlockedSites = function () { return JSON.parse(SM.get("blocklist")); } my.setWatchThisInstead = function (value) { ... } my.getWatchThisInstead = function () { return SM.get("instead"); } my.addBlockedSite = function (site) { my.blockedSites = JSON.parse(SM.get("blocklist")); my.blockedSites[site] = "Custom Add"; SM.put("blocklist", JSON.stringify(my.blockedSites)); } my.removeBlockedSite = function (site) { my.blockedSites = JSON.parse(SM.get("blocklist")); delete my.blockedSites[site]; SM.put("blocklist", JSON.stringify(my.blockedSites)); } return my; }(SM));
這里,我使用 Module Patten 創(chuàng)建一對(duì)相當(dāng)便攜的對(duì)象。現(xiàn)在看看在背景頁面中怎樣使用它們。
背景頁面
Gawkblocker 將使用背景頁面監(jiān)聽 URL 并將它們與鎖定站點(diǎn)列表進(jìn)行比較。記住,您只能有一個(gè)背景頁面實(shí)例,它是供所有打開的選項(xiàng)卡和窗口共享(不包括 incognito 窗口、除非您請(qǐng)求該權(quán)限或者用戶明確允許)。因?yàn)楸尘绊撁姹旧頉]有可見組件,其頁面上也沒有顯示相關(guān)的 HTML。
清單 3?顯示監(jiān)聽更新選項(xiàng)卡的代碼。
清單 3. 監(jiān)聽更新選項(xiàng)卡
chrome.tabs.onUpdated.addListener(function(tabId, changedInfo, tab) { for (site in GB.getBlockedSites()) { if (tab.url.match(site)) { chrome.tabs.update(tabId, {"url" : GB.getWatchThisInstead()},function () {}); } } });
這里有更高效的方法來遍歷鎖定站點(diǎn)列表,但是這并不是您應(yīng)該關(guān)注的。相反,看看如何使用?chrome.tabs.onUpdated.addListener
?附加到 Chrome 上,以及在一個(gè)回調(diào)函數(shù)中傳遞。
每個(gè) chrome.* API 調(diào)用都不同,但一般來說它們均遵守此模式,即調(diào)用一個(gè)方法以及在回調(diào)函數(shù)中傳遞。多數(shù) API 調(diào)用是異步的。這可能會(huì)導(dǎo)致計(jì)時(shí)問題,如果您不希望出現(xiàn)這種行為,閱讀關(guān)于該主題的參考文檔。
彈出窗口
Gawkblocker 并不真的需要一個(gè)彈出窗口,但是包括一個(gè)彈出窗口的話,可以為用戶提供一個(gè)方便的地方來查看當(dāng)前處于鎖定狀態(tài)的站點(diǎn)。
清單 4. 彈出頁面
$(document).ready(function(){ $.each(chrome.extension.getBackgroundPage().GB.getBlockedSites(), function (index, value) { $("#blockedlist").append("<div class='siterow' title='"+value+"'> <div class='sitename'>"+index+"</div><span class='sitedesc'> : "+value+"</span></div>"); } ); });
對(duì)?chrome.extension.getBackgroundPage().GB.getBlockedSites()
?的調(diào)用是實(shí)現(xiàn)從背景頁面獲取信息并在彈出頁面顯示的方法。這是處理擴(kuò)展中頁面間通信的一種方法,盡管在彈出窗口中沒必要這樣做。您可能想要包括 gawkblocker.js 文件,并直接調(diào)用 GB 對(duì)象。但是如果有很多異步活動(dòng),使用不同組件從相同地方提問是很有用的。
彈出窗口詢問背景頁面要求提供一個(gè)鎖定站點(diǎn)列表。然后它會(huì)遍歷該列表,并且將鎖定站點(diǎn)細(xì)節(jié)添加到彈出窗口的顯示 div 中(參見?圖 2)。
圖 2. 彈出窗口
選項(xiàng)頁面
您需要一個(gè)地方來控制擴(kuò)展行為。如果您使用清單指定一個(gè)選項(xiàng)頁面(正如您所做的),用戶就可以輕易地從擴(kuò)展管理頁面或者右鍵單擊瀏覽器活動(dòng)按鈕進(jìn)行訪問。選項(xiàng)頁面本身也是可選的(參見?圖 3)。
圖 3. 選項(xiàng)頁面
Gawkblocker 使用選項(xiàng)頁面支持用戶在訪問鎖定站點(diǎn)時(shí)指定行為、添加新站點(diǎn)到鎖定列表、或者從鎖定列表徹底刪除站點(diǎn)(參見?清單 5)。
清單 5. 選項(xiàng)頁面
$("#blockthistoo").click(function () { GB.addBlockedSite($("#dontgothere").val()); ... });
您可以仔細(xì)檢查背景頁面,就像檢查彈出窗口那樣(參見?清單 6)。
清單 6. 背景頁面
$("#blockthistoo").click(function () { chrome.extension.getBackgroundPage().GB.addBlockedSite($("#dontgothere").val()); ... });
您可能偏愛其中一個(gè)方法,具體取決于您的擴(kuò)展。
重定向登錄頁面
最后,當(dāng)重定向一個(gè)請(qǐng)求時(shí),需要轉(zhuǎn)到一個(gè)本地頁面。該頁面是所有頁面中最簡(jiǎn)單的。正如所寫的那樣,它只是一個(gè)嵌入 YouTube 視頻的頁面 (“Hey You! Don’t Watch That! Watch This!”)。它并不與其余擴(kuò)展以任何有意義的方式進(jìn)行交互,它只是該流程的終點(diǎn)(參見?圖 4)。
圖 4. 重定向登錄頁面
整合起來
現(xiàn)在,您已經(jīng)有了一個(gè)強(qiáng)大的擴(kuò)展,但是該如何對(duì)其進(jìn)行測(cè)試呢?首先,加載未包裝它們的擴(kuò)展文件。這被稱之為加載一個(gè)未打包擴(kuò)展,而且您可以從 Extension Managemen 頁面對(duì)其進(jìn)行控制(參閱?參考資料)(您也可以右鍵單擊任何已安裝的擴(kuò)展并選擇?Manage Extensions)。
要加載未包裝的擴(kuò)展,選擇?Developer Mode?以啟動(dòng)?Load unpacked extension?按鈕。要加載您的擴(kuò)展,單擊?Load unpacked extension?按鈕并導(dǎo)航到包含該擴(kuò)展的文件夾。如果您的清單文件有一個(gè)錯(cuò)誤,您的擴(kuò)展可能被禁用或者無法加載。如果是這樣的話,Chrome 將會(huì)告訴您。
一旦確定您的擴(kuò)展已準(zhǔn)備就緒,將有 2 個(gè)不同選擇供您發(fā)布擴(kuò)展。您可能會(huì)發(fā)布原始文件,但用戶將無法安裝此擴(kuò)展,除非他們也進(jìn)入擴(kuò)展管理頁面并啟用開發(fā)人員模式。另一個(gè)選擇是發(fā)布一個(gè)已包裝擴(kuò)展,或者將您的擴(kuò)展放入 Chrome Web Store。
發(fā)布一個(gè)已包裝擴(kuò)展
在擴(kuò)展管理頁面,挨著 Load unpacked extension 按鈕的是一個(gè)?Pack extension?按鈕(參見?圖 5)。單擊該按鈕啟動(dòng)包裝發(fā)布擴(kuò)展流程。Chrome 將向您詢問未包裝擴(kuò)展的目錄,也可以選擇一個(gè)私有密鑰文件。隨后將對(duì)該私有密鑰文件進(jìn)行討論。
圖 5. 擴(kuò)展管理頁面
第一次包裝擴(kuò)展時(shí),Chrome 將生成兩個(gè)文件:一個(gè) .crx 文件和一個(gè) .pem 文件。.crx 文件是您的包裝擴(kuò)展,包含所有準(zhǔn)備發(fā)布的文件。.pem 文件是上面提到的私有密鑰。Chrome 要求您保證此文件的安全,這意味著,如果您想要將一個(gè)更新打包到擴(kuò)展中,就需要該私有密鑰文件。沒有它,Chrome 將認(rèn)為該更新是一個(gè)全新擴(kuò)展。
一旦您的包裝擴(kuò)展準(zhǔn)備就緒,您就可以以任何方式發(fā)布,以電子郵件形式發(fā)送、放在您的網(wǎng)站上,將其包裝在您的安裝程序中,放在閃存驅(qū)動(dòng)器中,或任何適合您計(jì)劃的方法均可。發(fā)布它的主要缺點(diǎn)是您也要自己處理更新過程。
由于您的 Chrome 擴(kuò)展要檢查更新,添加一個(gè)行到清單文件是來說明在哪查找更新(參見?清單 7)。
清單 7. 檢查更新
{ "name": "GawkBlocker", "version": "1.7", "update_url": "http://yourawesomedomain.com/ext/updates.xml", ... }
然后,您需要托管一個(gè)遵守參考文檔自動(dòng)更新部分指定的格式的 XML 文件。這并不復(fù)雜,但是在您的那一端需要更多工作,這也意味著在 Chrome Web Store 中您不能獲得任何可見度。
將您的擴(kuò)展放入 Chrome Web Store
與您自己發(fā)布擴(kuò)展相比,將擴(kuò)展放入 Chrome Web Store 的過程并不涉及多少技術(shù),但是您需要做一些事情。
首先您需要在 Web 商店中以開發(fā)人員的身份完成設(shè)置。您需要一個(gè) Google 帳戶。登錄成功后,轉(zhuǎn)到 Developer Dashboard 以開發(fā)人員身份注冊(cè)。這需要 5 美元,您需要使用 Google Wallet 支付。如果您的 Google 帳戶已得到確認(rèn),可以立刻在 Developer Dashboard 中激活,如果您的帳戶是新的或者不常使用,可能會(huì)有一個(gè)延遲,直至帳戶審查通過。
注冊(cè)為一個(gè)開發(fā)人員之后,返回未包裝擴(kuò)展目錄,并壓縮所有擴(kuò)展文件(只是 HTML、CSS、JavaScript 和一些圖片文件)。不包括 .crx 或 .pem 文件。Chrome Web Store 將從您的壓縮包中創(chuàng)建一個(gè) .crx 文件,然后使用一個(gè)私有 .pem 文件進(jìn)行簽署。
您的帳戶和壓縮文件準(zhǔn)備好之后,就可以單擊該控制面板上大的藍(lán)色大按鈕?Add new item,上傳您的擴(kuò)展(參見?圖 6)。
圖 6. Chrome Web Store
如果您壓縮文件有一些錯(cuò)誤,控制面板將輸出一些錯(cuò)誤消息。如果您的壓縮文件是格式良好的,并且您的清單文件格式也正確,您將看到出現(xiàn)一個(gè)頁面,詢問關(guān)于擴(kuò)展的元數(shù)據(jù)(屏幕截圖、國家和描述等)。輸入您擴(kuò)展的相應(yīng)信息,就可以將該擴(kuò)展輕松地放入商店。
了解更新如何工作
擴(kuò)展放入商店后,進(jìn)行一些小更改并將更新上傳到商店來感受該流程。常見 gotcha 是忘記更新清單文件中的版本號(hào),每次當(dāng)您上傳一個(gè)更新時(shí),可以單擊 Extensions Management 頁面上的?Update extensions now?按鈕強(qiáng)制執(zhí)行一個(gè)更新。對(duì)于這些更新來說 Chrome Extensions 每幾個(gè)小時(shí) ping 一次,所以更新您的用戶不需要花費(fèi)太長(zhǎng)時(shí)間。
尋找答案
我們來看看如何證實(shí)問題的答案:
在瀏覽器 UI 中擁有一席之地有多難?結(jié)果證明非常簡(jiǎn)單,您只需要在清單文件中指定一個(gè) browser_action 并提供一個(gè)圖標(biāo)。
在瀏覽器會(huì)話間持久化數(shù)據(jù)涉及到什么?在 Chrome 中,您有權(quán)訪問 localStorage 一直持續(xù)到應(yīng)用程序發(fā)布。這使得持久化瀏覽器會(huì)話之間數(shù)據(jù)變得非常簡(jiǎn)單。
不同擴(kuò)展部分彼此如何通信?所有頁面可以使用?chrome.extension.getBackgroundPage()
?與背景頁面通信,并且消息傳遞 API 允許不同擴(kuò)展組件彼此通信,如果需要的話。
您對(duì)用戶數(shù)據(jù)的研究有多深入?與用戶允許程度一樣。每個(gè)權(quán)限都有特定警告,盡管用戶不完全清楚那些權(quán)限隱含了什么。
結(jié)束語
您已經(jīng)編寫了一個(gè) Chrome 基礎(chǔ)擴(kuò)展,然后您就可以開始深入了解它了。您可以在 chrome.* API 中獲取更多信息,現(xiàn)在您只是了解了一點(diǎn)皮毛。在掌握基礎(chǔ)知識(shí)之后,您可以從頭開始,看看能夠?qū)⒛?Chrome 擴(kuò)展到多遠(yuǎn)。
掃碼二維碼 獲取免費(fèi)視頻學(xué)習(xí)資料
- 本文固定鏈接: http://www.wangchenghua.com/post/1732/
- 轉(zhuǎn)載請(qǐng)注明:轉(zhuǎn)載必須在正文中標(biāo)注并保留原文鏈接
- 掃碼: 掃上方二維碼獲取免費(fèi)視頻資料