Chrome插件開發進階

好奇心使然,體驗了下chrome的插件開發(按照英文的意思chrome extension或許更應該稱爲chrome擴展),發現還真是個不錯的東東,在瀏覽google開發文檔的同時也做了些嘗試,腦子不好使,不記錄下來的話沒準過一週就淡忘了,索性把自己的一些嘗試記錄下來跟大家分享一下吧。
本文會圍繞chrome插件以下的5個概念來進行說明:
background page(後臺頁面)
browser action(瀏覽器功能擴展)
content script(內容腳本)
page action(頁面功能擴展)
NPAPI plugin(NPAPI插件,據Google官方消息,從2014年起將不再給予支持)


1341289593_7256.png
另外,本文並不是chrome插件的入門文檔,或許需要你對chrome extension有一定了解才容易理解這些內容,所以如果你完全沒接觸過chrome extension,建議你先看以下文章:

1. background page
manifest.json文件中可以如此定義background:
{ 
  "background": { 
    "scripts": ["background.js"] 
  } 
}


當然也可以通過屬性"page"替換"scripts"來引入.html文件,不過scripts和page只能兩選其一,如下所示:

"background": {   "page": "background.html" }

顧名思義,可以理解爲背景頁面腳本,或者直接解釋爲後臺腳本。background用來處理插件本身的一些邏輯,比如插件加載時需要執行的處理,運行中需要統一維護的數據等等,background只會在插件加載的時候運行一次,你可以在這個過程中讓它綁定一些運行中的事件。比如background中可以直接訪問chrome.browserAction對象來設置和定義browserAction,如:

chrome.browserAction.setIcon({path:"icon.png"});


也可以綁定browserAction的點擊事件定義事件響應處理:


chrome.browserAction.onClicked.addListener(function(){
   ......
});


還可以在background中調用chrome.tabs.create()來創建新的tab。
除了跟browserAction進行交互以外,與content script也可以進行協作,這點讓我們在content script的部分中再來說明。

2. browser action
browser action可以理解爲對瀏覽器現有菜單功能的擴展。可以在manifest.json文件中對browser action進行配置。


{  
"browser_action": {   
"default_icon": "icon19.png", 
"default_title": "Google Mail",
"default_popup": "popup.html"
  }
}


如此設置下,在插件加載時瀏覽器菜單欄就會有如上圖所示的桔色按鈕(icon19.png),單擊此按鈕會彈出popup.html描述的窗口。前面我們已經說明過在background中可以訪問browser action,那反過來呢?這個更直接,在browser action中通過background對象可以直接調用background中定義的方法或對象,如下所示,假設在background.js中定義了testBG函數,那麼在popup.html中可以這樣訪問:

var bg = chrome.extension.getBackgroundPage(); 
bg.testBG();

在popup中還可以注入代碼到web page中,但只限於對dom的訪問和修改。

chrome.tabs.executeScript(null, {code:"document.body.style.backgroundColor=blue"});


3.content script
你肯定不會僅滿足於對瀏覽器菜單功能進行擴展,很多時候也需要跟頁面本身進行交互,這是就需要用到內容腳本content script,content script跟頁面page共用同一份頁面的dom,也就是說content script可以直接去訪問或修改當前頁面的dom,但是注意了,它們只是共享了dom的訪問,js處理本身卻是在兩個不同的沙盒中運行的,所以並不能互調各自的js代碼。
如下處理是在當前頁面中插入一個div節點:

var element = document.body.firstChild;
var div = document.createElement("div");
document.body.insertBefore(div, element);


那麼在content script中能跟background交互嗎?當然。首先在content script中可以通過chrome.extension.sendRequest給background發送消息請求,同時可以通過chrome.extension.onRequest.addListener來監聽從background發送來的消息。
content script監聽消息:
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {});


background發送消息:
chrome.tabs.sendRequest(tab.id, data, function(data) {});


反之,
background監聽消息:
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {});


content script側發送消息:
chrome.extension.sendRequest(data, function(data) {});


以下是官方文檔中的例子:

