🎹
Chrome拡張でページ内のwindowオブジェクトを取得してpopupやbackgroundに送信する方法
Chrome 拡張からページ内の window オブジェクトにアクセスして色々やるのに少し詰まったので書きます。
ページ内の window オブジェクトを取得する
content_scripts からアクセスできる window オブジェクトはページ内の window オブジェクトとは別物です。
そのためページ内の window オブジェクトにアクセスするためには直接ページに js を埋め込む必要があります。
manifest.json
"manifest_version": 3,
"content_scripts": [
{
"matches": ["https://example.com/*"],
"js": ["content_scripts.js"]
}
],
"web_accessible_resources": [
{
"resources": ["embed.js"],
"matches": ["https://example.com/*"]
}
]
web_accessible_resources
にembed.js
を登録します。
content_scripts.js
const head = document.head
const script = document.createElement('script')
script.src = chrome.runtime.getURL('embed.js')
head.appendChild(script)
embed.js
const func = () => {
console.log(window)
}
func()
ここで window オブジェクトを操作できます。
window オブジェクトの情報を popup や background に送信する
埋め込んだ js 内ではchrome.runtime.sendMessage
が使えません。
そのため他機能と通信するためにwindow.postMessage
で一度 content_scripts を経由します。
流れとしてはこんな感じです。
実装例として popup でボタンを押したら window オブジェクトを取得してみます。
popup.tsx
export const Popup = () => {
const [state, setState] = useState()
useEffect(() => {
// content_scriptsからのメッセージを受け取ります
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
switch(request.action) {
case 'GET_WINDOW':
setState(request.data)
break
}
}
}, [])
const getWindowObject = async () => {
const tabId = await getTabId() // chrome.tabs.query()でtabIdを取得
if (tabId != null) {
// content_scriptsにメッセージを送信
chrome.tabs.sendMessage(tabId, { action: 'GET_WINDOW' })
}
}
return <button onClick={getWindowObject}>btn</button>
}
content_scripts.js
// popupからのメッセージを受け取り、embedに送信します
chrome.runtime.onMessage.addListener((request, sender) => {
window.postMessage(
{ type: 'FROM_CONTENT', action: request.action, data: request.data },
'*'
)
})
// embedからのメッセージを受け取り、popupに送信します
window.addEventListener('message', () => {
if (event.source != window) {
return
}
if (event.data.type && event.data.type === 'FROM_EMBED') {
switch (event.data.action) {
case 'GET_WINDOW':
chrome.runtime.sendMessage({
action: event.data.action,
data: event.data.data
})
break
}
}
}, false)
embed.js
// content_scriptsからのメッセージを受け取り、windowオブジェクトを取得して送信します
window.addEventListener('message', () => {
if (event.source != window) {
return
}
if (event.data.type && event.data.type === 'FROM_CONTENT') {
switch (event.data.action) {
case 'GET_WINDOW':
const data = JSON.stringify(window)
window.postMessage(
{ type: 'FROM_EMBED', action: 'GET_WINDOW', data },
'*'
)
break
}
}
}, false)
これで popup や background から window オブジェクトを操作することが出来るはずです。
まとめ
調べてもあまり出てこなかったので書いてみました。
もっと良い方法があれば教えて下さい mm
Discussion
有用な記事ありがとうございます!
冒頭のcontent_script.js部分ですが
script.src = chrome.runtime.getURL('content.js')
はscript.src = chrome.runtime.getURL('embed.js')
が正しいような気がしました。ご確認よろしくお願いいたします!
コメントありがとうございます!
ご指摘の通りembed.jsが正しかったので修正いたしました!