[Chrome Extension] Content Script
keywords: chrome.runtime.getURL()
Content Script @ Chrome Developer
Content scripts 是用來在瀏覽器網頁上執行的檔案,透過 content script 可以取得網頁內容,改變 DOM,並且傳送資訊到擴充套件。
⚠️ content script 並非可以直接使用所有 chrome 提供的 API,其中可以直接使用
i18n
,storage
, runtime 裡的runtime.connect
,runtime.getManifest
,runtime.getURL
,runtime.id
,runtime.onConnect
,runtime.onMessage
,runtime.sendMessage
。
隔離的空間(Isolated Worlds)
透過 Content Script 和原本網頁上的 Script 都可以操作該頁面上的 DOM,但 Content Script 和網頁上的 Script 實際上是兩個獨立的執行環境,因此沒辦法透過 content script 去執行在網頁上所定義好的方法;反之亦然,網頁上的 JavaScript 程式也沒辦法使用到 content script 內的程式。也因此,頁面上使用到的函式庫和 content script 中使用到的函式庫即使版本不同也不會衝突:
注入程式 Inject Scripts
keywords: chrome.tabs.executeScript([<tabId>], { code, file })
Content script 可以透過 programmatically 或 declaratively 的方式注入,前者是在某個事件後注入 contentScript,後者則是在 manifest.json
中定義好規則後,會自動注入。
Inject Programmatically
要注入 programmatic content script 需要在 manifest.json
中定義 activeTab 的權限(permission),如此可以在當前的 active tab 執行 content script 而不需要指定 cross-origin permissions:
// manifest.json
{
"name": "My extension",
...
"permissions": [
"activeTab"
],
...
}
如此將可以透過 chrome.tabs.executeScript()
來注入 content script,注入的方式可以直接撰寫某一段程式碼(code
),或者執行某一支檔案(file
)
// 執行程式碼 chrome.tabs.executeScript({ code: 'alert()' });
// 執行檔案 chrome.tabs.executeScript({ file: 'filePath.js' });
chrome.runtime.onMessage.addListener((message, callback) => {
if (message == 'executeCode') {
// 執行一段程式碼
chrome.tabs.executeScript({
code: 'document.body.style.backgroundColor="orange"',
});
} else if (message == 'executeFile') {
// 執行一支檔案
chrome.tabs.executeScript({
file: 'contentScript.js',
});
}
});
Inject Declaratively
透過 declarative injection 可以自動在特定頁面執行執行 content script。declarative injection 是透過在 manifest.json
中去註冊 content_scripts
的欄位,它可以包含 JavaScript, CSS 檔或同時兩者,所有要自動執行的 content_scripts
都必須指定 match patterns。
match patterns 撰寫參考 @ Chrome Developer
// 如果有要使用 declarative content script(到特定頁面自動載入 contentScript)
{
"name": "UXTesting Extension",
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"], // <all_urls>
"exclude_matches": ["*://*/*business*"],
"include_globs": ["*nytimes.com/???s/*"],
"exclude_globs": ["*science*"],
"run_at": "document_idle", // 決定 JavaScript 注入的時間,預設是 document_idle
"css": ["myStyles.css"],
"js": ["contentScript.js"]
}
]
}
Run Time
Content Script 的 JavaScript 檔案被注入到網頁的時間可以透過 manifest.json
中的 run_at
欄位來控制,建議使用預設的 document_idle
,但如果有需要也可以指定成 document_start
或 document_end
。
執行時間的說明可參考:run time @ Chrome Developer
Content Script 和 Web Page 間的溝通
由於 Content Script 和 Web Page 是屬於各自隔離的環境(isolated worlds),若有需要彼此溝通則需要使用 window.postMessage
的方式:
// content script
var port = chrome.runtime.connect();
window.addEventListener(
'message',
function (event) {
// We only accept messages from ourselves
if (event.source != window) return;
if (event.data.type && event.data.type == 'FROM_PAGE') {
console.log('Content script received: ' + event.data.text);
port.postMessage(event.data.text);
}
},
false,
);