Tutorial: Create a Custom Apple Watch Face and Get Rejected by the App Store

First of all:

4.2.4 Apple Watch apps that appear to be a watch face are confusing, because people will expect them to work with device features such as swipes, notifications, and third party complications. Creative ways of expressing time as an app interface is great (say, a tide clock for surfers), but if your app comes too close to resembling a watch face, we will reject it.

Now that this is out of the way, you’ll need a Mac with Xcode installed to create your own watch face.

1. Project Set Up

On Xcode, first set up an iOS game project or a single view app. It doesn’t matter since we won’t be modifying the phone app at all. Here I’ll call the project “WatchFace”.

After the iOS project is created. Create a new Target and set it up as a watchOS game app. Here I’ll just call it “Face”.

Make sure to have “Include notification scene” unchecked.

2. Watch Face Set Up

Now you should be able to see “Face” and “Face Extension” folder. Create an Asset folder. Drag and drop a watch face background (watch_face.png) that you want to use in that folder. Then drag and drop watch_face.png into Assets.xcassets. Here is the background I used:

Click on GameScene.sks, then drag and drop the watch_face.png from the asset folder onto the template. Resize it to fill the screen.

Create a new Color Sprite and name it “HourHand”. Naming here is important because this is how the code will recognize the sprite later. Resize it to your desire dimension for the hour hand of a watch. The “Anchor Point” of this sprite should be 0 for its Y axis so that it rotates at the bottom of the watch hand. You can also use images for watch hands. Just make sure you’ve added them in the Asset folder and Assets.xcassets. In this example I’ll just use simple color sprite.

Do the same twice for “MinuteHand” and “SecondHand”.

3. Animating the Watch Face

Overwrite GameScene.swift under “Face Extension” with the following code:

import SpriteKitclass GameScene: SKScene {//Define SKSpriteNode for watch handsvar secondHand:SKSpriteNode = SKSpriteNode()var minuteHand:SKSpriteNode = SKSpriteNode()var hourHand:SKSpriteNode = SKSpriteNode()override func sceneDidLoad() {if let secHand:SKSpriteNode = self.childNode(withName: "SecondHand") as? SKSpriteNode{secondHand = secHand}if let minHand:SKSpriteNode = self.childNode(withName: "MinuteHand") as? SKSpriteNode{minuteHand = minHand}hourHand = hrHand}}override func update(_ currentTime: TimeInterval) {// Called before each frame is renderedlet date = Date()let calendar = Calendar.currentlet hour = CGFloat(calendar.component(.hour, from: date))let minutes = CGFloat(calendar.component(.minute, from: date))let seconds = CGFloat(calendar.component(.second, from: date))secondHand.zRotation = -1 * deg2rad(seconds * 6)minuteHand.zRotation = -1 * deg2rad(minutes * 6)hourHand.zRotation = -1 * deg2rad(hour * 30 + minutes/2)}func deg2rad(_ number: CGFloat) -> CGFloat {return number * .pi / 180}}

Select an iPhone emulator with Apple Watch. Click on the Run button, and you should have the watch face running on an Apple Watch emulator:

4. Hiding Status Bar Clock

The clock on the upper right hand corner will only be hidden when an app is displaying a modal. To do this, we need to first create another Interface Controller inside Interface.storyboard under the “Face” folder. Name this controller the “IntroInterfaceController” and drag the Main Entry Point to this new controller. This way the app will start with this view first.

Next, create a new swift file with WatchKit Class template and give it the same name “IntroInterfaceController”. Make sure it is the subclass of “WKInterfaceController”.

Back to the Interface.storyboard, make sure that “IntroInterfaceController” are linked to the custom class that we just created, and with module “Face_Extension”.

When you click on the controller now, you should be able to see the swift file on the right hand side. Create a button on the controller, Ctrl click and drag it onto the IntroInterfaceController.swift file. Create an action named “goToWatchFace”.

Type in the following code into the “goToWatchFace()” function and inside the awake() function:

presentController(withName: "InterfaceController", context: nil)

The finished code should look like this:

class IntroInterfaceController: WKInterfaceController {override func awake(withContext context: Any?) {super.awake(withContext: context)// Configure interface objects here.presentController(withName: "InterfaceController", context: nil)}override func willActivate() {// This method is called when watch view controller is about to be visible to usersuper.willActivate()}override func didDeactivate() {// This method is called when watch view controller is no longer visiblesuper.didDeactivate()}@IBAction func goToWatchFace() {presentController(withName: "InterfaceController", context: nil)}}

Back to Interface.storyboard, make sure that the identifier and title are “InterfaceController” and module is “Face_Extension”

Now if you click run again, the watch face will look like this:

To hide the title, go in InterfaceController.swift and paste this inside awake()

setTitle(" ")

Under willActivate() in the same file, paste in the following code so that the watch face won’t freeze when there’s a notification.

skInterface.isPaused = false

Run the program again, and you should have a custom watch face running without the clock on the upper right hand corner. Notice this watch face is off center. You can adjust the position of the background and watch hands inside GameScene.sks.

If you tap on the upper left hand corner here, which is where the blank title is, it will bring you back to this view. Simply tap on the “Watch Face” button to go back to the watch face.

5. Loading Watch Face into Apple Watch

This step is pretty easy. Just connect your iPhone to your Mac. Instead of running this on an emulator, select your iPhone and Apple Watch then click run.

After it’s finished building, you will have a custom watch face app running on your apple watch.

The date complication and different watch hands in this example were added afterwards

In your watch Settings>General>Wake Screen, you can set it to always open your last app when the your watch is raised. That way the watch app will be shown if it was the last app you used.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store