diff --git a/ios/WatchApp/PhoneConnMgr.swift b/ios/WatchApp/PhoneConnMgr.swift index e361edf3..0d0df99c 100644 --- a/ios/WatchApp/PhoneConnMgr.swift +++ b/ios/WatchApp/PhoneConnMgr.swift @@ -14,13 +14,20 @@ class PhoneConnMgr: NSObject, WCSessionDelegate, ObservableObject { set { Store.setCtx(newValue) updateUrls(newValue) + + // Notify the view to update, but the [urls] are already published + // so the view will automatically update when [urls] changes. + // DispatchQueue.main.async { + // self.objectWillChange.send() + // } } get { return _ctx } } + var userInfo: [String: Any] = [:] @Published var urls: [String] = [] - + override init() { super.init() if !WCSession.isSupported() { @@ -29,24 +36,85 @@ class PhoneConnMgr: NSObject, WCSessionDelegate, ObservableObject { session = WCSession.default session?.delegate = self session?.activate() - - ctx = Store.getCtx() + + _ctx = Store.getCtx() + updateUrls(_ctx) } - + func updateUrls(_ val: [String: Any]) { if let urls = val["urls"] as? [String] { - self.urls = urls.filter { !$0.isEmpty } + DispatchQueue.main.async { + self.urls = urls.filter { !$0.isEmpty } + } } } - - func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) { - + + func session( + _ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, + error: Error? + ) { + // Request latest data when the session is activated + if activationState == .activated { + requestLatestData() + } } - // implement session:didReceiveApplicationContext: - func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any]) { - ctx = applicationContext + // Receive realtime msgs + func session(_ session: WCSession, didReceiveMessage message: [String: Any]) { + DispatchQueue.main.async { + self.ctx = message + } + } + + // Receive UserInfo + func session(_ session: WCSession, didReceiveUserInfo userInfo: [String: Any]) { + DispatchQueue.main.async { + self.ctx = userInfo + } + } + + // Receive Application Context + func session( + _ session: WCSession, didReceiveApplicationContext applicationContext: [String: Any] + ) { + DispatchQueue.main.async { + self.ctx = applicationContext + } + } + + private func requestLatestData(timeout: TimeInterval = 5.0, maxRetries: Int = 1) { + guard let session = session, session.isReachable else { return } + + var didReceiveResponse = false + var retries = 0 + + func sendRequest() { + session.sendMessage(["action": "requestData"]) { response in + didReceiveResponse = true + DispatchQueue.main.async { + self.ctx = response + } + } errorHandler: { error in + print("Request data failed: \(error)") + // Optionally, handle error UI here + } + + // Timeout handling + DispatchQueue.main.asyncAfter(deadline: .now() + timeout) { [weak self] in + guard let self = self else { return } + if !didReceiveResponse { + if retries < maxRetries { + retries += 1 + print("No response, retrying requestLatestData (\(retries))...") + sendRequest() + } else { + print("Request data timed out after \(retries + 1) attempts.") + // Optionally, update UI to indicate timeout + } + } + } + } + + sendRequest() } } - - diff --git a/lib/view/page/setting/platform/ios.dart b/lib/view/page/setting/platform/ios.dart index 7cd9a436..c7b412c6 100644 --- a/lib/view/page/setting/platform/ios.dart +++ b/lib/view/page/setting/platform/ios.dart @@ -114,7 +114,20 @@ class _IosSettingsPageState extends State { final (_, err) = await context.showLoadingDialog( fn: () async { - await wc.updateApplicationContext({'urls': result}); + final data = {'urls': result}; + + // Try realtime update (app must be running foreground). + try { + if (await wc.isReachable) { + await wc.sendMessage(data); + return; + } + } catch (e) { + Loggers.app.warning('Failed to send message to watch', e); + } + + // fallback + await wc.updateApplicationContext(data); }, ); if (err == null) {