📜 ⬆️ ⬇️

Create the first application for Apple watchOS 2

Most recently, in September, Apple released the update expected by many, the second version of the watchOS operating system. On writing of programs for it articles on Habré it was not like yet, we will try to correct this moment.

What's new


Everyone knows that the key disadvantage of all “smart watches” is the short battery life. Apple engineers decided to fix this point in a very simple way - to maximally unload the clock processor. For this, an original solution was invented - only the resources of the program were stored on the clock, and all the calculations were done on the phone processor. The watch program consisted of 2 components: the Watch App (what is stored on the watch) and WatchKit Extention (stored on the phone). Those. in fact, it was a kind of “remote desktop” for a smartphone — the application could not work without a phone nearby. As a communication channel, most likely, Bluetooth LE, which is not fast, was used. In the end, users often complained about the "inhibition" of the interface, which was a consequence of this principle. In general, despite the originality, the concept of "not soared." So, the main difference between OS2 - now the application is stored on the clock completely. However, it is still not completely independent - although the application on the clock works autonomously, there must be a “main” program for the iPhone, with which this application is installed. All this is much like a “crutch”, and in the next version there will probably not be such a restriction. However, we'll see.

If we talk about hardware, then 2 options for debugging watches are available to the programmer:
')
- 38mm screen, resolution 272x340,
- screen 42mm, resolution 312x390.

The remaining characteristics (memory, processor, etc.), on the Apple site could not find them. However, for our project it is not so important. Let's move on to the project (caution, traffic).

Create a project


Like all applications for Mac OS, iOS, programs for watchOS are created in the Xcode environment . You can download it for free in the Mac App Store. So, choose a new project in Xcode. In version 7.0, a new template iOS App with WatchKit App has appeared.



Create an application, call it WatchTest. Xcode creates a project, as shown in the figure.



As you can see, the project consists of 3 parts:

- WatchTest - the main application for iOS,
- WatchKit App - part of the application that stores resources
- WatchKit Extention - part of the application that stores the code.

(It can be seen that the division into 2 parts remains, which is similar to the N2 “crutch”, but now at least both parts are stored on the clock, and there will be no delays associated with transmitting the signal to the smartphone and back).

Create an iOS application


For training purposes, we will create something simple, such as a stopwatch program. One Label displaying time, and 2 start-stop and reset buttons. Pressing the start button starts the timer, incrementing the number of fractions of a second. Omit a lot of intermediate parts, we show immediately the result. The code (in Swift) and resources are shown in the figure.



Here you can see the controls (with the @IBOutlet tag, in our case only one UILabel) and the handlers of 2 buttons with the @IBAction tag (for those interested in more detail, you can read for example here ).

