Flutter应用用户使用时长追踪实现难题求助
解决方案与实现思路
一、Native侧独立处理生命周期事件与时间存储
不要依赖Flutter Method Channel在销毁时传递数据,而是让Native自己记录关键时间点并计算,或者把时间点存在本地,下次启动时再同步给Flutter统计。
Android端实现
使用ProcessLifecycleOwner监听整个应用的生命周期,它能捕捉到应用从前台到后台、以及进程即将被销毁的状态(比Activity的onDestroy更可靠):
- 依赖AndroidX lifecycle库(一般Flutter项目默认已引入)
- 注册生命周期观察者:
class AppLifecycleObserver : DefaultLifecycleObserver { private val prefs = MyApplication.context.getSharedPreferences("activity_time", Context.MODE_PRIVATE) private var lastResumeTime: Long = 0 override fun onResume(owner: LifecycleOwner) { super.onResume(owner) lastResumeTime = System.currentTimeMillis() prefs.edit().putLong("last_resume", lastResumeTime).apply() } override fun onPause(owner: LifecycleOwner) { super.onPause(owner) val pauseTime = System.currentTimeMillis() val duration = pauseTime - lastResumeTime // 累加时长到本地存储 val total = prefs.getLong("total_duration", 0) + duration prefs.edit().putLong("total_duration", total).apply() prefs.edit().remove("last_resume").apply() } override fun onDestroy(owner: LifecycleOwner) { super.onDestroy(owner) // 兜底处理:如果onPause没触发(比如强杀),用当前时间计算最后一段时长 val lastResume = prefs.getLong("last_resume", 0) if (lastResume != 0) { val duration = System.currentTimeMillis() - lastResume val total = prefs.getLong("total_duration", 0) + duration prefs.edit().putLong("total_duration", total).remove("last_resume").apply() } } } - 在Application类中注册观察者:
class MyApplication : FlutterApplication() { override fun onCreate() { super.onCreate() ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifecycleObserver()) } }
iOS端实现
利用UIApplicationDelegate的方法监听应用状态:
- 在
AppDelegate.swift中实现:import UIKit import Flutter @UIApplicationMain class AppDelegate: FlutterAppDelegate { let userDefaults = UserDefaults.standard private var lastResumeTime: TimeInterval = 0 override func applicationDidBecomeActive(_ application: UIApplication) { super.applicationDidBecomeActive(application) lastResumeTime = Date().timeIntervalSince1970 * 1000 userDefaults.set(lastResumeTime, forKey: "last_resume") } override func applicationWillResignActive(_ application: UIApplication) { super.applicationWillResignActive(application) let pauseTime = Date().timeIntervalSince1970 * 1000 let duration = pauseTime - lastResumeTime let total = userDefaults.double(forKey: "total_duration") + duration userDefaults.set(total, forKey: "total_duration") userDefaults.removeObject(forKey: "last_resume") } override func applicationWillTerminate(_ application: UIApplication) { super.applicationWillTerminate(application) // 兜底处理强杀场景 if let lastResume = userDefaults.double(forKey: "last_resume") { let terminateTime = Date().timeIntervalSince1970 * 1000 let duration = terminateTime - lastResume let total = userDefaults.double(forKey: "total_duration") + duration userDefaults.set(total, forKey: "total_duration") userDefaults.removeObject(forKey: "last_resume") } } }
二、Flutter侧同步与统计
通过Method Channel从Native读取存储的总时长,以及在需要时重置/查询:
- 在Flutter中创建Method Channel:
const platform = MethodChannel('com.example.activity_time'); Future<double> getTotalDuration() async { try { final double duration = await platform.invokeMethod('getTotalDuration'); return duration; } on PlatformException catch (e) { return 0; } } Future<void> resetTotalDuration() async { try { await platform.invokeMethod('resetTotalDuration'); } on PlatformException catch (e) { // 处理错误 } } - 在Native侧实现对应的Method Channel方法(以Android为例):
class MainActivity : FlutterActivity() { private val CHANNEL = "com.example.activity_time" private val prefs by lazy { getSharedPreferences("activity_time", Context.MODE_PRIVATE) } override fun configureFlutterEngine(flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result -> when (call.method) { "getTotalDuration" -> { val total = prefs.getLong("total_duration", 0) result.success(total.toDouble()) } "resetTotalDuration" -> { prefs.edit().putLong("total_duration", 0).apply() result.success(null) } else -> result.notImplemented() } } } }
三、关键优势
- 无需频繁时间校验:只在应用前后台切换、进程销毁时计算并累加时长
- 可靠性高:Native侧独立处理生命周期,不受Flutter页面销毁影响
- 数据持久化:时间点和总时长存在Native本地存储,即使应用被强杀也不会丢失未统计的片段时长
内容的提问来源于stack exchange,提问作者Vasani Viraj
相关产品推荐
相关产品推荐

