You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter应用用户使用时长追踪实现难题求助

解决方案与实现思路

一、Native侧独立处理生命周期事件与时间存储

不要依赖Flutter Method Channel在销毁时传递数据,而是让Native自己记录关键时间点并计算,或者把时间点存在本地,下次启动时再同步给Flutter统计。

Android端实现

使用ProcessLifecycleOwner监听整个应用的生命周期,它能捕捉到应用从前台到后台、以及进程即将被销毁的状态(比Activity的onDestroy更可靠):

  1. 依赖AndroidX lifecycle库(一般Flutter项目默认已引入)
  2. 注册生命周期观察者:
    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()
            }
        }
    }
    
  3. 在Application类中注册观察者:
    class MyApplication : FlutterApplication() {
        override fun onCreate() {
            super.onCreate()
            ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifecycleObserver())
        }
    }
    

iOS端实现

利用UIApplicationDelegate的方法监听应用状态:

  1. 在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读取存储的总时长,以及在需要时重置/查询:

  1. 在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) {
            // 处理错误
        }
    }
    
  2. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 10:55:12