Chrome扩展Manifest V3:MAIN世界脚本如何传递数据至本地世界
解决Manifest V3中MAIN世界脚本向扩展本地世界传递数据的方案
针对你遇到的MAIN世界脚本无法调用chrome.runtime.sendMessage的问题,这里提供两种可行的实现方案:
方案一:DOM自定义事件桥接 + Service Worker中转
通过MAIN世界脚本触发自定义DOM事件,隔离世界脚本监听后转发至Service Worker,再由Popup从Service Worker获取数据。
1. 配置Manifest.json
添加MAIN世界和隔离世界的Content Script,以及Service Worker声明:
{ "manifest_version": 3, "name": "Yandex Music Discord RPC", "version": "1.0", "content_scripts": [ // MAIN世界脚本:获取歌曲数据 { "matches": ["https://music.yandex.ru/*"], "js": ["main-world-script.js"], "world": "MAIN" }, // 隔离世界脚本:转发数据至Service Worker { "matches": ["https://music.yandex.ru/*"], "js": ["isolate-world-script.js"] } ], "background": { "service_worker": "background.js" }, "permissions": ["storage"], "host_permissions": ["https://music.yandex.ru/*"] }
2. MAIN世界脚本(main-world-script.js)
定时获取歌曲数据,通过自定义DOM事件传递至隔离世界:
// 每秒获取一次当前播放歌曲 setInterval(() => { try { const track = externalAPI.getCurrentTrack(); if (track) { // 触发跨世界可监听的自定义事件 const updateEvent = new CustomEvent('yandex-track-updated', { detail: track, bubbles: true, composed: true }); document.dispatchEvent(updateEvent); } } catch (err) { console.error("获取歌曲数据失败:", err); } }, 1000);
3. 隔离世界脚本(isolate-world-script.js)
监听自定义事件,将数据转发至Service Worker:
document.addEventListener('yandex-track-updated', (e) => { const trackData = e.detail; // 调用扩展API发送数据至Service Worker chrome.runtime.sendMessage({ type: "TRACK_UPDATE", data: trackData }); });
4. Service Worker(background.js)
存储实时歌曲数据,供Popup请求:
let currentTrack = null; // 接收Content Script发来的歌曲数据 chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => { if (msg.type === "TRACK_UPDATE") { currentTrack = msg.data; } }); // 响应Popup的数据请求 chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => { if (msg.type === "GET_CURRENT_TRACK") { sendResponse(currentTrack); } });
5. Popup.js 获取数据并处理Discord RPC
document.addEventListener('DOMContentLoaded', () => { // 请求当前歌曲数据 chrome.runtime.sendMessage({ type: "GET_CURRENT_TRACK" }, (track) => { if (track) { // 这里编写Discord RPC逻辑 console.log("当前播放:", `${track.title} - ${track.artists.map(a => a.name).join(', ')}`); // 示例:discordRpc.setActivity({ details: track.title, state: track.artists[0].name }); } }); // 监听实时更新(可选) chrome.runtime.onMessage.addListener((msg) => { if (msg.type === "TRACK_UPDATE") { // 实时更新Discord状态 console.log("歌曲更新:", msg.data.title); } }); });
方案二:Popup直接调用MAIN世界接口
如果不需要实时监听,可在Popup打开时通过chrome.scripting.executeScript直接在MAIN世界执行代码获取数据。
1. 更新Manifest.json权限
添加scripting和activeTab权限:
{ "permissions": ["scripting", "activeTab"], // 其他配置... }
2. Popup.js 直接获取数据
document.addEventListener('DOMContentLoaded', async () => { try { // 获取当前激活的标签页 const [activeTab] = await chrome.tabs.query({ active: true, currentWindow: true }); // 在MAIN世界执行代码获取歌曲 const [result] = await chrome.scripting.executeScript({ target: { tabId: activeTab.id }, func: () => externalAPI.getCurrentTrack(), world: "MAIN" }); const track = result.result; if (track) { // 处理Discord RPC逻辑 console.log("当前歌曲:", track); } } catch (err) { console.error("获取歌曲失败:", err); } });
内容的提问来源于stack exchange,提问作者Ильдар Гранкин
相关产品推荐
相关产品推荐

