Swift+Flutter开发Apple Watch伴侣应用sendMessage退出iOS应用后失效问题
Swift+Flutter开发Apple Watch伴侣应用真机适配问题
我目前正在使用Swift和Flutter开发一款Apple Watch伴侣应用,参考了theamorn的GitHub开源项目。在iOS 15.0+WatchOS 8.0的模拟器环境下,即便强制退出iOS应用,功能也能正常运行;但在AW Series 3(WatchOS 8.0)+iPhone 11(iOS 15.0)真机测试时,仅当iOS应用处于打开状态时功能才正常。
iOS端AppDelegate.swift代码
import UIKit import Flutter import WatchConnectivity @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { var session: WCSession? let methodChannelName: String = "app.controller.watch" override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { initFlutterChannel() if WCSession.isSupported() { session = WCSession.default; session!.delegate = self; session!.activate(); } GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } private func initFlutterChannel() { if let controller = window?.rootViewController as? FlutterViewController { let channel = FlutterMethodChannel( name: methodChannelName, binaryMessenger: controller.binaryMessenger) channel.setMethodCallHandler({ [weak self] ( call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in switch call.method { case "flutterToWatch": guard let watchSession = self?.session, watchSession.isPaired, watchSession.isReachable, let methodData = call.arguments as? [String: Any], let method = methodData["method"], let data = methodData["data"] as? Any else { result(false) return } let watchData: [String: Any] = ["method": method, "data": data] watchSession.sendMessage(watchData, replyHandler: nil, errorHandler: nil) result(true) default: result(FlutterMethodNotImplemented) } }) } } } extension AppDelegate: WCSessionDelegate { func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) { } func sessionReachabilityDidChange(_ session: WCSession) { print("Watch reachability: \(session.isReachable)") if (session.isReachable) { //invoke sendWakeupToFlutter via MethodChannel when reachability is true DispatchQueue.main.async { if let controller = self.window?.rootViewController as? FlutterViewController { let channel = FlutterMethodChannel( name: self.methodChannelName, binaryMessenger: controller.binaryMessenger) channel.invokeMethod("sendWakeupToFlutter", arguments: []) } } } } func sessionDidBecomeInactive(_ session: WCSession) { } func sessionDidDeactivate(_ session: WCSession) { } func session(_ session: WCSession, didReceiveMessage message: [String : Any]) { DispatchQueue.main.async { if let method = message["method"] as? String, let controller = self.window?.rootViewController as? FlutterViewController { let channel = FlutterMethodChannel( name: self.methodChannelName, binaryMessenger: controller.binaryMessenger) channel.invokeMethod(method, arguments: message) } } } }
Watch Extension端WatchViewModel.swift代码
import Foundation import WatchConnectivity class WatchViewModel: NSObject, ObservableObject { var session: WCSession var deviceList: String = "" @Published var loading: Bool = false @Published var pubDeviceList: [Device]? // Add more cases if you have more receive method enum WatchReceiveMethod: String { case sendLoadingStateToNative case sendSSEDeviceListToNative } // Add more cases if you have more sending method enum WatchSendMethod: String { case sendWakeupToFlutter case sendCloseToFlutter } init(session: WCSession = .default) { self.session = session super.init() self.session.delegate = self session.activate() } func sendDataMessage(for method: WatchSendMethod, data: [String: Any] = [:]) { sendMessage(for: method.rawValue, data: data) } } extension WatchViewModel: WCSessionDelegate { func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) { } func sessionReachabilityDidChange(_ session: WCSession) { print("iPhone reachability: \(session.isReachable)") if(session.isReachable) { //invoke sendWakeupToFlutter via sendMessage when reachability is true sendDataMessage(for: .sendWakeupToFlutter) } } // Receive message From AppDelegate.swift that send from iOS devices func session(_ session: WCSession, didReceiveMessage message: [String : Any]) { DispatchQueue.main.sync { guard let method = message["method"] as? String, let enumMethod = WatchReceiveMethod(rawValue: method) else { return } switch enumMethod { case .sendLoadingStateToNative: self.loading = (message["data"] as? Bool) ?? false case .sendSSEDeviceListToNative: self.deviceList = (message["data"] as? String) ?? "" let data = self.deviceList.data(using: .utf8)! do { self.pubDeviceList = try JSONDecoder().decode([Device].self, from: data) } catch let error { print(error) } } } } func sendMessage(for method: String, data: [String: Any] = [:]) { guard session.isReachable else { print("ios not reachable") return } print("ios is reachable") let messageData: [String: Any] = ["method": method, "data": data] let callDepth = 10 session.sendMessage(messageData, replyHandler: nil, errorHandler: nil) } }
已尝试的修改
已对Watch Extension做如下调整:
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) { if (activationState == WCSessionActivationState.activated) { sendDataMessage(for: .sendWakeupToFlutter) } }
最终处理结果
最终采纳的答案没有完全解决问题,但改善了运行表现,最终选择开发相对独立的Watch应用,不再使用Flutter MethodChannels实现功能。
内容的提问来源于stack exchange,提问作者Jonny
相关产品推荐
相关产品推荐

