[Chrome extension] 開始寫一個 Chrome extension 擴充功能
今天這篇文章是在記錄如何寫一個簡單的 Chrome extension (擴充功能)~
為什麼要寫 extension 呢?因為 extension 可以幫你把許多事情變得更簡單~
像我這次寫的這個 extension 要解決的是 Great Suspender 的一個問題…
Great Suspender 是一個不錯用的 Chrome extension,
可以將長時間不用的 tab 先暫時凍結起來,節省一點系統資源~
不過,像我開很多 tab 的時候,可能就會有很多 tab 會進到凍結的狀態,
有時會想要讓他們全部重新整理,回到未凍結的狀態~
可是,單只是重新整理頁面是不行的,必須按下頁面上面的黃色區域才行:
原本想裝一些可以重新整理所有頁面的 Chrome extension,來幫我把所有凍結的頁面都回復正常,
但因為單單重新整理沒有用,所以這些 extension 都無用武之地 (殘念)…
不過從 URL 的部分看來,原始的頁面 URL 是含在凍結頁的 URL 裡面,
這個被凍結的頁面原始的 URL 就是 #url 後面的部分囉~
觀察一下,那個 URL 的部分應該是被 JavaScript 的 encodeURIComponent() 編碼過的…
只要能取得 URL,作一次 decodeURIComponent() 就能還原原始的 URL~
既然沒有 Chrome extension 可以作到這件事,就自己來寫一個吧,
順便記錄一下該怎麼寫一個新的 Chrome extension~
1. 參考相關文件
要寫一個新的 Chrome extension,首先要造訪的自然是 Google 的官方網頁~
Getting Started: Building a Chrome Extension
花點時間好好看一下吧,而且 Chrome 也會更新裡面的一些東西,
像之前 Google 就修改了 manifest v2 的東西,也有可能增加新的 API~
2. 準備 manifest.json
這是一個 JSON 格式的檔案,用來告訴 Chrome 這個 extension 的一些相關資訊,
如名稱、敘述、版本、需要的權限、圖示、預設頁面等等~
這個 manifest 檔案要放在一個目錄裡面,
之後所有跟這 extension 相關的檔案也都要放在目錄裡面~
像我將這個 extension 的名稱取為 Reload Tabs,版本設定為 1.0,
使用 browser_action 表示會有一個圖示出現在 Chrome 的 extension 列上讓使用者點擊,
(因為我想要在點下圖示時,將所有的 Chrome tab 重新整理)
這裡面設定的圖示檔 (default_icon) 和點示圖示時要顯示的頁面 (default_popup) 都只是先取一個檔名,
還沒有實際的檔案~
{ "manifest_version": 2, "name": "Reload Tabs", "description": "Reload all Chrome tabs, including the ones that are frozen by Great Suspender", "version": "1.0", "permissions": [], "browser_action": { "default_icon": "icon.png", "default_popup": "popup.html" } }
要注意的是目前的 manifest_version 必須設成 2 喔~
當然之後 Chrome 如果有再更新的話,有可能這裡會要求更新的 manifest 版本…
Chrome 會根據 manifest 的版本,來決定 extension 的一些行為與規範,
像是之前從 v1 改版至 v2 時,就要求加強一堆與安全性相關的功能~
Chrome 會允許舊版的 manifest 使用一段時間,但寬限期過了之後,
如果 manifest 版本還是沒有更新到 Google 要求的話,
這個 Chrome extension 就無法再使用了,真是夠狠的~~
(我們的產品好像都沒辦法這樣搞,很古老的產品也得支援,
微軟已經停止支援的 Windows XP 我們還不知道要支援到天荒地老什麼時候~)
3. 準備 icon.png 圖示檔
基本上圖示檔是一個 19×19 的 PNG 檔案,
可以自己想辦法做一個出來,抓一個也可以 (要注意版權)~
網路上有很多免費的圖示可以抓,像我就從 IconFinder 找了個免費圖示下來用~
基本上也不需要去把圖縮成 19×19,Chrome 在顯示時自己就會縮圖了~
4. 測試一下新寫的 extension (圖示)
當然 extension 的部分都還沒寫到什麼,不過可以先看看圖示的效果~
在 Chrome extension 列上隨便一個圖示上按右鍵 > Manage,
或是在網址列上打 chrome://extensions/ 進到 extension 的管理頁面~
把右上角的 Developer mode 打勾,
可以看到下面出現了幾個開發 extension 用的按鈕~
選擇 Load unpacked extension… 按鈕後,選取包含 extension 檔案的那個目錄,
Chrome 就會將我們新寫的 extension 讀進來了~感動~~ ^^
而且在 extension 圖示列上,也出現了我們的圖示囉:
試著點一下圖示,出現了網頁找不到的錯誤,不過這也是預期中的~
5. 準備 popup.html 網頁檔 (初版)
這個 html 檔案是按下圖示時,會顯示的網頁,
因此我們要做的事可以寫在裡面~
當然 Chrome extension 還有其他觸發的方式 (像是背景頁面 background pages),
不過以我們這個 extension 的需求來說,相當足夠了:
點下圖示 -> 顯示一個網頁,裡面用 javascript 把所有的 tab 都重新整理, 順便顯示一個訊息說目前正在重新整理 -> 完成! |
那就先來建立一個最簡單的網頁檔 popup.html 吧~
雖然我還不會 HTML5,不過這是個趨勢,趁這時間學一點皮毛也是好的~
上 w3schools: HTML5 Introduction 複製一個 HTML5 的樣版網頁下來,稍微修改一下:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Reload Tabs</title> </head> <body> Hello! This is Reload Tabs extension! </body> </html>
這個網頁的內容就是顯示一段 Hello 字串,
改好之後,點下 extension 圖示就可以立刻看到效果~
(沒有的話,到 chrome://extensions/ 頁面對 extension 選擇 Reload):
可以看到,Chrome 會將網頁內容顯示在一個像對話框的東西裡面,
不過這對話框的寬度似乎有點小?
其實是因為我們並沒有指定網頁的 style width,
有指定的話,這個對話框也會相應的變大囉~
6. 在 popup.html 中加入 Javascript 來重新整理所有的 tab
接下來,我們要在 popup.html 裡加入一些 Javascript,
好來重新整理所有的 tab 囉~
要如何取得 Chrome 中所有的 tab 呢?
如果有仔細看 Chrome extension 的文件的話,應該會注意到 chrome.tabs 這一頁~
這裡面提到了 chrome.tabs.query() 這個 API 可以用來查詢 Chrome 的 tab~
直覺的在 popup.html 中加上 Javascript 碼來試試看:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Reload Tabs</title> <script> alert("script"); chrome.tabs.query({}, function(tabs) { alert(tabs); }); </script> </head> <body> Hello! This is Reload Tabs extension! </body> </html>
怪了,點下圖示後還是只顯示了 Hello 訊息,沒有預期的 alert 對話框?!
就算在 chrome://extensions/ 頁面對 extension 選擇 Reload 也是一樣…
瞄一下 Chrome Tutorial: Debugging 這邊的說明吧~
在 extension 圖示上按右鍵 > Inspect Popup 就可以跳出 Chrome developer tools 視窗來幫助除錯:
從下面的錯誤訊息中,可以發現是違反了 script-src 這個 Content Security Policy…
這個 Content Security Policy 是什麼東東呢?
基本上就是一些跟 Chrome extension 安全性相關的規則,
Google 為了避免 Chrome extension 本身造成危害,因此設定了一些規矩,
可以參考 Chrome Content Security Policy (CSP) 這個頁面~
舉例來說,下面這些是被禁止的:
1. Eval and related functions are disabled 2. Inline JavaScript will not be executed 3. Only local script and resources are loaded |
看來我們在 popup.html 中直接寫 inline 的 <script> 是撞到 CSP 的原因…
既然不能用 inline script,只好把它移到另一個外部的 JavaScript 檔案去囉~
7. 準備一個 popup.js 來執行 JavaScript
把原本在 popup.html 中的 <script></script> 的內容移到新的 popup.js 檔案中:
alert("script"); chrome.tabs.query({}, function(tabs) { alert(tabs); });
原本的 popup.html 中的 <script> 就改成連結至這個 popup.js:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Reload Tabs</title> <script src="popup.js"></script> </head> <body> Hello! This is Reload Tabs extension! </body> </html>
重新點一下圖示,這次就有正常的出現 alert 視窗,表示我們寫的 JavaScript 有作用了!
8. 修改 popup.js 使其可以謮取 tabs 的資訊
接下來就是把 popup.js 這個 JavaScript 修改一下,讓它可以讀到所有的 tab…
這邊用 console.log() 把訊息寫到 debug console 上去,
因此要在 extension 圖示上按右鍵 > Inspect Popup 的方式看訊息:
chrome.tabs.query({}, function(tabs) { for (var i = 0; i < tabs.length; i++) { console.log(tabs[i]); } });
點開其中一個 Tab object 來看:
嗯… 看來資訊跟 chrome.tabs 這邊的 property 的說明部分差不多,不過少了 url…
在 url 的地方,網頁上特別提及如果要使用 tab 的 url 屬性的話,
要在 manifest.json 中加入 “tabs” 的 permission:
於是 manifest.json 會變成這樣:
{ "manifest_version": 2, "name": "Reload Tabs", "description": "Reload all Chrome tabs, including the ones that are frozen by Great Suspender", "version": "1.0", "permissions": [ "tabs" ], "browser_action": { "default_icon": "icon.png", "default_popup": "popup.html" } }
到 extension 管理頁面將 extension 重新載入後,再點 Inspect popup,
這次就可以成功拿到 tab 的 url 了:
9. 修改 popup.js 使其可以重新整理所有的 tabs
既然已經可以讀到所有 tab 的 url,要重新整理也就很簡單了,只要呼叫 chrome.tabs.reload() 就行~
(不過後來測試結果,chrome.tabs.reload() 會連表單的部分也重送,
跟我只想要單純重新整理 URL 不同,因此後來就不採用 reload() 了)
不過我們還想連 Great Suspender 凍結的 tab 也重新整理,
那就必須將 url 讀出來之後,取出 #url 後面的部分作 URL decoding,用這當作那 tab 的新 url~
於是修改後的 popup.js 變成這樣:
chrome.tabs.query({}, function(tabs) { const URL_PATTERN = "/suspended.html#url="; for (var i = 0; i < tabs.length; i++) { var nTabID = tabs[i].id; var sTabURL = tabs[i].url; if (sTabURL != null) { // Check if this tab is frozen by Great Suspender var nPos = sTabURL.indexOf(URL_PATTERN); if (nPos >= 0) { // This tab is suspended by Great Suspender. // Reload with original url. sTabURL = decodeURIComponent(sTabURL.substr(nPos+URL_PATTERN.length)); } // Reload the tab chrome.tabs.update(nTabID, {"url": sTabURL}); } } });
測試一下新寫好的 extension 吧~
按下圖示後,所有的 tab 都被重新整理了,被 Great Suspender 凍結的頁面也都回復正常~
整個 extension 的任務可算是圓滿成功 🙂
不過到目前為止,都還只是個 Developer 版本的 chrome extension…
之後再來寫一篇將 chrome extension 上架到 Chrome App Store 的文章吧~~^^
One thought on “[Chrome extension] 開始寫一個 Chrome extension 擴充功能”
謝謝提供非常實用的教學!
版主回覆:(11/17/2014 03:51:25 PM)
不客氣,希望有幫上忙~:)