前言:
随着如今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))
}
复制代码