MikeB
MikeB

Reputation: 1659

Complication Timeline update with data from iPhone

I am trying to write a complication for watchOS 2 GM that displays a value it gets from my iPhone (iOS 9 GM) using WCSession.

Unfortunately I get the following error when sending a message:

Error Domain=WCErrorDomain Code=7014 "Payload could not be delivered." UserInfo={NSLocalizedDescription=Payload could not be delivered.}

This is what my code looks like in ComplicationController.swift:

import ClockKit
import WatchConnectivity

class ComplicationController: NSObject, CLKComplicationDataSource,WCSessionDelegate {

// MARK: - Timeline Configuration

var session : WCSession.defaultSession()
var myValue : Int?

...

func getCurrentTimelineEntryForComplication(complication: CLKComplication, withHandler handler: ((CLKComplicationTimelineEntry?) -> Void)) {

    getInfo()

    if self.myValue != nil {
        if complication.family == .CircularSmall {
            let template = CLKComplicationTemplateCircularSmallRingText()
            template.textProvider = CLKSimpleTextProvider(text: "\(self.myValue)")
            template.fillFraction = Float(self.myValue!) / 100
            template.ringStyle = CLKComplicationRingStyle.Closed

            let timelineEntry = CLKComplicationTimelineEntry(date: NSDate(), complicationTemplate: template)
            handler(timelineEntry)
        } else {
            handler(nil)
        }
    }

}

func requestedUpdateDidBegin(){
   getInfo()
}

// MARK: - Update Scheduling

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(NSDate(timeIntervalSinceNow: 5)); // only that low for debugging
}

func getInfo(){
        if (WCSession.defaultSession().reachable) {

            let messageToSend = ["Value":"Info"]
            session.sendMessage(messageToSend, replyHandler: { replyMessage in
                //handle and present the message on screen
                let value:[String:AnyObject] = replyMessage

                if value.indexForKey("myValue") != nil{
                    self.myValue = value["myValue"]! as? Int
                    print("Value: \(self.myValue)")
                }

             }, errorHandler: {error in
                    // catch any errors here
                    print(error)  
            })
        }
}

This is my ExtensionDelegate.swift:

import WatchKit
import WatchConnectivity

class ExtensionDelegate: NSObject, WKExtensionDelegate,WCSessionDelegate {
var session:WCSession!

func applicationDidFinishLaunching() {
    // Perform any final initialization of your application.
    if (WCSession.isSupported()) {
        session = WCSession.defaultSession()
        session.delegate = self
        session.activateSession()
    }
}

...

And finally my iOS AppDelegate:

import UIKit
import WatchConnectivity

class AppDelegate: UIResponder, UIApplicationDelegate, WCSessionDelegate {

var window: UIWindow?
var myDevice: UIDevice?

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    if (WCSession.isSupported()) {
        let session = WCSession.defaultSession()
        session.delegate = self // conforms to WCSessionDelegate
        session.activateSession()
    }

    application.statusBarStyle = UIStatusBarStyle.LightContent

    return true

}

func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void) {
    var reply = [String:AnyObject]()

    // some logic
    let value = //some Int value
    reply.updateValue(value, forKey: "myValue")

    replyHandler(reply)
}

Any ideas?

Thanks in advance!

Upvotes: 3

Views: 1717

Answers (1)

Mark Semsel
Mark Semsel

Reputation: 7155

A few things that will help you set things up so you can update your complications.

Generally, you'd want to have your timeline data already available for those points when the CLKComplicationDataSource methods are called. (Not always easy to do).

It looks like both your ComplicationController and ExtensionDelegate are being used as WCSessionDelegates. Use it in one place (probably ExtensionDelegate) and not the other, on the watch.

You have set up your AppDelegate to respond to a message, but any message handled by that didReceiveMessage method will only be coming from your Watch.

Determine where your message is originally coming from (maybe an external notification?), and send that info to the watch as a dictionary via WCSession 'send' methods.

Have your ExtensionDelegate (or whomever is responding to WCSessionDelegate methods) respond to the corresponding 'receive' methods to capture that sent info.

THEN: Kick off a refresh of your timeline by having the CLKComplicationServer reload your timeline.

Upvotes: 1

Related Questions