如何在Chrome Extension MV3的background.js中获取系统明暗主题设置?
解决MV3后台脚本无法检测系统主题变化的问题
由于MV3的后台脚本运行在Service Worker环境中,没有window对象,因此无法直接调用window.matchMedia。以下是两种可靠的解决方案:
方案一:使用Offscreen Document(推荐,持久监听)
Offscreen Document是MV3新增的API,用于替代原background.html的部分场景,可在独立页面环境中运行代码,支持window相关API。
1. 修改manifest.json配置
添加offscreen权限和文档路径:
{ "manifest_version": 3, "permissions": ["offscreen"], "background": { "service_worker": "background.js" }, "offscreen": { "page": "offscreen.html", "persistent": false } }
2. 创建offscreen.html
<!DOCTYPE html> <html> <body> <script src="offscreen.js"></script> </body> </html>
3. 编写offscreen.js(监听主题变化并通知后台)
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); // 向后台发送主题状态 function sendThemeUpdate(isDark) { chrome.runtime.sendMessage({ type: 'theme_updated', isDark }); } // 初始发送一次当前主题状态 sendThemeUpdate(mediaQuery.matches); // 监听主题变化 mediaQuery.addEventListener('change', (e) => { sendThemeUpdate(e.matches); });
4. 修改background.js(接收消息并更新图标)
// 确保offscreen文档已加载 async function initOffscreen() { if (await chrome.offscreen.hasDocument()) return; await chrome.offscreen.createDocument({ url: 'offscreen.html', reasons: ['USER_INTERFACE'], justification: '监听系统主题变化以同步扩展图标' }); } // 接收来自offscreen的主题消息,更新扩展图标 chrome.runtime.onMessage.addListener((msg) => { if (msg.type === 'theme_updated') { const iconPath = msg.isDark ? 'icons/dark.png' : 'icons/light.png'; chrome.action.setIcon({ path: iconPath }); } }); // 后台启动时初始化offscreen (async () => { await initOffscreen(); })();
方案二:使用Content Script + Storage(依赖网页环境)
如果你的扩展已包含内容脚本,可利用网页环境的window对象监听主题变化,再通过Storage同步到后台。
1. 修改manifest.json配置
添加content script和storage权限:
{ "manifest_version": 3, "content_scripts": [ { "matches": ["<all_urls>"], "js": ["content-script.js"], "run_at": "document_start" } ], "permissions": ["storage"] }
2. 编写content-script.js(监听主题变化并更新Storage)
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); // 更新Storage中的主题状态 function syncThemeToStorage(isDark) { chrome.storage.local.set({ isDarkTheme: isDark }); } // 初始同步一次 syncThemeToStorage(mediaQuery.matches); // 监听主题变化并同步 mediaQuery.addEventListener('change', (e) => { syncThemeToStorage(e.matches); });
3. 修改background.js(监听Storage变化并更新图标)
// 初始获取主题状态并设置图标 chrome.storage.local.get('isDarkTheme', (res) => { const isDark = res.isDarkTheme ?? false; // 默认浅色主题 const iconPath = isDark ? 'icons/dark.png' : 'icons/light.png'; chrome.action.setIcon({ path: iconPath }); }); // 监听Storage变化,实时更新图标 chrome.storage.onChanged.addListener((changes) => { if (changes.isDarkTheme) { const isDark = changes.isDarkTheme.newValue; const iconPath = isDark ? 'icons/dark.png' : 'icons/light.png'; chrome.action.setIcon({ path: iconPath }); } });
注意:方案二的局限性在于,若用户未打开任何网页,Content Script无法运行,无法监听主题变化。因此更推荐方案一。
内容的提问来源于stack exchange,提问作者AGamePlayer
相关产品推荐
相关产品推荐

