Does anyone have sample code for complications?

I'm trying to implement a complication and it's complicated!


Does anyone know where I could find some sample code or have any they could share?

Hi,


I found it complicated to get the complications to show up in the Simulator—the code was relatively simple, but placeholders didn’t seem to show up due to caching issues.


The video ‘Creating Complications with ClockKit’ is definitely the best place to start—the code below is based on the code shown in the video.


Create a new project

------------------------------------------

I found it easier to create a new project with the complication support added in (which also generates the stubs for the data source protocol functions), and then add that to my existing project.

+ File > New > Project > watchOS > Application (‘iOS App with WatchKit App’)

+ Add in ‘Include Complication’


Targets

------------------------------------------

Check the following settings for the WatchKit Extension target:

+ Target > WatchKit Extension

+ Complications Configuration:

+ Data Source Class = %(PRODUCT_MODULE_NAME).ComplicationController

+ Supported Families: check required families (only check the ones you’re handling in the app)

+ Complications Group: Complication (this is a group inside WatchKit Extension> Assets.xcassets)


Complication Controller

------------------------------------------

I found the placeholder template the best place to start since it is less dependent on the rest of your application or data model. In ComplicationController:


func getPlaceholderTemplateForComplication(complication: CLKComplication, withHandler handler: (CLKComplicationTemplate?) -> Void) {

switch complication.family {

case .UtilitarianLarge:

let template: CLKComplicationTemplateUtilitarianLargeFlat = CLKComplicationTemplateUtilitarianLargeFlat()

let simpleTextProvider: CLKSimpleTextProvider = CLKSimpleTextProvider(text: "Hello World")

template.textProvider = simpleTextProvider

handler(template)

default:

handler(nil)

}

}


func getPrivacyBehaviorForComplication(complication: CLKComplication, withHandler handler: (CLKComplicationPrivacyBehavior) -> Void) {

handler(CLKComplicationPrivacyBehavior.ShowOnLockScreen)

}


Scheme

------------------------------------------

This scheme launches Simulator (Watch) on the Watch face, rather than on your app:

+ Complication - Test WatchKit App running on Simulator

In the console should see:

“Extension received request to wake up for complication support.”

This indicates that the placeholders have been cached; probably not a good sign if you don’t see this!


Caching

------------------------------------------

If getting stale or empty data, use ‘Apple Watch’ app on Simulator (iPhone) to toggle ‘Show App on Apple Watch’ to clear cache; or reinstall app.


David

Thanks David.


I also found this on the web which helped me get my complications working:


http://www.sneakycrab.com/blog/2015/6/10/writing-your-own-watchkit-complications

I've watched the "Creating Complciations with WatchKit" video and while I have a functioning 3rd-party complication I'm still unsure how and when the WatchKit extention is opened in the background to check if the data is stale.


Apple doesn't seem to mention this in the videos and the documention seems to be pretty vauge on the topic only stating that the extention will be woken up.


Anyone know if there is a delgate call or notificaiton that is triggered when ClockKit wakes up your extention?

I think this might be what you're looking for. From the docs (The Life Cycle of a Complication section):


After gathering your data, ClockKit calls the getNextRequestedUpdateDateWithHandler: method of your data source object to determine the time for the next update cycle. Complications should provide as much data as possible during each update cycle, so specify a date as far into the future as you can manage. Do not ask the system to update your complication within minutes. Provide data to last for many hours or for an entire day. If your data changes later, you can invalidate the current timeline and ask ClockKit to refresh your data using the methods of the CLKComplicationServer class.


The following delegate method in the ComplicationController allows you to specify how long to wait to update the content of your complication.


func getNextRequestedUpdateDateWithHandler(handler: (NSDate?) -> Void)
{
    // Call the handler with the date when you would next like to be given the opportunity to update your complication content
    handler(nil);
}


You can pass in a date in the handler like so:


func getNextRequestedUpdateDateWithHandler(handler: (NSDate?) -> Void)
{
    let nextUpdateDate:NSDate = NSDate()
      
    let oneHour:NSTimeInterval = 3600
      
    nextUpdateDate.addTimeInterval(oneHour)
      
    // Call the handler with the date when you would next like to be given the opportunity to update your complication content
    handler(nextUpdateDate);
}


This will launch your app extension every hour to check for updates.

Thanks adeeb I've looked at the docs and understand that the extention will launch but there isn't any documention on how to know in your extention that it has launched for the purpouses of updating a complication.


I'm sure this is done in the app delegate, but in my testing in the simulator I couldn't ever get the app to make any calls to applicationdidbecomeactive or applicationdidbecomeinactive.


