chrome外掛開發【轉】
本文將從個人經驗出發,講述為什麼需要Chrome外掛,如何開發,如何除錯,到哪裡找資料,會遇到怎樣的問題以及如何解決等,同時給出一個個人認為的比較典型的例子——獲取網頁內容,和伺服器互動,再把資訊反饋給使用者。OK,準備開始吧,我儘量把文章寫得好看點,以免讀者打瞌睡。
目錄
為什麼需要
為什麼是Chrome
需要準備什麼
如何開始
Page Action
Chrome外掛結構
學習資料
我的例子
除錯
除錯Content Scripts
除錯Background
除錯Popup
一些問題
總結
為什麼需要
簡單地說,瀏覽器外掛,可以大大的擴充套件你的瀏覽器的功能。包括但不僅限於這些功能:捕捉特定網頁的內容,捕捉HTTP報文,捕捉使用者瀏覽動作,改變瀏覽器位址列/起始頁/書籤/Tab等介面元素的行為,與別的站點通訊,修改網頁內容……給你增加許多想象空間,試想想看,你可以用它來識別一些網站上的廣告程式碼,並直接把這些程式碼刪掉,這樣你就不會受到廣告的困擾了,沒錯,如你所願,這樣的外掛別人已經開發好了,你可以直接用。不過,也要說瀏覽器外掛的弊端,那就是:會帶來一些安全隱患,也可能讓你的瀏覽器變得緩慢甚至不穩定。
為什麼是Chrome
因為Chrome的外掛開發起來最簡單,總體上看沒什麼新的技術,開發語言就是javascript,web前端工程師能很快上手;而Firefox的外掛開發則複雜許多,涉及到環境的搭建和一些WEB以外的技術;IE的外掛開發就更復雜了,需要熟悉C++和COM技術,當然還要裝微軟的Visual Studio。
應該說Chrome和Opera的外掛的開發都不難,但Firefox的則比較棘手,也許你要問,那為什麼Firefox的外掛是最豐富的?我想這有些歷史原因,Chrome出來畢竟比較晚,另外幾種瀏覽器提供的外掛的功能也是不盡相同的,OK,我們還是言歸正傳吧。
需要準備什麼
幾乎是零需求。Chrome瀏覽器和一個文字編輯器即可,文字編輯器最好是帶語法高亮的那種。谷歌對我們做技術的人來說真是太大度了。
文章不長,照著文章去做,完成後,你就成功開發了第一個Chrome外掛,這個外掛會彈出一個小視窗,上面顯示些阿貓阿狗的小圖片。如圖:
這個外掛一共有4個檔案:
manifest.json - 所有外掛都要有這個檔案,這是外掛的配置檔案,可看作外掛的“入口”。
icon.png - 小圖示,推薦使用19*19的半透明png圖片,更好的做法是同時提供一張38*38的半透明的png圖片作為大圖示,在我後面提供的例子中,我就是那麼幹的。
popup.html - 就是你所看到的那個阿貓阿狗的彈出頁面。
popup.js - 阿貓阿狗頁面所引用的javascript檔案。
這裡千萬千萬注意了,我當初沒仔細看popup.html裡有一小段註釋,這一小段註釋說:出於安全考慮,javascript必須與html分開存放。而我想嘛,一個小測試程式,沒必要分開吧,直接寫一起不就行了嗎?結果javascript死活執行不了,我翻來覆去找不到原因,還以為彈出的小視窗不支援javascript,在網上搜索了半天又沒有結果,最後才發現是這個原因,浪費了許多時間,這個事情也一定程度上說明了:細節決定成敗。
manifest.json中的內容也非常顯而易見,我選擇其中幾個屬性講一下:
複製程式碼
{
“manifest_version”: 2,
“name”: “One-click Kittens”,
“description”: “This extension demonstrates a browser action with kittens.”,
“version”: “1.0”,
“permissions”: [
“https://secure.flickr.com/”
],
“browser_action”: {
“default_icon”: “icon.png”,
“default_popup”: “popup.html”
}
}
複製程式碼
“manifest_version”:現在應該總是2。
“permissions”:很重要的東西,即允許外掛做哪些事情,訪問哪些站點,假如一個外掛的”permissions”裡寫有“http://*.hacker.com/”,那麼這個外掛就被允許訪hacker.com上的所有內容,包括可能會把你的一些個人資訊提交給hacker.com,危險性不言而喻,檢視一個外掛能訪問那些站點的方法是:在chrome的位址列裡輸入“chrome://extensions/”(注意:這個頁面我們之後要頻繁用到,請收藏一下),然後點對應外掛的旁邊的那個“許可權”,如:
“default_popup”:用來指定點選小圖示後彈出的小視窗中預設顯示的是哪個html,這個彈出的小視窗就叫做“popup”。
“browser_action”:這是一個瀏覽器級的動作,也就是說,不管你現在在訪問哪個頁面,那個小按鈕總是顯示出來,而我們的外掛如果僅僅是針對某些頁面的話,就不適合用這個”browser_action”了。下面我們來弄一個只有訪問部落格園(www.cnblogs.com)才會出現的小按鈕。
Page Action
chrome-plugin-page-action-demo.7z
這個外掛只有4個檔案,其中兩個還是圖示,那就只剩下一個必須的manifest.json和一個background.js了。
mainifest.json:
複製程式碼
{
“manifest_version”: 2,
“name”: “cnblogs.com viewer”,
“version”: “0.0.1”,
“background”: { “scripts”: [“background.js”] },
“permissions”: [“tabs”],
“page_action”: {
“default_icon”: {
“19”: “cnblogs_19.png”,
“38”: “cnblogs_38.png”
},
“default_title”: “cnblogs.com article information”
}
}
複製程式碼
注意:這裡是“page_action”而不是“browser_action”屬性了。
“permissions”屬性裡的“tabs”是必須的,否則下面的js不能獲取到tab裡的url,而這個url是我們判斷是否要把小圖示show出來的依據。background是什麼概念?這是一個很重要的東西,可以把它認為是chrome外掛的主程式,理解這個很關鍵,一旦外掛被啟用(有些外掛對所有頁面都啟用,有些則只對某些頁面啟用),chrome就給外掛開闢了一個獨立的javascript執行環境(又稱作執行上下文),用來跑你指定的background script,在這個例子中,也就是background.js。
background.js
複製程式碼
function getDomainFromUrl(url){
var host = “null”;
if(typeof url == “undefined” || null == url)
url = window.location.href;
var regex = /.:\/\/([^\/]).*/;
var match = url.match(regex);
if(typeof match != “undefined” && null != match)
host = match[1];
return host;
}
function checkForValidUrl(tabId, changeInfo, tab) {
if(getDomainFromUrl(tab.url).toLowerCase()==”www.cnblogs.com”){
chrome.pageAction.show(tabId);
}
};
chrome.tabs.onUpdated.addListener(checkForValidUrl);
複製程式碼
程式碼中,我們使用了一個正則表示式去匹配url,獲取出其中的domain部分,如果domain部分是“www.cnblogs.com”的話,就把小圖示show出來,效果如下:
當然了,你現在點那個小圖示的話,是沒有任何反應的,我沒有像官方提供的那個例子那樣提供了popup。OK,現在是時候描述下chrome外掛的結構了。
Chrome外掛結構
需要宣告的是,這個結構圖是我自己畫的,代表我對Chrome外掛的理解,可能並不全面,甚至還不是十分準確,但找來找去找不到現成的,只好自己動手,如有謬誤,請不吝指出。
如圖,manifest.json作為外掛的配置檔案,同時可以看作程式的“入口”,因為它指定了顯示什麼圖示,background script有哪些檔案,content script又有哪些檔案,pop up的頁面是什麼,等等。
什麼是popup,什麼是background script,相信大家都清楚了,那什麼是content script呢?content script就是我們要注入到頁面中的指令碼,外掛允許我們往網頁中注入指令碼,這是一個多麼讓人有想象力的功能,其功能之強大無需多解釋,總的來說,就是讓我們全面干預頁面的內容!也許你馬上會想到,這可能帶來很大的安全隱患,沒錯,有些惡意外掛會竊取你的頁面資訊,而有些有漏洞的外掛則可能讓你遭受跨站指令碼注入(XSS)的攻擊;另一個可能你會想到的問題是:往頁面中注入自己的指令碼,難道不會跟頁面原本的指令碼發生衝突嗎?能想到這點說明你真的很厲害,如果我們的注入指令碼和頁面原本的指令碼處於同一個執行環境中,確實會發生衝突,所以,Chrome是另外開闢了一個獨立的執行空間,供我們的Content Script使用的,Content Script能訪問DOM的內容,但卻不能訪問頁面原本的指令碼(我是說直接訪問不行),反之,頁面原本的指令碼也不能直接訪問Content Script。在圖中,淺紅色的背景塊代表Content Script的執行環境,而淺藍色的背景塊代表頁面執行環境,另外外掛的執行環境我用淺綠色表示,注意,這是三個不同的執行環境,除錯的時候你會充分體會到它們的不同。
那麼,Content Script會在什麼時候執行呢?預設情況下,是在網頁載入完了和頁面指令碼執行完了,頁面轉入空閒的情況下(Document Idle),但這個是可以改變的,詳情可參考https://developer.chrome.com/extensions/content_scripts.html,檢視其中的“run_at”。
由於處於不同的執行環境中,Content Script和Background Script不能直接互相訪問,那它們之間如何通訊?通過Message!這個之後的程式碼中會有。
學習資料
理解了Chrome外掛結構之後,我相信你完全有能力開發一款自己的外掛了,當然了,你得自己去google一些資料,這裡我就分享下我的方法。
再則,官方提供的例子,可以看看,https://developer.chrome.com/extensions/samples.html,我發現上面的例子有些已經不能用於新版的Chrome了,但沒關係,你只要找你想要的就行了,也不用一個個嘗試,就根據你的需要,挑選幾個你感興趣的看看即可。
遇到問題,怎麼辦?當然是用google去查詢問題,但這裡我最最最強烈推薦stackoverflow.com,這簡直是解決問題的神器!不多解釋了,用過便知。
學習過程基本上就是:看個大概,寫點程式碼,除錯除錯。就可以了。哦,大前提當然是你得有javascript的基礎。(你:呵呵,你在逗我吧!)
我的例子
chrome-plugin-cnblogs-article-information.zip
chrome-plugin-cnblogs-article-info-server.zip (伺服器端,PHP程式碼)
好,輪到我的例子登場了。它的功能是這樣的:當你瀏覽部落格園的時候,它會啟動並嘗試獲取你瀏覽的文章的資訊(標題、作者和日期),再通過往另一個伺服器傳送請求的方式,記錄和獲取你第一次訪問這篇文章的時間,把這個時間連帶文章的資訊,顯示在popup上。聽起來挺無聊的功能,但關鍵是為了演示嘛,如圖:
這個外掛一共有9個檔案,新出現的檔案有兩個(其它相信大家都很熟悉了),一個是“content_script.js”,這就是前面提到的Content Script,獲取和修改頁面的內容就靠它了;另一個是“jquery-2.0.0.min.js”,大名鼎鼎的jQuery,我很喜歡用的js庫,其理念是“write less,do more”,能幫我減少很多程式碼,這是目前最新的2.0.0版,這個版本跟以前的1.x.x的最大差別就是不再支援IE6、7和8,我個人是十分贊同這種做法的,微軟的舊版瀏覽器都成了Web技術發展的絆腳石了,而且這次我們用的是Chrome瀏覽器,果斷選擇最新版了。
另外還有一個伺服器端,為了讓問題簡化,這次我用了php程式碼,一個php檔案就是整個處理了,沒有太多繁雜的配置,簡潔,這是php最大的優勢。系統結構如圖:
抓取網頁的內容得依靠content_script.js,然後通過sendMessage/onMessage和background.js交換資料,background.js將url資訊通過ajax(XMLHttpRequest)傳送給localhost,獲取此頁面的第一次訪問的時間,最後,使用者點小圖示,popup.html出現,popup.html會讀取(程式碼在popup.js中)background.js中的articleData的資料,把它顯示出來。這就是整個過程。
我抓取網頁資料的方式並不能確保所有的部落格園的文章都能被正常獲取,這跟使用者使用的部落格模板有關係,但我嘗試下來大多數文章還是可以抓取的,我不去適應所有的模板了,畢竟這只是個演示的demo。
另外還需說明的一點是我使用了jQuery做XMLHttpRequest,post的內容不是傳統的html表單形式,而是json資料,所以在伺服器端這邊,就不能直接用$_REQUEST獲取,而是通過讀取“php://input”的內容獲取。順便談談個人對web api的一個看法:“統一”大於“靈活”,這是我的觀點,我確定我的介面的格式是json,使用utf-8編碼,於是就一直用下去,呼叫者不用考慮用XML還是html表單還是別的,開發者也不必多考慮,讓這成為一種統一的約定,在團隊協助和以後的開發中會很省事。
除錯
程式開發,必定要涉及到除錯,記得我剛開始做WEB開發前,問一些做了好久WEB開發的朋友,你們是怎樣做javascript除錯的,我發覺大多數人竟然回答:用alert一點點試吧——不是不行,是太原始,太低效了,對吧?其實Chrome直接支援javascript的除錯,擁有了Chrome,就相當於擁有了一個強大的javascript偵錯程式了。
Chrome開啟開發者工具的方法是++(Windows版),大致如下:
我們這次需要關心的有“Elements”、“Sources”和“Console”這三個標籤。Elements是用來做DOM分析的,功能有點類似Firebug,幫助我們分析頁面的內容;而Sources,是我們用來除錯javascript的;Console則是我們的Log的輸出視窗,也是一個除錯利器。
除錯Content Script
如我提供的這個例子,可在Sources的“Copntent Scripts”下看到“content_script.js”然後設斷點,執行到斷點處時,Chrome會挺住,你可以觀察到上面的值,如圖:
太cool了,請問你還要一點點alert嗎?
除錯Background
由於background和content script並不在同一個執行環境中,因此上面的方法是看不到Background的javascript的。要除錯Background,還需要開啟外掛頁,也就是“chrome://extensions”。點對應的外掛的“generated background page.html”,就出現了除錯視窗,接下來的操作就跟前面的類似了。如圖:
至於你看到ID,“aajnhhjiia……”這一長串東西,這是chrome自動安排的一個ID。
除錯Popup
雖然Popup和Background是處於同一執行環境中,但在剛才的Background的除錯視窗中是看不到Popup的程式碼的。除錯Popup還需要這樣:
然後……就跟前面差不多了。
一些問題
也許有時候你會發覺偵錯程式不是很靈,至少我用下來感覺如此,比如你可能發現斷點設不了,或者斷點不起作用,或者看不到你自己的javascript檔案。我的方法是在外掛頁中,把對應的外掛的“已啟用”這個複選框去掉,再重新勾上,然後再點一下“重新載入(Ctrl+R)”,通常能解決問題。當然了,還有些很古怪的問題,還不好重現,總體的解決思路就是重新載入一下,實在不行的話重啟瀏覽器,或者清除瀏覽器快取什麼的,再試試看。
在做外掛除錯的時候我還遇到一個十分鬱悶的問題,那就是我的Chrome使用了“Go Agent”,關於Go Agent是用來幹嘛的,這個嘛,可以去google一下,我相信絕大多數程式設計師都會喜歡上它……可由於使用了這個東西,很可能會導致外掛的XMLHttpRequest工作不正常,而且可能你會思索半天也找不到原因,好吧,暫時把Go Agent停用掉,甚至可能你需要重啟下Chrome——我的經驗。
總結
我還是想說,我覺得Google對我們程式設計師來說是個很大度的公司,在Chrome這個產品上面就可見一斑。利用Chrome外掛技術,我們可以做許多有用的東西,通過本文,相信你已經知道如何去開發一款Chrome外掛了,當然了,Chrome外掛的功能是很強大的,我用到的僅是冰山一小角。要深入,當然還需要更加充分地利用google和stackoverflow.com了。