Chrome扩展内容脚本无法访问全局window对象问题求助
问题:Chrome扩展内容脚本无法访问window.phantom.solana对象?
我开发了一款Chrome扩展,能在Twitter每条推文上添加按钮,点击按钮需要调用window.phantom.solana.connect()函数。直接在浏览器控制台执行这个函数能正常运行,但在内容脚本里调用时,window对象的上下文和控制台不一样,找不到phantom.solana属性。我已经尝试过事件通信、web_accessible_resources等方法,还是没解决,请问怎么在扩展里访问到和控制台相同的window对象?
提供的代码
manifest.json
{ "manifest_version": 3, "name": "react-boilerplate", "description": "react-boilerplate for chrome extension", "version": "1.0.0", "action": { "default_title": "React Boilerplate" }, "permissions": ["tabs", "bookmarks", "storage", "identity", "scripting"], "icons": { "16": "icon.png", "48": "icon.png", "128": "icon.png" }, "background": { "service_worker": "background.js" }, "content_scripts": [ { "matches": ["https://*.twitter.com/*"], "js": ["contentScript.js"] } ], "web_accessible_resources": [ { "resources": ["web_accessible_resources.js"], "matches": ["<all_urls>"], "extension_ids": ["bfnaelmomeimhlpmgjnjophhpkkoljpa"] } ] }
内容脚本代码
import React from "react"; import { createRoot } from "react-dom/client"; import "../assets/tailwind.css"; import ContentScript from "./contentScript"; function init() { const appContainer = document.createElement("div"); if (!appContainer) { throw new Error("Cannot find app container"); } const root = createRoot(appContainer); const articleList = window.document.querySelectorAll("article"); root.render(<ContentScript />); for (const element of articleList) { var btn = document.createElement("button"); btn.appendChild(document.createTextNode("Bonk tweet")); btn.style.color = "white"; btn.addEventListener("click", function () { // this function should catch the window object chrome.runtime.sendMessage( { greetings: "Bonk tweet" }, function (response) { console.log(response.farewell); // don't have access to window.phantom.solana console.log(this); console.log(window); } ); }); element.appendChild(btn); } } setTimeout(init, 4000);
解决方案
核心原因是Chrome扩展的内容脚本运行在隔离环境,和网页自身的JS上下文完全隔离,所以无法直接访问网页注入的window.phantom对象。需要通过「注入网页脚本+跨上下文消息通信」的方式解决:
1. 修改manifest.json
调整web_accessible_resources配置,移除不必要的extension_ids限制,确保脚本能被Twitter网页访问:
"web_accessible_resources": [ { "resources": ["page-script.js"], "matches": ["https://*.twitter.com/*"] } ]
2. 创建网页注入脚本page-script.js
这个脚本会运行在网页的原生上下文,能直接访问window.phantom.solana,负责处理钱包连接逻辑并传递结果:
// 监听来自内容脚本的消息 window.addEventListener('message', (event) => { if (event.source !== window || event.data.type !== 'CONNECT_PHANTOM') return; // 调用Phantom钱包连接方法 window.phantom.solana.connect() .then((resp) => { window.postMessage({ type: 'PHANTOM_CONNECT_RESULT', data: resp }, '*'); }) .catch((err) => { window.postMessage({ type: 'PHANTOM_CONNECT_ERROR', error: err.message }, '*'); }); });
3. 修改内容脚本contentScript.js
- 先注入网页脚本到Twitter页面;
- 按钮点击时通过
postMessage触发网页脚本的连接逻辑; - 监听网页脚本返回的结果:
import React from "react"; import { createRoot } from "react-dom/client"; import "../assets/tailwind.css"; import ContentScript from "./contentScript"; function init() { // 注入网页脚本到页面上下文 const script = document.createElement('script'); script.src = chrome.runtime.getURL('page-script.js'); script.onload = () => script.remove(); document.head.appendChild(script); const appContainer = document.createElement("div"); if (!appContainer) { throw new Error("Cannot find app container"); } const root = createRoot(appContainer); const articleList = window.document.querySelectorAll("article"); root.render(<ContentScript />); // 监听网页脚本返回的连接结果 window.addEventListener('message', (event) => { if (event.source !== window) return; switch(event.data.type) { case 'PHANTOM_CONNECT_RESULT': console.log('Phantom连接成功:', event.data.data); break; case 'PHANTOM_CONNECT_ERROR': console.error('Phantom连接失败:', event.data.error); break; } }); for (const element of articleList) { const btn = document.createElement("button"); btn.appendChild(document.createTextNode("Bonk tweet")); btn.style.color = "white"; btn.addEventListener("click", function () { // 向网页脚本发送连接指令 window.postMessage({ type: 'CONNECT_PHANTOM' }, '*'); }); element.appendChild(btn); } } setTimeout(init, 4000);
注意事项
- 消息通信要通过
type字段做校验,避免和其他脚本的消息冲突; - 确保
page-script.js在扩展打包目录中,路径和manifest.json配置一致; - Manifest V3中禁止内容脚本直接修改网页window对象,必须通过这种跨上下文消息传递的方式实现。
内容的提问来源于stack exchange,提问作者Miloš Arsić
相关产品推荐
相关产品推荐

