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

关于WCSession transferUserInfo的问题:Apple Watch发送CLLocation至iPhone无响应

解决Apple Watch通过WCSession transferUserInfo发送CLLocation无响应的问题

嘿,我之前也踩过这个一模一样的坑,咱们一步步排查为什么你的接收方法没触发:

1. 先确认WCSession的激活和配置没毛病

你代码里提到了检查WCSession.default.activationState,但要确保这几点:

  • 手表和iPhone两端都得在生命周期早期就初始化并激活WCSession——比如iPhone端在application(_:didFinishLaunchingWithOptions:)里,手表端在awake(withContext:)或者willActivate()里,不能等位置更新了才去激活,那时候可能已经晚了。
  • 两端都要设置delegate,并且必须实现session(_:activationDidCompleteWith:error:)这个代理方法,用来确认激活是否成功——要是激活失败了,后面的传输肯定没戏。
  • 发送前一定要检查WCSession.default.isReachable是否为true——如果设备没连接,transferUserInfo会把数据缓存起来,等恢复连接才发,测试时你可能误以为没触发,其实是在排队呢。

2. CLLocation的序列化是重灾区

transferUserInfo要求字典里的值必须是plist兼容类型,或者遵循NSCoding的对象。虽然CLLocation确实遵循NSCoding,但直接塞到userInfo里有时候会出问题,建议手动归档后再发:

// 手表端发送代码修改
if let location = locations.first, WCSession.default.isReachable {
    do {
        let locationData = try NSKeyedArchiver.archivedData(withRootObject: location, requiringSecureCoding: false)
        let userInfo = ["locationData": locationData]
        WCSession.default.transferUserInfo(userInfo)
        print("位置数据已发送")
    } catch {
        print("序列化CLLocation失败:\(error.localizedDescription)")
    }
}

然后iPhone端接收时再反序列化:

func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) {
    DispatchQueue.main.async {
        if let data = userInfo["locationData"] as? Data,
           let location = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? CLLocation {
            // 这里处理你的CLLocation对象
            print("收到位置:\(location.coordinate.latitude), \(location.coordinate.longitude)")
        }
    }
}

直接传CLLocation的话,系统有时候会因为序列化不彻底导致传输失败,接收端自然不会触发方法。

3. 接收端的代理方法要搞对

别搞混了方法!用transferUserInfo发送的话,对应的接收方法是session(_:didReceiveUserInfo:),不是session(_:didReceiveMessage:)(那个是即时消息用的)。另外要确保iPhone端的WCSessionDelegate确实实现了这个方法,而且没有拼写错误。

4. 测试场景的小细节

  • 测试时确保手表和iPhone是配对且正常连接的(蓝牙或Wi-Fi都可以,别开飞行模式)。
  • 如果用模拟器,要确认Watch模拟器和iPhone模拟器是配对状态(在Xcode的「Window」→「Devices and Simulators」里能设置)。
  • 有时候Xcode的调试缓存会抽风,试试重启Xcode、模拟器/真机,重新安装App,说不定就好了。

最后给你一个完整的示例参考:

手表端完整发送代码

class InterfaceController: WKInterfaceController, WCSessionDelegate, CLLocationManagerDelegate {
    var locationManager: CLLocationManager!
    
    override func awake(withContext context: Any?) {
        super.awake(withContext: context)
        // 初始化并激活WCSession
        if WCSession.isSupported() {
            WCSession.default.delegate = self
            WCSession.default.activate()
        }
        // 初始化位置管理器
        locationManager = CLLocationManager()
        locationManager.delegate = self
        locationManager.requestWhenInUseAuthorization()
        locationManager.startUpdatingLocation()
    }
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        guard let location = locations.first, WCSession.default.isReachable else { return }
        do {
            let locationData = try NSKeyedArchiver.archivedData(withRootObject: location, requiringSecureCoding: false)
            WCSession.default.transferUserInfo(["location": locationData])
        } catch {
            print("序列化失败:\(error)")
        }
    }
    
    // 必须实现的WCSession代理方法
    func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
        if let error = error {
            print("WCSession激活失败:\(error)")
        }
    }
    
    func sessionDidBecomeInactive(_ session: WCSession) {}
    func sessionDidDeactivate(_ session: WCSession) {}
}

iPhone端完整接收代码

class ViewController: UIViewController, WCSessionDelegate {
    override func viewDidLoad() {
        super.viewDidLoad()
        if WCSession.isSupported() {
            WCSession.default.delegate = self
            WCSession.default.activate()
        }
    }
    
    func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) {
        DispatchQueue.main.async {
            if let data = userInfo["location"] as? Data,
               let location = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? CLLocation {
                // 处理位置数据,比如更新UI
                print("收到位置:\(location.coordinate)")
            }
        }
    }
    
    func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {}
    func sessionDidBecomeInactive(_ session: WCSession) {}
    func sessionDidDeactivate(_ session: WCSession) {}
}

按照这个思路排查,大概率是序列化或者WCSession激活的问题,试试看!

内容的提问来源于stack exchange,提问作者Evel Knievel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:38:06