WatchOS3 Complication that launches App
These code changes are required:
func getSupportedTimeTravelDirections(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTimeTravelDirections) -> Void)
{
handler([])
}
func getCurrentTimelineEntry(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTimelineEntry?) -> Void)
{
if complication.family == .circularSmall
{
let template = CLKComplicationTemplateCircularSmallRingImage()
template.imageProvider = CLKImageProvider(onePieceImage: UIImage(named: "Circular")!)
let timelineEntry = CLKComplicationTimelineEntry(date: Date(), complicationTemplate: template)
handler(timelineEntry)
} else if complication.family == .utilitarianSmall
{
let template = CLKComplicationTemplateUtilitarianSmallRingImage()
template.imageProvider = CLKImageProvider(onePieceImage: UIImage(named: "Utilitarian")!)
let timelineEntry = CLKComplicationTimelineEntry(date: Date(), complicationTemplate: template)
handler(timelineEntry)
} else if complication.family == .modularSmall
{
let template = CLKComplicationTemplateModularSmallRingImage()
template.imageProvider = CLKImageProvider(onePieceImage: UIImage(named: "Modular")!)
let timelineEntry = CLKComplicationTimelineEntry(date: Date(), complicationTemplate: template)
handler(timelineEntry)
} else {
handler(nil)
}
}
func getLocalizableSampleTemplate(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTemplate?) -> Void)
{
switch complication.family
{
case .circularSmall:
let image: UIImage = UIImage(named: "Circular")!
let template = CLKComplicationTemplateCircularSmallSimpleImage()
template.imageProvider = CLKImageProvider(onePieceImage: image)
handler(template)
case .utilitarianSmall:
let image: UIImage = UIImage(named: "Utilitarian")!
let template = CLKComplicationTemplateUtilitarianSmallSquare()
template.imageProvider = CLKImageProvider(onePieceImage: image)
handler(template)
case .modularSmall:
let image: UIImage = UIImage(named: "Modular")!
let template = CLKComplicationTemplateModularSmallSimpleImage()
template.imageProvider = CLKImageProvider(onePieceImage: image)
handler(template)
default:
handler(nil)
}
}
Plus you need to provide the images as assets in the extension.
Complication not appears in Gallery
I watch this video again and noticed ComplicationController
has prefix $(PRODUCT_MODULE_NAME)
in the target preferences:
My project didn't had this prefix, I quickly found out that ComplicationController methods never called. Because that was the place when we set tintColor
, default complication was displayed.
I solved this by deleting my watch app and watch extension targets and creating new from scratch. The prefix appeared in Xcode and I could see my app icon in Complications Gallery running in Simulator.
Where and When to get data for Watch Complication
For watchOS 3, Apple recommends that you switch from using the complication datasource getNextRequestedUpdateDate
scheduled update to update your complication.
The old way for watchOS 2
requestedUpdateDidBegin()
is really only designed to update the complication. Keeping your complication (and watch app) up to date usually involves far more than reloading the timeline (and asynchronously retrieving data never fit in well with the old approach).
The new way for watchOS 3
The new and better approach is to use background refresh app tasks. You can use a series of background tasks to schedule and handle your app extension being woken in the background to:
Fetch new data
- using WKWatchConnectivityRefreshBackgroundTask to obtain data from the phone, or
- using WKURLSessionRefreshBackgroundTask to download data from a server
- update your model once the data arrives,
- update your complication from the model (by reloading or extending the timeline), and finally
- update your app's dock snapshot to show the data on the dock
Call each tasks’s setTaskCompleted
method as soon as the task is complete.
Other benefits of using app tasks
One of the key features about this design is that the watch extension can now handle a variety of foreground and background scenarios which cover:
- initially loading data when your app/complication starts,
- updating data in the background, when the extension is woken by a background task, and
- updating data in the foreground, when the user resumes your app from the dock.
Apple recommends that you use each opportunity you are given regardless of whether your app is in the foreground or background to keep your complication, app, and dock snapshot up to date.
Are there any limitations?
The number of total available tasks per day is divided among the number of apps in the dock. The fewer apps in the dock, the more tasks your app could utilize. The more apps in the dock, the fewer you can utilize.
If your complication is active, your app can be woken up at least four times an hour.
If your complication is not active, your app is guaranteed to be woken at least once an hour.
Since your app is now running in the background, you're expected to efficiently and quickly complete your background tasks.
Background tasks are limited by the amount of CPU time and CPU usage allowed them. If you exceed the CPU time (or use more than 10% of the CPU while in the background), the system will terminate your app (resulting in a crash).
For more information
A good introduction explaining when and why to update your watch app is covered in Designing Great Apple Watch Experiences.
For specifics, the Keeping Your Watch App Up to Date session covers everything you need to know to keep your complication, app, and dock snapshot up to date.
WatchBackgroundRefresh sample code demonstrates how to use
WKRefreshBackgroundTask
to update WatchKit apps in the background.
Related Topics
Local Notification While App Not Running
How to Repeat Animation (Using Uiviewpropertyanimator) Certain Number of Times
App Crash on Sign in (Xcode 9.3) Exc_Bad_Access (Code=1, Address=0X1)
How to Properly Implement the Equatable Protocol in a Class Hierarchy
Create Skscene Subclasses Programmatically, Without Size Info
Adding a Search Bar to Navigationview in Swiftui
Swift Bindings Won't Work Xcode 6 Beta 5
How to Cast an _Nsmallocblock_ to Its Underlying Type in Swift 3
Given a Hexadecimal String in Swift, Convert to Hex Value
How to Use Objective-C Enum in Swift
How to Reload a UI View's Content Swift
Subclass Nsapplication in Swift
Swift: Extract Float from Byte Data
Target Parameter in Dispatchqueue
How to Create Text File for Writing
Convert Emoji to Hex Value Using Swift
Why Can't I Change Variables in a Protocol Extension Where Self Is a Class