---
tags: Other
---
# Chrome Extension
[TOC]
Extension 其實就是一個 web pages app ,由一個 manifest.json 和其他網頁檔案組成。
什麼情況下需要 Chrome Extension ?
* 需要一個輔助工具,讓 Chrome Browser 有**更好的操作體驗**。
* 需要針對特定的幾個網頁**增加功能**或**修改外觀**。
## [Manifest 安裝檔](https://developer.chrome.com/extensions/manifest)
`manifest.json` 可以視為**安裝檔**的內容,裡面會包含許多 extension 的資訊。
* 必要的設定:`manifest_verson` 、 `name` 、 `version`
* 建議的設定:`description` 、 `icons` 、 `default_locale`
> 但是,如果沒有要做多國語言的話,就不要設定 default_locale (整行拿掉,不是設為空字串),因為您的專案資料夾下必須有這個檔案 (project/_locales/en/messages.json) 才能設定,而 default_locale 只是設定預設使用哪個語言。
可以透過 `chrome-extension://{{EXTENSION_ID}}/manifest.json` 來查看其他 Extension 的設定,其他檔案修改相對路徑就可以看到了。
可以使用 [JSONLint](https://jsonlint.com/) 等第三方 JSON 驗證工具,確保 JSON 程式碼格式沒有任何錯誤。
### Manifest Verson
一個代表 manifest file 格式版本的整數,如果使用的是 Chrome 18 以上,則應該設定成 2。
差異可看:[Changes between version 1 and 2](https://developer.chrome.com/extensions/manifestVersion#manifest-v1-changes)
```json
"manifest_version": 2
```
### Extension 相關訊息
包括名稱、版本、描述、網站等等。
* `homepage_url` :可以在 Toolbar 右鍵或是或是 Extension 說明拜訪**主頁**。
* `options_ui` :
* 通常是 Extension 的**設置頁面**,為了將 Chrome Extension 客製化,會需要提供一些選項讓使用者自行設定,選項頁面就是為此而存在。
* 選項頁面設定的值可以用 **chrome.storage** 的 API 來儲存,不但可以在 Extension 的任何腳本中存取,也支援同步功能。
* `page` 必須是相對路徑,`chrome_style` 會添加一些默認的樣式,推薦使用。

```json
"name": "PET",
"version": "1.0.0",
"description": "全世界最偉大的小幫手",
"homepage_url": "https://pet.kkbox.io/",
"options_ui":
{
"page": "options.html",
"chrome_style": true
}
```
### Icon
偷懶用一個也行,但還是建議乖乖來。
* 128:用在安裝時
* 48:在 chrome://extensions 裡顯示
* 16:favicon
```json
"icons":
{
"16": "img/icon_16.png",
"48": "img/icon_48.png",
"128": "img/icon_128.png"
}
```
### Toolbar
瀏覽器右上角的圖標設置,**browser_action** 和 **page_action** 只能選擇一個來設定,或者都不設定。
下面三者皆為 optional 。
* `default_icon`:預設會是灰底正方形帶 Extension name 的第一個字母: ,若有設置 `icons` ,則採用 `icons` 的圖檔。
* `default_title`:預設會是 Extension name 。
* `default_popup`:Browser Action 或 Page Action 點擊後跳出的小頁面。通常所要顯示的資訊與當前網頁內容沒有關係時,就會用彈出頁面來顯示。
```json
"browser_action":
{
"default_icon": "img/icon.png",
"default_title": "Tooltip Title",
"default_popup": "popup.html"
}
```
#### [Browser Action](https://developer.chrome.com/extensions/browserAction)
適合需要**常駐在每個網頁的功能**。

##### Badge
可以在圖標上顯示一些文本  ,提示使用者一些訊息,最多只支持英文 4 字或中文 2 字。沒辦法透過配置文件來指定,必須通過 code 。
```javascript
chrome.browserAction.setBadgeText({text: 'new'})
chrome.browserAction.setBadgeBackgroundColor({color: [255, 0, 0, 255]})
```
#### [Page Action](https://developer.chrome.com/extensions/pageAction)
類似 browser action,差別在於 page action 用於**特定網頁才需要的功能**,由於 browser action 常駐時會佔用一部份的記憶體,如果你的功能需要在特定狀況下才啟用,建議用 page action 取代 browser action。常見應用是 RSS 訂閱(只有網頁提供 RSS 時才啟用)。


### [Background Pages](https://developer.chrome.com/extensions/background_pages)
一個 extension 通常要有一個**常駐執行**的 script,用來控制 Browser UI(page action 或 browser action),例如我們會需要一個常駐的程式去監聽 FB 是否有新的訊息,如果聽到則在 browser actoin 上面顯示 badge,收信亦如是。
會一直常駐的後台 js 或後台頁面,有兩種指定方式:
1. `page` :在設定檔定義為 html,再從 html 讀取 javascript。
2. `scripts` :指定 js ,會自動生成一個默認的背景頁 `_generated_background_page.html` 。
當啟用 Extension 時,就會在背景產生一個後台頁面(一個 Extension 只會有一個後台頁面),直到 Extension 被停用或是 Chrome Browser 被終止才會結束。可以透過擴充功能管理頁或 `chrome-extension://{{EXTENSION_ID}}/background.html` 進入後台頁面。
```json
"background":
{
"page": "background.html"
// or
"scripts": ["js/background.js"]
}
```
#### Event pages
Background 的生命週期太長,長時間掛載可能會影響性能。Event Pages 與 Background 只差別在多一個 persistent 的參數。
Event pages 是靠事件觸發,唯一主動載入是在剛安裝的時候,而此時可以利用 runtime.onInstalled 事件來做一些每次更新版本的初始化動作(比如說加按鈕到網頁上的右鍵選單裡)。
會使事件頁面載入的情況:
1. Extension 第一次安裝或更新為最新版本時。
2. 事件頁面監聽的某一事件被觸發時。
3. 內容腳本或其他的 Extension 發送訊息時。
4. Extension 中的其他頁面呼叫 runtime.getBackgroundPage 時。
```json
"background":
{
"scripts": ["event-page.js"],
"persistent": false
}
```
### [Content Script](https://developer.chrome.com/extensions/content_scripts)(TODO)
可以在頁面裡面嵌入 javascript,他們可以透過 DOM 得知使用者瀏覽的頁面的內容,甚至可以改變這些內容。
這些是 content script 可以做到的事:
* 將所有網址套上超鏈接
* 修改字體大小
* 去掉廣告
* 諸如此類...
但不能:
* 呼叫 chrome.* APIs 這類的 API(chrome.extension 除外)
* 使用 extension page 上的變數和函式(例如 background pages)
* 使用網頁上的變數和函式
這些限制可以透過 chrome.extension 與 extension pages 做溝通。
* `matches`:格式可以參考 [Match Patterns](https://developer.chrome.com/extensions/match_patterns) 。`<all_urls>` 表示所有頁面。
* `run_at`:載入 code 的時間,默認為 `document_idle` ,表示頁面空閒時。另外包含選項 `document_start` 、 `document_end` 。
```json
"content_scripts": [
{
"matches": ["http://www.google.com/*"],
"css": ["mystyles.css"],
"js": ["jquery.js", "myscript.js"],
"run_at": "document_start"
}
]
```
### 資源列表(TODO)
一般普通頁面能夠直接訪問的 Extension 資源列表,如果不設置是不能直接訪問的。
```json
"web_accessible_resources": ["js/inject.js"]
```
### [Permission](https://developer.chrome.com/extensions/permissions)
有權限才能做事。更多權限可以看 [Declare Permissions](https://developer.chrome.com/extensions/declare_permissions)。
```jsonld
"permissions":
[
"contextMenus", // 右鍵選單
"tabs", // 標籤
"notifications", // 通知
"storage",// 本地儲存
]
```
### [Override Pages](https://developer.chrome.com/extensions/override)
覆蓋瀏覽器的默認頁面。
| The default New Tab page | An alternative New Tab page |
|:----------------------------------:|:----------------------------------:|
|||
```json
"chrome_url_overrides":
{
"newtab": "newtab.html"
}
```
## 載入擴充功能
Chrome Web Store 安裝擴充工具,下載的會是一個副檔名為 `.crx` 的打包檔,不利於開發與測試,可以使用以下方法載入 local 端的套件檔。
1. 進入 [chrome://extensions](chrome://extensions) 。
2. 確保開啟「開發人員模式」。
3. 點選「載入未封裝項目」後選取專案資料夾所在位置。
## [Context Menus](https://developer.chrome.com/apps/contextMenus)
開發右鍵選單功能。
* Manifest 加上權限。
```json
"permissions": ["contextMenus"]
```
* Type:`normal` 、 `checkbox` 、 `radio` 、 `separator`
```javascript
chrome.contextMenus.onClicked.addListener((info, tab) => {
console.log(info['selectionText'])
})
chrome.runtime.onInstalled.addListener(() => {
chrome.contextMenus.create({
type: 'normal',
title: 'Select: %s',
contexts: ['all'],
id: 'search'
})
})
```
可以在 title 透過 `%s` 顯示**目前選取文字**。

## [Notification](https://developer.chrome.com/extensions/notifications)(TODO)
推送桌面通知。

* Manifest 加上權限。
```json
"permissions": ["notifications"]
```
* Type:`basic` 、 `image` 、 `list` 、 `progress`
```javascript
chrome.notifications.create('notificationId', {
type: 'basic',
iconUrl: chrome.runtime.getURL('icon.png'),
title: 'Hello!',
message: '好累啊~~'
}, (notificationId) => {
console.log(notificationId)
})
```
* 第一次建立通知訊息時,會正常顯示,但同樣的 notificationId 在建立第二次時,卻不會顯示通知訊息。根據官網的描述,是會先 clear 再 create,但沒說明會不會再顯示通知訊息。
> If it matches an existing notification, this method first clears that notification before proceeding with the create operation.
```javascript
chrome.notifications.clear('notificationId', function (wasCleared) {
chrome.notifications.create('newFeed', {
type: 'basic',
iconUrl: chrome.runtime.getURL('icons/icon128.png'),
title: 'New Feed!',
message: ''
}, (notificationId) => {
console.log(notificationId);
})
})
```
* 加上 buttons 提供選項,除了原先的關閉,會多出更多的選項。

```javascript
buttons: [
{
title: 'button'
},
{
title: 'button2'
}
]
```
## 打包上傳發布
### 流程
1. 進入 [Developer dashboard](https://chrome.google.com/webstore/developer/dashboard?hl=zh-tw)。
2. 點選「 Add new item 」,然後上傳打包好的 `.zip` 檔。
3. 上傳成功後,接著填寫一些相關資訊和上傳圖片等。
> Screenshots 一定要上傳,之前踩到過 [Extension 無法顯示在「 Web Store (KKBOX) > KKBOX Inc. 裡」](https://gitlab.kkinternal.com/pet/infra/issues/40#note_349471)的問題。
4. Visibility options 選擇「 Private -> Everyone at kkbox.com 」

瀏覽權限分為三種:
* **Public** - 所有使用者皆可查看及安裝應用程式或擴充功能。
* **Unlisted** - 使用者需有應用程式或擴充功能的連結,才能查看及進行安裝。應用程式不會顯示在 Chrome 線上應用程式商店的搜尋結果中。您可以將應用程式或擴充功能的連結提供給網域外的使用者。(kkbox.com 中的所有人也都能看到該商品)
* **Private** - 只有網域內的使用者才能查看及安裝應用程式或擴充功能。您也可以在開發人員資訊主頁中指定信任的測試人員,限制只有這些人員才能存取應用程式或擴充功能。
如要驗證你的帳戶並發佈商品,需支付一次性的開發人員註冊費 US$5.00 :cry: 。
如果**只對 kkbox.com 中的使用者發佈,則無需付費** :smile:。
4. 點選下方的「 Preview changes 」。
5. 預覽沒問題就可以點選「 Publish changes 」。
7. 請 **CorpIT** 人員幫忙把 Extension 加入 collection ( KKBOX Inc. ),在 Web Store 左側 KKBOX Inc. 裡看到發布的 Extension :thumbsup: 。
### Chrome auto-update
* 增加版號並重新包裝 `.zip` 上傳即可,之後 Chrome 會自動更新(時間點無法預測);無需使用者介入。切記**版號要比前一版高**。
> Upload a new ZIP file to update the manifest (which specifies information such as the name, short description, version, and permissions) or to update any other files that are part of the package that the user downloads from the store. Don’t forget to increment the version number]
>
> Every few hours, the browser checks whether any installed extensions or apps have an update URL. For each one, it makes a request to that URL looking for an update manifest XML file. If the update manifest mentions a version that is more recent than what's installed, the browser downloads and installs the new version.[name=[Autoupdating - Google Chrome](https://developer.chrome.com/apps/autoupdate)]
* [Extension 擴充功能頁](chrome://extensions/)顯示的版號是本地安裝的版本,至於最新版是多少,則要到 [Web store](https://chrome.google.com/webstore/) 上看。
* Google Chrome 每幾個小時會檢查一次是否有更新(預設是五小時),但實際更新的頻率無法掌握。
> Rory: Currently this defaults to 5 hours ([based on the code here](https://cs.chromium.org/chromium/src/extensions/common/constants.cc?q=kDefaultUpdateFrequencySeconds&dr=CSs&l=45)).
> You can override this by launching chrome with the `extensions-update-frequency` command-line parameter, which is the frequency in seconds. And you can go to `chrome://extensions`, tick the Developer mode checkbox at the top right, then press the Update Extensions Now button
>
> Chrome docs doesn't specify this 5 hour value though, so it could change in future versions without notice: Every few hours, the browser checks whether any installed extensions or apps have an update URL. For each one, it makes a request to that URL looking for an update manifest XML file.
> [name=[How often do Chrome extensions automatically update? - Stack Overflow](https://stackoverflow.com/questions/24100507/how-often-do-chrome-extensions-automatically-update)]
* 若要馬上更新,可以在 [chrome://extensions](chrome://extensions) 啟用 Developer Mode,按 Update 可以立即更新所有的 Extension。但無法更新特定的 Extension。
## 參考資料
* [Getting Started Tutorial](https://developer.chrome.com/extensions/getstarted)
* [Chrome Extension 開發經驗篇](http://jzlin-blog.logdown.com/tags/chrome%20extension)
* [Chrome Extension 開發與實作](https://ithelp.ithome.com.tw/users/20079450/ironman/1149)
* [大兜的 Chrome Extension 學習筆記](https://tonytonyjan.net/2012/05/25/get-start-with-chrome-extension/)
* [熬過了那些歷歷在目的千辛萬苦,我最後終於獲得了一些 event page 的小知識](https://pymaster.tw/posts/169400-chrome-extension-after-a-great-deal-of-trouble-i-finally-understand-the-meaning-of-event-page/)