如何让Safari网页扩展在活跃标签页无操作时统计时长?
Safari网页扩展:活跃标签页无操作时的时长统计解决方案
问题根源在于非持久化背景脚本(persistent: false)会在闲置时被系统挂起,没法持续计时。下面是具体解决方法:
核心方案:用内容脚本+页面可见性API实现持续计时
内容脚本运行在页面上下文里,只要页面处于可见状态,哪怕没操作也能稳定计时,不受背景脚本挂起影响。
1. 更新manifest.json配置
添加内容脚本权限,确保能注入到所有网站:
{ "permissions": [ "tabs", "activeTab", "storage" ], "background": { "scripts": ["background.js"], "persistent": false }, "content_scripts": [ { "matches": ["<all_urls>"], "js": ["content.js"], "run_at": "document_start" } ] }
2. 编写content.js(内容脚本)
监听页面可见性变化,启动/停止计时,定时把时长数据传给背景脚本存储:
let startTime = null; let timerId = null; // 页面可见时启动计时 function startTracking() { if (startTime) return; startTime = Date.now(); // 每10秒同步一次时长,避免频繁通信 timerId = setInterval(() => { const elapsed = Math.floor((Date.now() - startTime) / 1000); chrome.runtime.sendMessage({ type: "updateDuration", url: window.location.href, duration: elapsed }); startTime = Date.now(); // 重置起始时间,防止重复统计 }, 10000); } // 页面隐藏时停止计时 function stopTracking() { if (!startTime) return; clearInterval(timerId); const elapsed = Math.floor((Date.now() - startTime) / 1000); chrome.runtime.sendMessage({ type: "updateDuration", url: window.location.href, duration: elapsed }); startTime = null; timerId = null; } // 监听页面可见性切换 document.addEventListener("visibilitychange", () => { document.visibilityState === "visible" ? startTracking() : stopTracking(); }); // 页面加载完成后,若可见则直接开始计时 if (document.visibilityState === "visible") { startTracking(); }
3. 完善background.js(背景脚本)
接收内容脚本的消息,把时长数据存储到localStorage:
chrome.runtime.onMessage.addListener((message, sender) => { if (message.type !== "updateDuration") return; const domain = new URL(message.url).hostname; // 获取当前域名已统计的时长,累加后存回 chrome.storage.local.get([domain], (result) => { const currentTotal = result[domain] || 0; chrome.storage.local.set({ [domain]: currentTotal + message.duration }); }); });
辅助优化:标签切换时同步状态
添加标签切换监听,确保切换标签时内容脚本的计时状态正确:
在background.js中加入:
chrome.tabs.onActivated.addListener((activeInfo) => { chrome.tabs.sendMessage(activeInfo.tabId, { type: "checkVisibility" }); });
在content.js中加入:
chrome.runtime.onMessage.addListener((message) => { if (message.type === "checkVisibility") { document.visibilityState === "visible" ? startTracking() : stopTracking(); } });
注意事项
- Safari对内容脚本注入限制严格,
matches设为<all_urls>才能覆盖所有网站; - 计时间隔别太频繁(比如10秒一次),减少通信和存储开销;
- 要实现每日统计的话,可以在背景脚本里加日期判断,每天重置或归档前一天的数据。
内容的提问来源于stack exchange,提问作者Sergey Bakotin
相关产品推荐
相关产品推荐

