May 26th, 2015
We are very excited to announce that we are making the complete Highstreet WatchKit app available as open source. The WatchKit app is the latest expansion of our Highstreet shopping app platform and our first foray into Apple Watch development. It’s completely written in Swift. As always, we’ve tried to make the app as delightful and polished as we could, given WatchKit’s current limitations.
In this blog post, we’d like to take the opportunity to explain our motivations for open sourcing and provide an overview of the most interesting technical and design aspects of the app. But first, and without further ado, we should point out that the project can be found at https://github.com/GetHighstreet/HighstreetWatchApp.
The iOS development community is a great place for working with open source software. We have learned a lot from open source software and we use it on a daily basis. By open sourcing our WatchKit app, we want to contribute to the community and hope to provide a learning experience and inspiration for others.
In a recent blogpost by Natasha The Robot, she describes the trend where actual apps are being open sourced. She mentions projects and companies that are well established in our community. If it makes sense for them, we should definitely see how it works for us.
We were in the audience when Ash Furrow shared his open source story at last week’s UIKonf. He gave some concrete benefits of open sourcing, for individuals and companies alike. We will be writing better code because it is open source and, perhaps even more so, because only part of our product is.
This is the first time for us releasing a project of this size as open source. The WatchKit app was an ideal candidate because it’s self-contained, topical and the result of an interesting journey, both for engineering as well as the design perspective. We certainly hope it is useful to some of you out there.
About the App
Highstreet is a shopping app platform. The apps for iPhone and iPad offer a delightful shopping experience optimized for these devices.
We believe that an app for Apple Watch should not try to mirror all functionality from its iPhone counterpart. For that reason, we are not offering full catalog browsing or the ability to place an order. It is a very personal device, so our app should offer a personal experience. We have many ideas for what this could mean but we started with one that seems to make a lot of sense: favorites.
The basic idea of the Apple Watch app for Highstreet is to be able to quickly favorite a product on the Watch (for example from a notification) in order to check it in more detail in the iPhone app later.
While working with Apple — which is a very fancy way of saying that we were lucky enough to be invited to a WatchKit lab session -, they were pushing us to add more delight to our app. This seemed to contradict with the limitations that were posed on us through WatchKit. The key to achieving delight in our Apple Watch app was close collaboration between engineering and design in order to push the limitations of the system. Sometimes in ways that felt like ’cheating’, but only the good kind.
WatchKit offers two simple transitions: a push that comes from the right and a model that comes from the bottom. By default, the new screen will always show the WatchKit loading indicator until the interface has been loaded. It is not possible to prolong the showing of this indicator for example if additional loading is needed. The loading indicator can however be turned off for a screen, which will make the screen appear without any dynamic data.
When the user taps the ‘Promotions’ button from the launch screen of the app, a white dot can be seen to fly in from the right. The single dot turns into three dots, which then form a loading indicator. When the content is loaded, the indicator implodes and the content is revealed. The following animation provides a ‘behind the scenes’ view of this transition:
You’ll see the transition being reused in other parts of the app as well.
As said, the users of a Highstreet app can keep track of their favorite products. A favorited product is marked throughout the app with a small heart icon in the top right of a product thumbnail. On the detail screen, the user can add or remove a product from their favorites through the force press menu or with the button at the bottom of the screen. We created nice tiny animations for both actions.
With Highstreet, we’re building a platform for shopping apps. There is what we call the ‘Highstreet iOS Core’, containing all business logic and interface code for the iPhone & iPad app. The core is imported in each client project, where it is configured for that specific client. As a result, our customers all get an app that looks and feels like their brand, but the app shared 99% of the code with other Highstreet apps.
With the introduction of Apple Watch, the Highstreet platform now has a second ‘core’ that is used for the WatchKit Apps: WatchKitCore. WatchKitCore consists of two parts: the logic that is linked in every WatchKit Extension target (WatchKitExtensionCore.framework) and the assets for the WatchKit App target (storyboard, PNG sequences and other assets).
Because the WatchKit app we’re open sourcing today is part of our platform, the structure might seem a little bit more complex than a stand-alone app would be. The following diagram should shed light on the overall structure of our platform and the parts that are open source now:
The WatchKit app normally gets its data from the iPhone app, but since we’re not open sourcing that, the example app will instead use example data.
The HighstreetWatchApp project is similar to a Highstreet client project in that it imports the platform and configures it for the specific case. In this case, it is configured to load sample data and does not import the iOS app part of our platform.
The product catalogs of our customers change all the time, so we make heavy use of the ability to programatically add images to the device cache. The image cache size is limited to 5MB, so we regularly have to remove images as well. We try to be smart about it by keeping an access log and evicting the least recently accessed images (see code).
Also, all calls made to the watch after WKInterfaceDevice.addCachedImage(image:name:) are delayed until the image is transferred to the watch. There is no way of knowing if calls are being delayed or when the device has caught up.
When there are recurring elements in an interface, we usually create a custom UIView subclass that can be reused in those instances. This is not possible with WatchKit, because all interface elements are defined in the Storyboard and they cannot be subclassed. As the next best thing, we’ve created fragments. A fragment is instantiated with a fixed set of interface elements (retrieved from @IBOutlets) and takes ownership of updating these elements when the model changes.
Our ProductOutlineFragment takes care of a single product in a list of products and is used on the product list screen in the app as well as on the category and home promotion notification long looks.
One of the most compelling features of having a WatchKit app is the ability to provide a dynamic long look notification screen to our users. Apple is saying the interactions with the watch should be measured in seconds (rather than minutes on the iPhone) and this is especially true for the notifications. We therefore had to make sure that the long looks would load as quickly as possible.
Our solution is to send a silent notification to the iPhone, wich then prepares all the information needed by the long look and embeds that in the userInfo of a newly scheduled local notification.
Apple advises developers to have the iPhone app do most of the work. This is where WKInterfaceController.openParentApplication(userInfo:reply:) comes in handy. We built a typesafe command pattern on top of the NSPropertyListSerialization-based data connection. All data requests are implemented as commands that are sent to the iPhone app. We treat the reply NSDictionary as JSON and use the excellent SwiftyJSON to parse it. The execution of a command is performed asynchronously and the result is represented by a BrightFutures Future.
Early in development, when the iPhone app was not yet able to respond to all commands, we could swap out the real executor with one that would return sample data. (We are using the same approach in the open source example app.) It also allowed us to easily treat part of the userInfo of a notification as a reply to a command, which enabled the aforementioned embedding behavior.
Open Source Development
We will continue to develop our WatchKit app in the open, for the time being. This means that we directly push changes to the public repositories.
We are not expecting major contributions from the community, but would love to hear what you think about our app, code and design! Pull requests and issues are definitely welcome.
The source code is available under the MIT License. All assets are licensed under Creative Commons Attribution 4.0 International (CC BY 4.0).
Originally published at www.highstreetapp.com.