如何在Tauri跨平台桌面应用中用JavaScript追踪用户活跃与空闲时间
实现Tauri应用的用户活跃/空闲时间全面追踪
要完成全场景的用户活跃与空闲追踪,需要结合前端DOM交互监听和Tauri系统级API,覆盖应用前台、后台、最小化等所有状态,以下是具体实现方案:
核心场景拆分与对应策略
- 前台活跃检测:通过监听用户鼠标、键盘等交互事件,实时标记活跃状态,无操作超过阈值则标记为空闲。
- 后台/最小化状态:利用Tauri调用系统原生API获取系统级空闲时间,同时监听窗口状态切换,自动切换检测逻辑。
- 系统级边界场景:捕获锁屏、睡眠、应用切换等事件,确保状态判断准确。
具体代码实现
1. 前端:前台交互监听
在你的JS文件中添加基础交互监听,维护活跃状态并触发状态回调:
let isUserActive = true; let idleTimer = null; const IDLE_THRESHOLD = 60000; // 自定义空闲阈值,示例为1分钟 // 监听所有用户交互事件 const activeTriggers = ['mousemove', 'keydown', 'click', 'scroll', 'touchstart']; activeTriggers.forEach(event => { window.addEventListener(event, handleUserActive); }); // 用户活跃时重置计时器并更新状态 function handleUserActive() { if (!isUserActive) { isUserActive = true; syncStateToBackend(true); } resetIdleTimer(); } // 启动空闲计时器 function resetIdleTimer() { if (idleTimer) clearTimeout(idleTimer); idleTimer = setTimeout(() => { isUserActive = false; syncStateToBackend(false); }, IDLE_THRESHOLD); } // 将状态同步到Tauri后端 function syncStateToBackend(isActive) { window.__TAURI__.invoke('track_state', { is_active: isActive, timestamp: Date.now() }); }
2. Tauri后端:系统空闲检测与窗口监听
在src-tauri/src/main.rs中实现跨平台系统空闲时间获取,并监听窗口状态切换:
use tauri::{Manager, WindowEvent}; use std::time::Duration; // 跨平台获取系统空闲时间(毫秒) #[tauri::command] fn get_system_idle() -> Result<u64, String> { #[cfg(target_os = "windows")] { use winapi::um::winuser::{GetLastInputInfo, LASTINPUTINFO}; let mut input_info = LASTINPUTINFO { cbSize: std::mem::size_of::<LASTINPUTINFO>() as u32, dwTime: 0, }; unsafe { if GetLastInputInfo(&mut input_info) != 0 { let tick = winapi::um::winbase::GetTickCount(); Ok((tick - input_info.dwTime) as u64) } else { Err("Failed to fetch system idle time".into()) } } } #[cfg(target_os = "macos")] { use core_foundation::base::TCFType; use core_foundation::date::CFDate; use core_graphics::event::CGEventSource; let source = CGEventSource::new(CGEventSource::STATE_SYSTEM).unwrap(); let idle = source.get_last_event_time(); let now = CFDate::now().abs_time(); Ok((now - idle) as u64) } #[cfg(target_os = "linux")] { use libxss::XScreenSaverInfo; use x11_dl::xlib; let xlib = xlib::Xlib::open().unwrap(); let display = unsafe { (xlib.XOpenDisplay)(std::ptr::null()) }; let mut info = XScreenSaverInfo::new(); unsafe { (xlib.XScreenSaverQueryInfo)(display, (xlib.XDefaultRootWindow)(display), &mut info); } Ok(info.idle as u64) } } // 接收前端状态并存储/处理 #[tauri::command] fn track_state(is_active: bool, timestamp: u64) { // 这里可以将状态写入本地文件、数据库或进行实时统计 println!("User state: {} | Timestamp: {}", is_active, timestamp); } fn main() { tauri::Builder::default() .invoke_handler(tauri::generate_handler![get_system_idle, track_state]) .setup(|app| { let main_window = app.get_window("main").unwrap(); let window_clone = main_window.clone(); // 监听窗口焦点/状态变化 main_window.on_window_event(move |event| { match event { WindowEvent::Focused(is_focused) => { if !is_focused { // 窗口失焦/最小化,启动系统空闲检测线程 std::thread::spawn(move || { loop { match get_system_idle() { Ok(idle_ms) => { let is_active = idle_ms < 60000; // 同前端阈值 window_clone.invoke("syncStateToBackend", &[is_active]).ok(); } Err(e) => eprintln!("Idle check error: {}", e), } std::thread::sleep(Duration::from_secs(1)); } }); } else { // 窗口恢复焦点,重置前端计时器 window_clone.invoke("resetIdleTimer", &[]).ok(); } } _ => {} } }); Ok(()) }) .run(tauri::generate_context!()) .expect("Failed to run Tauri app"); }
3. 数据统计与整合
在前端维护状态历史,计算总活跃/空闲时长:
const stateHistory = []; function syncStateToBackend(isActive) { const timestamp = Date.now(); stateHistory.push({ isActive, timestamp }); window.__TAURI__.invoke('track_state', { is_active: isActive, timestamp }); calculateTotalDuration(); } function calculateTotalDuration() { let totalActive = 0; let totalIdle = 0; for (let i = 1; i < stateHistory.length; i++) { const prev = stateHistory[i-1]; const curr = stateHistory[i]; const duration = curr.timestamp - prev.timestamp; if (prev.isActive) { totalActive += duration; } else { totalIdle += duration; } } console.log(`总活跃时长:${Math.floor(totalActive / 1000)}秒`); console.log(`总空闲时长:${Math.floor(totalIdle / 1000)}秒`); }
关键注意事项
- 跨平台适配:不同系统的空闲时间API差异较大,上述代码已覆盖Windows/macOS/Linux,需确保对应依赖已添加到
Cargo.toml(比如Windows的winapi,macOS的core-foundation/core-graphics,Linux的libxss/x11-dl)。 - 性能优化:后台检测线程每隔1秒执行一次即可,避免过高频率占用系统资源。
- 隐私合规:若收集用户行为数据,需在应用中明确告知用户并获得同意,符合GDPR、CCPA等法规要求。
- 边界处理:额外监听系统锁屏、睡眠事件(可通过Tauri的系统相关插件实现),确保状态判断无遗漏。
内容的提问来源于stack exchange,提问作者vasanth kumar
相关产品推荐
相关产品推荐