The source code of this part (after a little refactoring)
 import UIKit class ViewController: UIViewController { @IBOutlet weak var timeLabel: UILabel! var seconds: Int! var timer: NSTimer! let interval: Double = 1.0/20.0 override func viewDidLoad() { super.viewDidLoad() self.seconds = 0; // Watch support initWatchConnection() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } @IBAction func onButtonStart(sender: AnyObject) { startOrStopTimer() } @IBAction func onButtonReset(sender: AnyObject) { resetTimer() } func startOrStopTimer() { if (self.timer == nil) { self.timer = NSTimer.scheduledTimerWithTimeInterval(interval, target:self, selector:"onTimer", userInfo:nil, repeats:true) } else { self.timer.invalidate() self.timer = nil } } func resetTimer() { if (self.timer != nil) { self.timer.invalidate() self.timer = nil } self.seconds = 0; self.timeLabel.text = "0.00" } func onTimer() { self.seconds = self.seconds + 1 self.timeLabel.text = String(format: "%.2f", Double(self.seconds)*interval) } } 


Run the application, make sure that it works. Now we will create a program for the Apple Watch, which will be the “remote control” for our stopwatch. There will be 2 “start” and “reset” buttons that will activate the corresponding commands on the smartphone. This could not be done by limiting to the same stopwatch on the clock, but it is interesting to try the new Watch Connectivity framework, designed specifically for the exchange between the clock and the phone.

Create an Apple Watch application


Open the interface.storyboard on the WatchKit App. Add 2 buttons and Label to display the result. In the code, we create an object of the WCSession class, which is responsible for connecting the clock with the phone. This class has a sendCommand method, which we will use. Its parameter is dictionary, in which we can put various data. In our case, we will transmit a plain text command. The method may not be the most effective, but simple and clear.

The final result (resources + code) is shown in the figure.



Source code of this part
 import WatchKit import Foundation import WatchConnectivity class InterfaceController: WKInterfaceController, WCSessionDelegate { @IBOutlet var statusLabel: WKInterfaceLabel! private var session : WCSession! override func awakeWithContext(context: AnyObject?) { super.awakeWithContext(context) } override func willActivate() { super.willActivate() session = WCSession.isSupported() ? WCSession.defaultSession() : nil session?.delegate = self session?.activateSession() } override func didDeactivate() { session = nil super.didDeactivate() } @IBAction func onButtonStartStop() { self.sendCommand("startstop") } @IBAction func onButtonReset() { self.sendCommand("reset") } func sendCommand(cmd: String) { self.statusLabel.setText("Sending...") if let session = session where session.reachable { let applicationData = [ "body" : cmd ] session.sendMessage(applicationData, replyHandler: { replyData in self.statusLabel.setText("Send: done") }, errorHandler: { error in self.statusLabel.setText("Send: fail") }) } else { self.statusLabel.setText("No connection") } } } 


Start, press the buttons ... and nothing happens. That's right, we have not added a message handler from the clock to the main program.

We are finalizing the iOS application


We add to the iOS application almost identical code to initialize WCSession . Of interest to us is the function session: didReceiveMessage , which is automatically called as soon as the application receives a message from the clock. The parameter of this function will be the same dictionary that we sent when sending. In replyHandler we can transmit any reply that can be analyzed on the clock. The dispatch_async function (dispatch_get_main_queue ()) is needed in order to work with the timer in the main thread, otherwise it will not start correctly.

The final code is visible in the figure.



Source code completely
 import UIKit import WatchConnectivity class ViewController: UIViewController, WCSessionDelegate { @IBOutlet weak var timeLabel: UILabel! var seconds: Int! var timer: NSTimer! let interval: Double = 1.0/20.0 private var session : WCSession! override func viewDidLoad() { super.viewDidLoad() self.seconds = 0; // Watch support initWatchConnection() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } @IBAction func onButtonStart(sender: AnyObject) { startOrStopTimer() } @IBAction func onButtonReset(sender: AnyObject) { resetTimer() } func startOrStopTimer() { if (self.timer == nil) { self.timer = NSTimer.scheduledTimerWithTimeInterval(interval, target:self, selector:"onTimer", userInfo:nil, repeats:true) } else { self.timer.invalidate() self.timer = nil } } func resetTimer() { if (self.timer != nil) { self.timer.invalidate() self.timer = nil } self.seconds = 0; self.timeLabel.text = "0.00" } func onTimer() { self.seconds = self.seconds + 1 self.timeLabel.text = String(format: "%.2f", Double(self.seconds)*interval) } func initWatchConnection() { if (WCSession.isSupported()) { session = WCSession.defaultSession() session?.delegate = self session?.activateSession() } } func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void) { if let body:String = message["body"] as? String { if (body == "startstop") { dispatch_async(dispatch_get_main_queue(),{ self.startOrStopTimer() }) replyHandler([ "answer" : "OK" ]) } if (body == "reset") { dispatch_async(dispatch_get_main_queue(),{ self.resetTimer() }) replyHandler([ "answer" : "OK" ]) } } } } 


Now we start the program on the clock and the smartphone, and everything works - pressing the buttons on the clock correctly starts the timer, as desired.

Debugging


The Xcode environment comes with a fully functional simulator that looks something like this.



For some reason, among the pairs of “simulator-clock” there is only iPhone 6 and iPhone 6 Plus, I do not know whether the clock will work with other models. However, I still don’t have an Apple Watch, like the iPhone 6 / 6Plus, so there’s nothing to check “live” (it’s interesting, but not enough to pay 30 thousand rubles for a watch).

Accommodation on the App Store


This program will not be placed in the App Store. And for those who want to place their masterpieces there, I will note briefly:

- you need to add additional icons in the Watch Kit App, they will be displayed on the clock
- you need to add new screenshots and icon on the App Store
- you need to add new Apple ID for each component (App and Extention) and generate distribution-certificates for each component. In total, thus, 3 certificates per program are obtained.
- Further, as usual, Build-Archive, and the resulting archive, containing everything inside, is poured into the App Store.

Something like this. If anyone is interested, you can continue. As you can see, programming for watchOS, although it has some peculiarities, is not fundamentally different from creating an ordinary iOS program. The author wishes all successful experiments.

Source: https://habr.com/ru/post/268705/


All Articles