Even if the applicationdidbecomeactive calls are happening it doesn't seem like there is a clear way to determine if the applciation is becoming active because the user has opened it on the watch or if the complciation has launched the extention in the background.

I'm having the same issue as KeatonT - not seeing the Watchkit extension launching after the time specified in getNextRequestedUpdateDateWithHandler.


For testing purposes in the Simulator I am setting this to 60 seonds later in the handler call:


handler(NSDate(timeIntervalSinceNow: 60))


But there is no sign of the extension becoming active - I assume that is the ExtensionDelegate.


Has anyone managed to get this timed background launching of the extension to work?

I'm about 90% sure now after doing a bit more research that the background updating feature hasn't been implimneted in this first beta. I wish someone at apple could or would confirm.

Thanks Keaton. Not mentioned in the release notes, which does cover some other "complications" issues.

https://developer.apple.com/library/prerelease/watchos/releasenotes/General/RN-watchOSSDK-2.0/index.html


I suppose I could file a bug - never done that before. ;-)

Yeah I noticed it wasn't mentioned in the release notes, but we also don't get any overview of backgrounding for native watch apps at all.

This is great, but I'm still getting blank complicaitons, both in the simulator and on device. I've re-installed everything from scratch to refresh the cache but I'm still not seeing anything during selection of the complication or am I seeing anything for the 'next event'.


Any ideas?


I've tried implimenting it as in the WWDC video, and also copied the code here: http://www.sneakycrab.com/blog/2015/6/10/writing-your-own-watchkit-complications but no luck.


func getPlaceholderTemplateForComplication(complication: CLKComplication, withHandler handler: (CLKComplicationTemplate?) -> Void) {
        var template: CLKComplicationTemplate? = nil
        switch complication.family {
        case .ModularSmall:
            template = nil
        case .ModularLarge:
            template = nil
        case .UtilitarianSmall:
            template = nil
        case .UtilitarianLarge:
            template = nil
        case .CircularSmall:
            let modularTemplate = CLKComplicationTemplateCircularSmallRingText()
            modularTemplate.textProvider = CLKSimpleTextProvider(text: "--")
            modularTemplate.fillFraction = 0.7
            modularTemplate.ringStyle = CLKComplicationRingStyle.Closed
            template = modularTemplate
        }
        handler(template)
    }

I've set up a sample project here with what I belive to be correct code, but I'm not seeing any data in the complication in either the template when customizing a watch face or once the complication has been selected (any template). This is testing on the simulator and actual device.


https://github.com/fluidpixel/Complications


If anyone could give it a go and see if they have the same issue or at least spot what might be wrong.


Thanks.

Well in your sample code you're never setting a placeholder template for the modular large, so the center complication in your screenshots will not have placeholder data populated.


I'm not an expert in swift but here is some sample code from my project on how to do it in Objective-C:


    CLKComplicationTemplateModularLargeStandardBody *template = [[CLKComplicationTemplateModularLargeStandardBody alloc] init];
    template.headerTextProvider = [CLKSimpleTextProvider textProviderWithText:@"Title Text"];
    template.body1TextProvider = [CLKSimpleTextProvider textProviderWithText:@"Body Text"];
    handler(template);

Thanks. I was able to get a sample app working.


When customizing a watchface and one of the fields is selected, it is highlighted in green and there is a label (black text on solid green background) with the name of the complication. For built-in choices it shows names like "STOPWATCH", "TIMER". etc.


For my sample app, the name that shows in green is a very long string "MYAPPNAME WATCHKIT A" which I assume is derived from my app project name.


How do I change this to a short meaningful phrase that only shows up when configurating the complication? Something like "MyApp". I don't want to rename my entire application to a very short name to force this. I assume there is a plist entry somewhere that I should change but I don't know where to find it.

In Beta 4 (and perhaps also in Beta 3) there are now new delegates that can be called to check if the complication needs updating, or to say that the budget is exhuasted. See the section "Resonding to Scheduled Updates" here:


https://developer.apple.com/library/prerelease/watchos/documentation/ClockKit/Reference/CLKComplicationDataSource_protocol/index.html#//apple_ref/occ/intfm/CLKComplicationDataSource/requestedUpdateDidBegin


(Hat tip to viking at this thread - https://forums.developer.apple.com/thread/6708)


Unfortunately I still don't see any sign of requestedUpdateDidBegin being called in my app running in the Simulator. (Swift apps are a mess on the actual Watch.)

I'm not seeing any sign of - (void)requestedUpdateDidBegin being called in beta 4 on the simulator.

Does anyone have sample code for complications?
 
 
Q