Photo by Raagesh C on Unsplash
上篇利用了 Apple 的官方教學簡單了解要怎麼建立一個 Watch App,不過在教學裡的Watch 資料是可以獨立取得的,在多數的情況下,都是要從 iOS App 中取得資料,需要與 iOS App 溝通才行,而 Watch Connectivity 就是用來與WatchOS 溝通的Framework
本篇使用 Xcode 14.3 & SwiftUI
Watch Connectivity
它是負責Watch 與 App 之前的溝通,有提供幾種資料傳遞,也有提供背景傳遞方式,本篇內容是利用 Watch Connectivity 中的SendMessage 來進行簡單的資料傳遞,這種方式是必須在手錶不是在背景的情況下才可以進行資料傳送,算是比較即時的資料傳送方式
WatchConnectivity 就如它的名字是負責用來做為 WatchOS App 與 iOS App 之間的溝通,因此在 WatchOS 端與 iOS 端都需要寫相同的function 用來確認連結與傳遞資料,就如圖片所示

WCSection
WCSession 無論那種傳送方式都是使用這個 Class ,在 iOS App 與 WatchOS App 都要寫上 WCSession,它會進行檢查與傳送工作
import WatchConnectivity
if WCSession.isSupported() {
let session = WCSession.defaultSession()
session.delegate = self
session.activateSession()
}
- 需要先使用
WCSession.isSupported()
確認是否有支援互相傳送資料 - 建立一個Session基本上沒有什麼特別需求的話就直接使用Default 的就好
- 設定好 Delegate
- 最後就是 Activate session
WCSessionDelegate
這個Delegate 中有用來接收雙方資料的function 也有確認是否連線成功的 function,若使用 SwiftUI 來撰寫,接收會影響UI 更新的參數時,記得要使用 @Published var
來接,不然UI 就不會更新了
下面三個function 在 App 端一定要實作的,Watch 端的話只需要實作第一個,簡單說一下這三個的用途
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
}
func sessionDidBecomeInactive(_ session: WCSession) {
}
func sessionDidDeactivate(_ session: WCSession) {
}
activationDidCompleteWith
,就是當呼叫完activateSession
之後會觸發sessionDidBecomeInactive
,停止連線的時候會觸發sessionDidDeactivate
,當所有資料傳送完成且停止連線的時候會觸發
本篇中在這三個時機點並沒有要特別處理什麼事情,所以並不會在這三個function 裡寫東西。
Send Message
用 Message 的方式傳送的 Data 是 Dictionary ,Key 可以自定,使用 Dictionary 就可以使用Decodable 的讓它變成 Data Object 這樣之後會比較好處理
func sendHiToWatch() {
guard let wcSection = section, wcSection.isReachable else {
return
}
let hiDic = ["Say": "Hi, Watch"]
wcSection.sendMessage(hiDic) { result in
print("Result : \(result)")
}
}
在 sendHiToWatch
裡簡單建立一了個 Dictionary ,Key是 “Say”,Value是 “Hi, Watch”,因為 Message 的傳送方式 Watch App 必需要在前景,因此使用 isReachable
來確認是否可以傳送Message。
再來就是呼叫 sendMessage
這個func 將想要的資料傳送出去
Receive Message
在 WCSessionDelegate
中 didReceiveMessage
就是用來接收,可以寫在App 端與 Watch 端,接收完之後也可以依情況回傳 reply
,reply
的資訊會在 sendMessage
的Result中。
func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: @escaping ([String : Any]) -> Void) {
let hiMessage = message["Say"] as! String
DispatchQueue.main.async {
self.appMessage = hiMessage
}
let reply = ["Get": "Good"]
replyHandler(reply)
}
之所以使用 DispatchQueue.main.async{}
是因為 appMessage
這個參數是要用來更新UI 的,更新UI 的參數一定要在main thread 上才行喔。
Run
寫完之後就可以跑跑看啦~ 若是要用Simulator 的話,記得要下載Watch Simulator 並且與 iPhone Simulator 配對,此外還有一些設定要做,不然就會發現App 都可以跑起來但是就是無法傳送資料

下一篇會整理一下我在這個中間遇到的一些問題,並說明要 Simulator要如何配對
最後祝大家 Coding 愉快!!
Reference
Video
There and back again: Data transfer on Apple Watch
Introducing Watch Connectivity