Ver Fonte

feat: 补充用户在线心跳上报逻辑

陈文艺 há 1 semana atrás
pai
commit
b7f3d0ee01

+ 16 - 13
Lanu/Common/Config/LNAppConfig.swift

@@ -71,7 +71,11 @@ class LNAppConfig {
     
     @Published
     private(set) var hasNewVersion = false
-    private(set) var isForeground = true
+    private(set) var isForeground = true {
+        didSet {
+            LNEventDeliver.notifyEvent { ($0 as? LNAppMainEvent)?.onAppStateChanged(foreground: self.isForeground) }
+        }
+    }
     
     var curEnv: LNAppEnvType = LNUserDefaults[.appEnv, .official] {
         didSet {
@@ -101,7 +105,9 @@ class LNAppConfig {
         didSet {
             guard oldValue != curLang else { return }
             LNUserDefaults[.appLanguage] = curLang
-            notifyLanguageChanged()
+            LNEventDeliver.notifyEvent {
+                ($0 as? LNAppMainEvent)?.onAppLanguageChanged(newLanguage: self.curLang)
+            }
         }
     }
     
@@ -123,11 +129,17 @@ class LNAppConfig {
     init() {
         checkNewVersion()
         LNEventDeliver.addObserver(self)
-        NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: .main) { [weak self] _ in
+        NotificationCenter.default.addObserver(
+            forName: UIApplication.didEnterBackgroundNotification,
+            object: nil, queue: .main)
+        { [weak self] _ in
             guard let self else { return }
             isForeground = false
         }
-        NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: .main) { [weak self] _ in
+        NotificationCenter.default.addObserver(
+            forName: UIApplication.willEnterForegroundNotification,
+            object: nil, queue: .main)
+        { [weak self] _ in
             guard let self else { return }
             isForeground = true
         }
@@ -177,12 +189,3 @@ extension LNAppConfig: LNNetworkMonitorNotify {
         }
     }
 }
-
-extension LNAppConfig {
-    private func notifyLanguageChanged() {
-        let curLang = self.curLang
-        LNEventDeliver.notifyEvent {
-            ($0 as? LNAppMainEvent)?.onAppLanguageChanged(newLanguage: curLang)
-        }
-    }
-}

+ 42 - 0
Lanu/Manager/Account/LNAccountManager.swift

@@ -40,6 +40,10 @@ var hasLogin: Bool {
 class LNAccountManager: NSObject {
     static let shared = LNAccountManager()
     
+    private let onlineHeartbeatInterval: TimeInterval = 5
+    private var onlineHeartbeatTimer: Timer?
+    private var isReportingOnlineHeartbeat = false
+    
     private(set) var token = LNUserDefaults[.token, ""] {
         didSet { LNUserDefaults[.token] = token }
     }
@@ -279,12 +283,50 @@ extension LNAccountManager {
     }
 }
 
+extension LNAccountManager {
+    private func startOnlineHeartbeatTimerIfNeed() {
+        runOnMain { [weak self] in
+            guard let self else { return }
+            guard onlineHeartbeatTimer == nil else { return }
+            let timer = Timer.scheduledTimer(withTimeInterval: onlineHeartbeatInterval, repeats: true)
+            { [weak self] _ in
+                guard let self else { return }
+                guard wasLogin && LNAppConfig.shared.isForeground else {
+                    return
+                }
+                isReportingOnlineHeartbeat = true
+                LNHttpManager.shared.reportOnlineHeartbeat { [weak self] err in
+                    guard let self else { return }
+                    isReportingOnlineHeartbeat = false
+                    if let err {
+                        Log.d("report online heartbeat failed: \(err.errorDesc)")
+                    }
+                }
+            }
+            RunLoop.main.add(timer, forMode: .common)
+            onlineHeartbeatTimer = timer
+            Log.d("start online heartbeat")
+        }
+    }
+    
+    private func stopOnlineHeartbeatTimer() {
+        runOnMain { [weak self] in
+            guard let self else { return }
+            onlineHeartbeatTimer?.invalidate()
+            onlineHeartbeatTimer = nil
+            Log.d("stop online heartbeat")
+        }
+    }
+}
+
 extension LNAccountManager {
     private func notifyUserLogin() {
+        startOnlineHeartbeatTimerIfNeed()
         LNEventDeliver.notifyEvent { ($0 as? LNAccountManagerNotify)?.onUserLogin() }
     }
 
     private func notifyUserLogout() {
+        stopOnlineHeartbeatTimer()
         LNEventDeliver.notifyEvent { ($0 as? LNAccountManagerNotify)?.onUserLogout() }
     }
     

+ 5 - 0
Lanu/Manager/Account/Network/LNHttpManager+Account.swift

@@ -17,6 +17,7 @@ private let kNetPath_Login_Refresh = "/user/renewalToken"
 private let kNetPath_Logout = "/user/logout"
 
 private let kNetPath_Login_Captcha = "/user/login/mobile/sendCode"
+private let kNetPath_Online_Heartbeat = "/user/online/heartbeat"
 
 extension LNHttpManager {
     func loginByPhone(code: String, num: String, captcha: String,
@@ -51,6 +52,10 @@ extension LNHttpManager {
     func logout(completion: @escaping (LNHttpError?) -> Void) {
         post(path: kNetPath_Logout, completion: completion)
     }
+    
+    func reportOnlineHeartbeat(completion: @escaping (LNHttpError?) -> Void) {
+        post(path: kNetPath_Online_Heartbeat, completion: completion)
+    }
 }
 
 extension LNHttpManager {

+ 2 - 0
Lanu/Manager/LNEventDeliver.swift

@@ -10,10 +10,12 @@ import Foundation
 protocol LNAppMainEvent {
     func onAppLaunchFinished()
     func onAppLanguageChanged(newLanguage: LNAppLanguage)
+    func onAppStateChanged(foreground: Bool)
 }
 extension LNAppMainEvent {
     func onAppLaunchFinished() {}
     func onAppLanguageChanged(newLanguage: LNAppLanguage) {}
+    func onAppStateChanged(foreground: Bool) { }
 }
 
 class LNEventDeliver {