一次簡單的請求
如果你僅僅需要給你自己的擴展的另外一部分發送一個消息(可選的是否得到答覆),你可以簡單地使用chrome.extension.sendRequest()或者chrome.tabs.sendRequest()方法。這個方法可以幫助你傳送一次JSON序列化消息從content script到擴展,反之亦然。如果接受消息的一方存在的話,可選的回調參數允許處理傳回來的消息。
像下面這個例子一樣,可以從content script 發起一個請求:
contentscript.js
================
chrome.extension.sendRequest({greeting: "hello"}, function(response) {
  console.log(response.farewell);
});
傳遞一個請求到擴展很容易,你需要指定哪個標籤發起這個請求。下面這個例子展示瞭如何指定標籤發起一個請求。
background.html
===============
chrome.tabs.getSelected(null, function(tab) {
  chrome.tabs.sendRequest(tab.id, {greeting: "hello"}, function(response) {
    console.log(response.farewell);
  });
});
接受消息的一方,需要啓動一個chrome.extension.onRequest事件監聽器用來處理消息。這個方法在content script和擴展中都是一樣的。這個請求將會保留直到你做出了迴應。下面的這個例子是一個很好的做法調用一個空對象請求然後得到答覆的例子。
chrome.extension.onRequest.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"});
    else
      sendResponse({}); // snub them.
  });
小提示:如果多個頁面都發起了相同的請求,都在等待答覆,只有第一個發起請求的頁面會得到響應,其他的將會被忽略。




content script除了跟background可以交互,跟web page本身也可以有信息交互。一方面content script可以直接訪問page的dom,同時還可以通過dom的Event來跟頁面進行交互。

content script中綁定事件:
[javascript]view plaincopy
  1. document.addEventListener("EventName",function() {});

web page中如何發送事件給content script呢?如下:
[javascript]view plaincopy
  1. var ev = document.createEvent('HTMLEvents');

  2. ev.initEvent('EventName', false, false);

  3. document.dispatchEvent(ev);

反之,web page中綁定事件,content script中觸發事件的話同上面處理一樣,也成立。

4.page action
page action跟browser action有所區別,它會加載和顯示在地址欄的裏面,所以一般會跟當前訪問的URL地址進行交互,比如你可以讓瀏覽器在訪問所有帶"mail"字符串的URL時顯示page action。具體的顯示位置如下圖:
1341290058_2765.png
如果想使用page action功能,需要在manifest.json中定義如下屬性:
[javascript]view plaincopy
  1. "page_action" : {

  2. "default_icon" : "icon.png",

  3. "default_title" : "Page Action"

  4. }

我們可以把對page aciton的設置和處理放在background page中,從而直接在background中通過chrome.pageAction來設置page action,比如如下代碼實現了當所訪問URL中有mail字符串時就顯示page action的icon這樣的功能:
[javascript]view plaincopy
  1. chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {

  2. if (tab.url.indexOf("mail") > -1) {

  3. chrome.pageAction.show(tabId);

  4. }

  5. });


5.NPAPI Plugin
JS雖然越來越牛叉了,但畢竟存在侷限性,有些處理目前用JS來做畢竟還不現實,比如視頻插件,大數據計算等,這類處理大部分還是會通過C++等語言封裝的組件來實現的,那麼在JS的插件裏怎麼調用這些C++的組件?因爲chrome支持了NPAPI,那這點就不成問題了。(關於什麼是NPAPI,一來不是本文介紹的重點,二來我也沒詳細研究過,有興趣的自己google吧)
在這裏就介紹下在chrome插件中怎麼去結合NPAPI插件。首先需要在manifest.json中定義如下關於插件的屬性:
[javascript]view plaincopy
  1. "plugins": [

  2. { "path": "plugin1.dll", "public": true },

  3. { "path": "plugin2.dll" }

  4. ]

當chrome插件加載後,就可以在html頁面中使用所定義的NPAPI插件了,假設插件的mime-type是x-plugin1時我們可以這樣去調用NPAPI插件:
  1. <embedtype="application/x-plugin1"id="pluginId">

  2. <script>

  3. var plugin = document.getElementById("pluginId");

  4. var result = plugin.PluginMethod(); //調用plugin中定義的方法

  5. </script>


好了,就寫這麼多,謹以此文整理了下自己的思路,也希望能給大家帶來一些收穫。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章