iOS应用向配套WatchOS应用发送消息熄屏状态失败问题咨询
问题原因
你遇到的熄屏后设备不可达是WCSession的sendMessage接口的固有特性:该接口属于实时通信接口,要求Watch端应用必须处于前台活跃状态才能正常通信,手表熄屏后普通Watch应用会被系统挂起,WCSession的isReachable状态自然变为false,消息无法发送。
解决方案
分两种场景适配:
场景1:允许消息非实时送达(绝大多数普通应用场景)
替换sendMessage接口,改用系统自带队列缓存的通信接口,系统会在Watch应用下次唤醒时自动投递消息,无需保证实时在线:
- 如果需要传递最新的状态类数据,用
updateApplicationContext:该接口会覆盖之前的未投递数据,Watch端每次唤醒拿到的都是最新的状态 - 如果需要传递所有不可丢失的事件类数据,用
transferUserInfo:该接口会按发送顺序排队,所有数据都会被依次投递
iOS端代码修改示例
func sendMessageToWatch(type: String, message: String) { print ("Sending message to watch \(type) \(message)") let message = [type: message] do { // 替换为updateApplicationContext,不需要判断isReachable try WCSession.default.updateApplicationContext(message) } catch { print ("There was an error in sending message \(error)") debugPrint(error) } }
Watch端代理方法补充
// 接收updateApplicationContext传递的数据 func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any]) { print ("Context received in watch \(applicationContext)") DispatchQueue.main.async { // 界面更新要切主线程 WKInterfaceDevice().play(.click) let isStatusType = applicationContext["Status"] != nil if (isStatusType) { let text = applicationContext["Status"] as! String statusLabel.setText(text) } } } // 如果用transferUserInfo,补充这个代理方法 func session(_ session: WCSession, didReceive userInfo: [String : Any]) { // 处理userInfo逻辑同上 }
场景2:必须熄屏时实时送达
仅适用于拥有WatchOS后台运行权限的应用,比如体能跟踪类、音频播放类应用:
- 在Watch端项目的
Signing & Capabilities中添加对应的后台模式权限 - 启动对应后台任务后,Watch应用熄屏不会被挂起,
isReachable状态保持有效,sendMessage可正常使用
额外优化建议
两边的WCSession激活逻辑不要仅绑定到界面生命周期,最好放到应用全局入口初始化:
- iOS端放到
AppDelegate的didFinishLaunchingWithOptions方法中 - Watch端放到
ExtensionDelegate的applicationDidFinishLaunching方法中
避免界面销毁后会话失效导致的偶发通信失败。
内容的提问来源于stack exchange,提问作者touchydeer36
相关产品推荐
相关产品推荐

