In May the Zalando mobile team updated our iOS app to include several extra features, including navigation and a new product detail page. We also included Apple Watch support for the very first time, to make the Zalando app more user-friendly and innovative. Because it’s so new, the WatchKit framework is likely to present some challenges even for highly experienced iOS developers. With this in mind, I'd like to share some insights regarding our team’s experience of working with it to help you avoid some pitfalls and save time.
Initially our idea was to use the WatchKit extension to implement a custom push notification. To do this, we needed to create an Apple Watch app with the Notification scene. Our key learnings:
It's not possible to send a push notification from the real environment to the Apple Watch simulator. The only way to send push notifications on the simulator is to use PushNotificationPayload.apns inside of a WatchKit extension. This payload contains an example JSON needed to send to an Apple Watch.
A "category" field in PushNotificationPayload.apns should have the same name as the “notification category” name in a Storyboard. You can create a few notification categories with different interfaces in the same project. According to the category name in the payload, the application itself decides which interface to present.
To test a push notification on the simulator, configure your targets. To do this, our team consulted the " The Build, Run, and Debug Process” section of the iOS Developers Library.
There is no guarantee that your dynamic notification will arrive. We added two types of notifications in the Apple Watch App: dynamic and static. During testing, however, only static notifications arrived on a real device. We investigated this issue and learned that dynamic notifications arrive only in special cases, such as when the Apple Watch is being worn and its battery level is above 50%. Yet even if these conditions are met, you can’t guarantee that your dynamic notification will arrive; the system decides, and there's no way to influence it.
It should be possible for developers to test dynamic notifications. Hopefully Apple will correct this soon.
You can’t create a WatchKit Extension separate from an Apple Watch App. You cannot customize the push-notification appearance without also creating a dedicated Apple Watch app, even though you might not need it. The only way to support custom notifications is to have both an app and extension.
You can’t run the iPhone app from Apple Watch. It initially seemed possible on the simulator, but when we tested our results on an actual Apple Watch we learned that we couldn’t launch a parent app from an Apple Watch app. Epic fail.
Unlike the iPhone, the Apple Watch does not support animation. By adding a set of images in Images.xcassets, we implemented a custom loading indicator. Unfortunately, this is currently the only way to display animations on the watch. Neither Core Graphics nor Core Animation are available with the watch.
Do not use the main thread in handleWatchKitExtensionRequest:reply. All interactions between the iPhone and Apple Watch are performed in the background. Calling openParentApplication:reply inside the Apple Watch app does not open the parent app, as the team initially assumed from the name; the method works only in background threads. I advise you to ensure that all the methods you invoke in the handleWatchKitExtensionRequest:reply: inside an AppDelegate do not work on the main thread. Otherwise, some problems may occur on a locked iPhone or when the main app is in the background.
Choose the right setup of provisioning profiles to avoid difficulties during app uploading. Our team’s work really started to get interesting when began to provision our profiles configuration. The biggest challenge was to set up our configs and make them work. Before making an app package, make sure that:
- bundleId of the WatchKit Extension is in format bundleId(of main app).watchkitextension
- bundleId of the Apple Watch app is in the format bundleId(of main app).watchkitapp
- WKAppBundleIdentifier (in .plist of the WatchKit Extension) is in format bundleId(of main app).watchkitapp
- WKCompanionAppBundleIdentifier (in .plist of the Apple Watch app) is the same as bundleId of the main app
We created separate provisioning profiles for the WatchKit Extension and Apple Watch app and configured them in Code Signing with the same Team name. A few odd bugs remained even after we followed these steps, but after some manipulations we were able to generate the application package.
In the end, we created a fully-functioning Apple Watch app. A simple list of current sales from the Zalando shop would have been underwhelming, so we added a detailed view, custom loading indicator and both hands-free and "force touch" event handling. The end result:
While developing the Apple Watch app, our team faced many difficulties due to the lack of documented examples to follow and learn from and lack of real devices for testing. Many behaviors that worked in a certain way on the simulator worked completely differently on the real device. But in the end, it was definitely a great learning experience!