Preface:
As nowApple
The development of ecosphere, more and moreApp
Will take their own simplified version fromiOS
The migration toWatchOS
(Alipay, wechat, Handq, Toutiao, QQ Music, netease cloud music and so on, all haveWatch
versionApp
).
So, I also tried to put our group for the first timeiOS App
The migration toApple Watch
.
From research to implementation, it took about a week. I stepped in a few potholes, too. Keep a record.
1. Apple Watch:
Apple Watch is the company’s “wellness” smartwatch. The original Apple Watch 1 was released in 2014, and by 2020, the Apple Watch 5 had been released.
There are two kinds of Apple Watch apps:
- Watch App for iOS AppFrom:
iOS
migratedWatch App
, but withiOS App
Communication. - Watch App: independent
Watch App
, can be independently installed inApple Watch
On.
Mostly the first one, Watch App for iOS App. This paper also takes the first case as an example.
Preparations:
Create a new target for watchOS.
At this point, there will be two targets: Apple Watch and Apple Watch Extension.
Note: inWatchOS
In, not likeiOS
That depends onUIKit
Write complex interfaces. For now, rely onstoryboard
Build some simple UI interface and interface jump logic.
Ii. Main differences with iOS:
- Can only use
storyboard
Drag and drop corresponding controls to build the basic UI. - Simple layout, vertical layout by default. Can be nested
Group
To fulfill the vertical layout requirements. - The value transfer between interfaces depends on
contextForSegue
Methods.
在storyboard
Set in thesegueIdentifier
.
And then the next controllerawake(withContext context: Any?)
Method receive parsingcontext
.
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"}} -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- / / at the next lower level controller, through the context object. override func awake(withContext context: Any?) { super.awake(withContext: context)letitem = context as? String // Data passed from the previous levelprint(item)
// ...
}
Copy the code
Communication between iOS and WatchOS
Apple released the WatchConnectivity framework after WatchOS 2.0 for communication between iOS and WatchOS.
1. IOS terminal implementation:
Implement a singleton WatchManager. Used to send and receive messages from the Watch terminal. After the App starts, call startSession when appropriate. Initialize WCSession reply.
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")}}Copy the code
At the same time, call the sendMessage, sendMessageData, and transferFile methods where you need to send a message to the watch. You can pass Data of types Dictionary, Data, and file.
Note: there is a pit here,
sendMessage
methodsreplyHandler
,errorHandler
Parameters cannot be passed directlynil
Otherwise the message might not get out.
ifTDWatchManager.manager.session? .isReachable ==true{/ / determine whether can reach TDWatchManager. Manager. The session? .sendMessage(["key": "value"], replyHandler: { (dict) in
print(dict)
}, errorHandler: { (error) in
print(error)
})
}
Copy the code
2.Watch end implementation:
Also, implement a singleton WatchSessionManager. Used to receive and send messages to iOS devices. After the App starts, call startSession to initialize the Session object.
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()}} WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) {print("Received userInfo for iPhone")
}
func session(_ session: WCSession, didReceive file: WCSessionFile) {
print("Received file on iPhone")
}
func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
print("Received message from iPhone")
}
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
print(session)
}
}
Copy the code
Sending and receiving messages are consistent with those on iOS. To summarize, you communicate via WatchManager singletons and receive messages via broker callbacks.
Iv. Some pits and solutions:
-
To communicate with WatchConnectivity, both the iOS App and Watch App must be alive and in the Reachable state. As long as one end is not online, there is no communication. If the real-time data is required, the Watch terminal cannot rely on the data of the iOS terminal.
-
Apple Watch devices 4 and below are 32-bit hardware and systems that cannot parse 64-bit data. (Apple Watch 5 starts with 64-bit hardware and system)
Solution:
-
For the first problem, fortunately, the Watch terminal can be connected to WiFi and supports NSURLSession. AFNetworking/Alamofire can be used to initiate requests proactively. This ensures the real-time performance of the data. But what about the logon state (token verification, etc.) in the request? The current solution is to obtain user data (token, etc.) from iOS terminal through WatchConnectivity communication and cache it locally for request. (To prevent token invalidation, update and cache the latest token when both iOS and Watch are online.)
-
For problem two, if the request contains 64-bit data (such as Int64), then the server may need to work with it. Do not include 64-bit data for the Watch. I can’t think of a better solution, after all, with 32-bit hardware.
5. Special requirements: Apple Watch generates a QR code
Thanks: Qrcode.generate () — BiliBili. Bloggers recommend EFQRCode, a powerful tripartite library of QR codes written in Swift. Supported: iOS, macOS, watchOS and tvOS.
-
Pod ‘EFQRCode/watchOS’
-
Usage: Generate qr code in Watch terminal.
let cgImage = EFQRCode.generate(content: "https://github.com/EFPrefix/EFQRCode")
if let cgImage = cgImage {
ImageView.setImage(UIImage(cgImage: cgImage))
}
Copy the code
Vi. Watch related reference learning materials
Apple Watch Development (series)