前言:
隨着如今Apple
生態圈的發展,愈來愈多的App
會把本身的簡化版從iOS
遷移至WatchOS
(支付寶、微信、手Q、頭條、QQ音樂、網易雲音樂等等,都有Watch
版App
)。
因而,我也是第一次嘗試了把咱們的組的iOS App
遷移至Apple Watch
。
從調研到實現,大概花了一週的時間。也踩了一些坑,記錄一下。git
Apple Watch
是蘋果公司主打 「健康」 概念的智能手錶。
於2014年發佈第一代Apple Watch 1
,截至2020年,已發佈Apple Watch 5
。github
Apple Watch App
分爲兩種:緩存
iOS
遷移過來的Watch App
,可與iOS App
通訊。Watch App
,可獨立安裝在Apple Watch
上。大部分是第一種,Watch App for iOS App
。本文也是以第一種狀況舉例。bash
準備工做:微信
新建一個watchOS
的target
。session
這時,會出現兩個target:Apple Watch
、Apple Watch Extension
。app
注意:在 WatchOS
中,沒法像 iOS
那樣依賴 UIKit
寫出各類複雜的界面。目前,只能依賴 storyboard
搭建出一些簡單的UI界面與界面跳轉邏輯。框架
storyboard
拖拽相應控件,搭建基本UI。Group
來完成縱向佈局需求。contextForSegue
方法。storyboard
中設置segueIdentifier
。awake(withContext context: Any?)
方法接收解析context
。override func contextForSegue(withIdentifier segueIdentifier: String) -> Any? {
if segueIdentifier == "" {
// ...
return "A"
} else {
// ...
return "B"
}
}
override func contextForSegue(withIdentifier segueIdentifier: String, in table: WKInterfaceTable, rowIndex: Int) -> Any? {
if segueIdentifier == "" {
if rowIndex == 0 {
return "A"
} else {
return "B"
}
} else {
return "C"
}
}
--------------------------------------------
// 下一級controller中,經過context對象接收。
override func awake(withContext context: Any?) {
super.awake(withContext: context)
let item = context as? String // 上一級傳遞的數據
print(item)
// ...
}
複製代碼
Apple在 WatchOS 2.0
後發佈了 WatchConnectivity
框架,用於iOS
與WatchOS
之間的通訊。ide
實現一個單例WatchManager
。用於給Watch
端發消息、接收Watch
的消息。
App啓動後,在合適時機調用startSession
。初始化WCSession
回話。佈局
import UIKit
import WatchConnectivity
class WatchManager: NSObject, WCSessionDelegate {
static let manager = WatchManager()
var session: WCSession?
private override init() {
super.init()
}
func startSession() {
if WCSession.isSupported() {
session = WCSession.default
session?.delegate = self
self.session?.activate()
}
}
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
print(session)
}
func sessionDidBecomeInactive(_ session: WCSession) {
print("🏡sessionDidBecomeInactive")
}
func sessionDidDeactivate(_ session: WCSession) {
print("🏡sessionDidDeactivate")
}
}
複製代碼
同時,在須要給手錶發消息的地方調用sendMessage
、sendMessageData
、transferFile
方法。
能夠傳遞 Dictionary
、Data
、file
類型的數據。
注意:這裏有個坑,
sendMessage
方法的replyHandler
、errorHandler
參數不能直接傳nil
,否則消息可能會發不出去。
if TDWatchManager.manager.session?.isReachable == true { //判斷是否可達
TDWatchManager.manager.session?.sendMessage(["key": "value"], replyHandler: { (dict) in
print(dict)
}, errorHandler: { (error) in
print(error)
})
}
複製代碼
一樣,實現一個單例WatchSessionManager
。用於接收iOS
端的消息,給iOS
端發消息。
在App啓動後,調用startSession
,初始化session
對象。
import WatchKit
import WatchConnectivity
class WatchSessionManager: NSObject, WCSessionDelegate {
static let manager = WatchSessionManager()
var session: WCSession?
private override init() {
super.init()
}
func startSession() {
if WCSession.isSupported() {
session = WCSession.default
session?.delegate = self
self.session?.activate()
}
}
// 數據來源:
func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) {
print("收到iPhone端的userInfo")
}
func session(_ session: WCSession, didReceive file: WCSessionFile) {
print("收到iPhone端的file")
}
func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
print("收到iPhone端的message")
}
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
print(session)
}
}
複製代碼
發消息、接收消息也與iOS
端實現一致。
總結來講,就是經過WatchManager
單例通訊,並經過代理回調接收消息。
使用WatchConnectivity
通訊,須要iOS App
和Watch App
端同時存活,同時處於Reachable
狀態。
只要一端不在線,就沒法通訊。
若是對數據的實時性有要求,Watch
端就不能依賴iOS
端的數據了。
Apple Watch 4
及如下的設備是32
位的硬件與系統,沒法解析64
位的數據。(Apple Watch 5
開始是64
位的硬件與系統)
解決方案:
對於問題一,好在Watch
端可鏈接WiFi
,支持NSURLSession
。
能夠使用AFNetworking
/Alamofire
主動發動請求。這樣就保證的數據的實時性。
但請求裏的登陸態(token
校驗等等)怎麼辦呢?
目前的方案是,先經過WatchConnectivity
通訊從iOS端獲取用戶數據(token
等等),並緩存在Watch本地用於請求。(爲了防止token
失效等問題,只要iOS
端和Watch
端同時在線時,更新並緩存最新的token
。)
對於問題二,若是請求裏含有64
位數據(好比Int64
),那麼可能須要服務端配合處理一下了。
給Watch
端的數據不要包含64
位的數據。
目前沒想到更好的解決方法,畢竟是32
位的硬件設備。
這裏感謝:《QRCode.generate()! —— BiliBili》這篇博客。
博主推薦了一個用Swift
寫的強大的二維碼三方庫:EFQRCode。
支持: iOS, macOS, watchOS and tvOS.
導入:pod 'EFQRCode/watchOS'
使用:在Watch
端生成二維碼。
let cgImage = EFQRCode.generate(content: "https://github.com/EFPrefix/EFQRCode")
if let cgImage = cgImage {
ImageView.setImage(UIImage(cgImage: cgImage))
}
複製代碼