WatchKit FAQ
Check out the answers to the most commonly asked questions about WatchKit – Apple’s framework for making Apple Watch apps! By Soheil Azarpour.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
WatchKit FAQ
30 mins
- Basic Questions
- What is WatchKit and how does it work?
- What’s the difference between Xcode 6.2 beta and Xcode 6.3 beta? Which one should I use for WatchKit development?
- Can you build Apple Watch apps in Swift?
- Can I create custom watch faces?
- How many Apple Watches can I pair with one iPhone?
- Can I pair my Apple Watch with an iPad?
- Can an iPhone app wake up its WatchKit extension and watch app?
- Can third-party apps make phone calls from a watch app?
- Can you access the heartbeat sensor and other sensors on the watch from your watch app?
- What are the differences between short-look, long-look, static and dynamic notifications?
- Under The Hood
- How can I test a glance or a notification using the simulator?
- Can I position interface elements on top of each other?
- Can I customize the CALayer property of interface elements?
- Can I subclass the classes available in WatchKit?
- Can I mix page-based and navigation-based interface controllers?
- Are there equivalents for UIActivityIndicator or UIAlertController on the Apple Watch?
- Can I use Core Graphics to generate images dynamically and then use them in a watch app? Can they be cached on the watch?
- Can I use custom views in the Apple Watch? Can I customize the interface elements beyond their public API?
- How does the Apple Watch communicate with your iPhone?
- Can I use the Apple Watch while in Airplane Mode?
- What happens to my app when the Apple Watch can’t communicate with its paired iPhone?
- How can a watch app communicate with its companion iPhone app?
- How can an iPhone app communicate with its watch app?
- What happens if I don’t implement static or dynamic notification interfaces?
- What’s the difference between setImage(_:) and setImageNamed(_:)?
- Can I use iCloud in a watch App?
- Animation
- How can I add animations to my watch app?
- Can I create animations for the Apple Watch in code?
- What is the maximum animation frame rate on the Apple Watch?
- Debugging and Unit Testing
- How can I run and debug both the iPhone app and the Apple Watch app at the same time using the simulators?
- How can I unit test my WatchKit extension?
- Sharing Data
- How can you share data between a WatchKit extension and its containing iOS app?
- How can you share a Core Data database between a watch app and an iPhone app?
- Let’s Get Down to Business
- Can you make games for the Apple Watch? What kinds of games are suitable?
- How can you earn money with Apple Watch apps?
- Is there any reason to believe watch apps are a new opportunity that might let developers make a living just by developing for the App Store?
- More Questions?
What happens if I don’t implement static or dynamic notification interfaces?
Even if you don’t have a watch app, the system will still display notifications for your iPhone app on the watch. However, the default notification interface has no custom styling. If you have interactive notifications, the system will hide those actions on the watch.
What’s the difference between setImage(_:) and setImageNamed(_:)?
You should use setImageNamed(_:)
when the image you want to display is either cached on the watch on is in an asset catalog in the watch app’s bundle, and use setImage(_:)
when the image isn’t cached — this will transfer the image data to the Apple Watch over the air!
An image is cached on the watch if it’s one of the following:
- Bundled with the watch app target in the project, meaning that the image resides in the asset catalog belonging to Watch App target in the project
- Explicitly cached on the watch beforehand via one of these
WKInterfaceDevice
APIs:addCachedImage(_:name:)
oraddCachedImageWithData(_:name:)
Can I use iCloud in a watch App?
Yes, you can use iCloud with the Apple Watch app. Lister: A Productivity App, which is one of the sample projects provided by Apple, demonstrates how to use iCloud in this context.
Animation
How can I add animations to my watch app?
There is only one way to display animations on the Apple Watch: image sequences. To make something appear animated, you have to pre-generate a series of images, and then cycle through them like a flip-book. The era of the animated GIF is back! ;]
You can display a sequence of static images in a WKInterfaceImage
object to create your own custom animations.
@IBOutlet weak var image: WKInterfaceImage?
...
image?.setImageNamed(image1) // Load the initial image using the required <name><number> format
image?.startAnimating() // Starts animating
...
image?.stopAnimating() // Optional. Stops animating.
You can also animate only a subset of images as shown in the following code snippet:
image?.startAnimatingWithImagesInRange(range, duration: 2, repeatCount: 1)
Can I create animations for the Apple Watch in code?
Yes, but perhaps not in the way you think – as I mentioned above there is no Core Animation framework or equivalent. You can use Core Graphics to render each frame of the animation to an offscreen context, render it to an instance of UIImage
, and at the end you’ll have a sequence of images you can animate on the Apple Watch.
The following code snippet shows how you can create an animation for a moving circle using Core Graphics by generating an image sequence for each frame (code courtesy of Jack Wu from WatchKit by Tutorials):
// Create an offscreen context
UIGraphicsBeginImageContextWithOptions(size, opaque, scale)
let context = UIGraphicsGetCurrentContext()
for centerX in 0..100 {
// Draw a circle at centerX.
// Create a snapshot.
let image = UIGraphicsGetImageFromCurrentImageContext()
// Write the image as a file
let data = UIImagePNGRepresentation(image)
let file = "path\\image_\(centerX).png"
data.writeToFile(file, atomically: true)
}
// End the context.
UIGraphicsEndImageContext()
What is the maximum animation frame rate on the Apple Watch?
You can’t set the animation frame rate on the Apple Watch. However, it’s possible to set the animation length and the let the system automatically determine the frame rate.
If the sequence of images are sent over the air, for instance when images are not cached, they will run up to 10 fps. If the images are already cached on the Apple Watch via the image cache or asset catalog in the WatchKit app bundle, they will run up to 30 fps.
Debugging and Unit Testing
How can I run and debug both the iPhone app and the Apple Watch app at the same time using the simulators?
- Build and run the watch app; this launches the Apple Watch simulator, runs the watch app and attaches it to the debugger.
- Then in the iOS simulator, tap on your iPhone app’s icon to launch it.
- Now go back to Xcode, and from the top menu select Debug\Attach To Process and then select the appropriate iPhone app. This will add a new process to your Xcode Debug Navigator and attach the iPhone app to the Debugger.
How can I unit test my WatchKit extension?
You can write unit tests for your watch app in the same way you write unit tests for your iPhone or iPad apps; simply add a new Unit Test target for the WatchKit extension to your project. However, you can’t specify the watch app as a Host Application.
You have to add every single file that you want to test to the WatchKit extension Unit Test target explicitly.
Sharing Data
How can you share data between a WatchKit extension and its containing iOS app?
You need to enable App Groups; this refers to a container on the local file system that both an extension and its containing iPhone app can access. You can define multiple app groups and enable them for different extensions.
Once App Groups are enabled, you can use either of the following techniques, based on your needs:
- Read and write to a shared container directly. You get the URL of the shared container by asking
NSFileManager
. There is a single API for this:let kMyAppGroupName = "com.raywenderlich.mywatchapp.container" var sharedContainerURL: NSURL? = NSFileManager.defaultManager(). containerURLForSecurityApplicationGroupIdentifier(kMyAppGroupName)
- Use shared
NSUserDefaults
. To create defaults storage in the shared container, you need to initialize a newNSUserDefaults
instance usingNSUserDefaults(suiteName:)
and pass in the unique identifier of the app group, like so:let kMyAppGroupName = "com.raywenderlich.mywatchapp.container" let sharedUserDefaults = NSUserDefaults(suiteName: kMyAppGroupName)
let kMyAppGroupName = "com.raywenderlich.mywatchapp.container"
var sharedContainerURL: NSURL? = NSFileManager.defaultManager().
containerURLForSecurityApplicationGroupIdentifier(kMyAppGroupName)
let kMyAppGroupName = "com.raywenderlich.mywatchapp.container"
let sharedUserDefaults = NSUserDefaults(suiteName: kMyAppGroupName)
Note: When you want to read from or write to a shared container, you must do so in a coordinated manner to avoid data corruption, because a shared container can be accessed simultaneously by separate processes. The recommended way to coordinate reads and writes is using NSFilePresenter
and NSFileCoordinator
. However, it’s advised against using file coordination APIs in an app extension because they can result in deadlocks.
The reason behind this is the lifecycle of app extensions. App extensions have only 3 states: (a) running, (b) suspended and (c) terminated. If an app extension that uses file coordination APIs is suspended while writing, it never gets the chance to relinquish ownership, so other processes get deadlocked.
However, an iPhone or an iPad application is notified via its app delegate when it’s placed in the background, and it should then remove file presenters. When the app is brought back to the foreground, the file presenters can be re-added.
Instead, you can use atomic safe-save operations like NSData
‘s writeToURL(_:atomically:)
. SQLite and Core Data also allow you to share data in a shared container in safe manner between multiple processes, even if one is suspended mid-transaction.
You can learn more about this in Technical Note TN2408: Accessing Shared Data from an App Extension and its Containing App.
Note: When you want to read from or write to a shared container, you must do so in a coordinated manner to avoid data corruption, because a shared container can be accessed simultaneously by separate processes. The recommended way to coordinate reads and writes is using NSFilePresenter
and NSFileCoordinator
. However, it’s advised against using file coordination APIs in an app extension because they can result in deadlocks.
The reason behind this is the lifecycle of app extensions. App extensions have only 3 states: (a) running, (b) suspended and (c) terminated. If an app extension that uses file coordination APIs is suspended while writing, it never gets the chance to relinquish ownership, so other processes get deadlocked.
However, an iPhone or an iPad application is notified via its app delegate when it’s placed in the background, and it should then remove file presenters. When the app is brought back to the foreground, the file presenters can be re-added.
Instead, you can use atomic safe-save operations like NSData
‘s writeToURL(_:atomically:)
. SQLite and Core Data also allow you to share data in a shared container in safe manner between multiple processes, even if one is suspended mid-transaction.
You can learn more about this in Technical Note TN2408: Accessing Shared Data from an App Extension and its Containing App.