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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 06:18:03