为iPhone应用添加WatchKit扩展:让iPhone处理业务同步至手表
完全可以用WCSession实现你的需求,这正是它设计的核心场景之一!
你的思路非常合理——让iPhone端承担所有复杂的业务逻辑(网络请求、令牌处理这些),Watch只负责接收结果并在WKInterfaceMap上展示POI,完全不需要重构现有iOS端的代码(毕竟那些带UIAlert的网络类确实没法直接在WatchKit里用)。下面我给你拆解具体的实现步骤:
1. 先明确WCSession的适配性
WCSession就是Apple专门为iOS主App和WatchKit扩展(包括Watch App和WatchKit Extension)之间的双向通信设计的API,完美匹配你的需求:
- 支持即时消息推送(适合主动刷新POI的场景)
- 支持离线缓存传输(如果Watch和iPhone断开连接,数据会暂存,等重新连接后自动同步)
- 不需要额外的服务器中转,完全是设备间的本地通信
2. 具体实现步骤
第一步:在两端激活WCSession
首先要在iOS主App和WatchKit Extension里都初始化并激活WCSession,这是通信的前提。
iOS主App端(比如在AppDelegate或SceneDelegate里):
import WatchConnectivity class AppDelegate: UIResponder, UIApplicationDelegate, WCSessionDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // 检查设备是否支持Watch Connectivity if WCSession.isSupported() { let session = WCSession.default session.delegate = self session.activate() } return true } // 必须实现的WCSessionDelegate方法 func sessionDidBecomeActive(_ session: WCSession) {} func sessionDidDeactivate(_ session: WCSession) {} func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {} }
WatchKit Extension端(在ExtensionDelegate里):
import WatchConnectivity import WatchKit class ExtensionDelegate: NSObject, WKExtensionDelegate, WCSessionDelegate { func applicationDidFinishLaunching() { if WCSession.isSupported() { let session = WCSession.default session.delegate = self session.activate() } } // 必须实现的WCSessionDelegate方法 func sessionDidBecomeActive(_ session: WCSession) {} func sessionDidDeactivate(_ session: WCSession) {} func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {} }
第二步:iOS端处理业务逻辑并发送POI数据
你的现有网络类完全不用改——继续在iOS端调用它们获取POI数据(包括令牌验证、网络请求、错误处理这些),拿到数据后用WCSession发送给Watch。
这里有两种发送方式可选:
sendMessage(_:replyHandler:errorHandler:):即时发送,适合需要Watch立即响应的场景(比如用户主动刷新POI)transferUserInfo(_:):离线缓存发送,如果Watch当前不可达,数据会暂存在iPhone上,等Watch重新连接后自动同步
举个代码例子(假设你有一个POI模型):
import WatchConnectivity import CoreLocation // 把POI模型放到共享框架里,两端都能引用(避免重复定义) struct POI: Codable { let id: String let name: String let coordinate: CLLocationCoordinate2D } // 扩展POI,实现字典转换(或者直接用Codable序列化Data) extension POI { func toDictionary() -> [String: Any] { return [ "id": id, "name": name, "latitude": coordinate.latitude, "longitude": coordinate.longitude ] } } // 在iOS端的业务类里发送数据 func sendPOIToWatch(pois: [POI]) { let session = WCSession.default let poisDict = pois.map { $0.toDictionary() } if session.isReachable { // 即时发送,适合主动刷新场景 session.sendMessage(["pois": poisDict], replyHandler: { reply in // 可选:处理Watch的回复(比如确认收到数据) }, errorHandler: { error in print("发送POI失败:\(error.localizedDescription)") }) } else { // 离线缓存,等Watch上线后自动同步 session.transferUserInfo(["pois": poisDict]) } }
第三步:Watch端接收数据并展示到WKInterfaceMap
在WatchKit的界面控制器(比如InterfaceController)里实现WCSessionDelegate的方法,接收iOS端发来的POI数据,然后解析并添加到地图上。
import WatchConnectivity import WatchKit import CoreLocation class InterfaceController: WKInterfaceController, WCSessionDelegate { @IBOutlet weak var map: WKInterfaceMap! override func awake(withContext context: Any?) { super.awake(withContext: context) if WCSession.isSupported() { WCSession.default.delegate = self WCSession.default.activate() } } // 接收即时消息 func session(_ session: WCSession, didReceiveMessage message: [String : Any]) { DispatchQueue.main.async { guard let poisDict = message["pois"] as? [[String: Any]] else { return } let pois = poisDict.compactMap { dict -> POI? in guard let id = dict["id"] as? String, let name = dict["name"] as? String, let lat = dict["latitude"] as? CLLocationDegrees, let lon = dict["longitude"] as? CLLocationDegrees else { return nil } return POI(id: id, name: name, coordinate: CLLocationCoordinate2D(latitude: lat, longitude: lon)) } // 清空旧标记,添加新POI self.map.removeAllAnnotations() pois.forEach { poi in self.map.addAnnotation(poi.coordinate, with: .red) // 可选:添加标记的交互(比如点击显示POI名称) } } } // 接收离线缓存的userInfo func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) { DispatchQueue.main.async { // 和上面的解析逻辑一致,处理缓存的POI数据 guard let poisDict = userInfo["pois"] as? [[String: Any]] else { return } // ...解析并展示 } } // 必须实现的WCSessionDelegate方法 func sessionDidBecomeActive(_ session: WCSession) {} func sessionDidDeactivate(_ session: WCSession) {} func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {} }
3. 额外注意事项
- 共享代码:把POI模型、通用工具类放到一个共享的Swift框架里,iOS和Watch端都引用这个框架,避免重复代码。
- 数据序列化:如果你的POI模型比较复杂,推荐用
Codable直接序列化/反序列化Data,比字典更安全、简洁。 - 错误处理:在发送和接收数据时,记得处理网络不可达、解析失败等异常情况。
这种方案完全规避了WatchKit不支持iOS专属API(比如UIAlert)的问题,你不需要重构任何现有iOS端的代码,所有复杂逻辑都留在iPhone上,Watch只做最纯粹的展示工作,完美贴合你的核心需求。
内容的提问来源于stack exchange,提问作者gasparuff
相关产品推荐
相关产品推荐

