iosswiftuiwatchkitwatchconnectivityapple-watch-complication

WatchKit complication not updating


I want to do something that seems simple - I have an app on the iPhone that allows you to change a date. On the watch, I have a complication that shows among other things the days until that date. So clearly, when you change the date on the iPhone app, I want the date on the watch to change and that state to be persisted until or if you change the date on the iPhone again.

What I've done is created a state object included in both the complication and the watch app, and in both I just do this to display the value

    @ObservedObject state = OneDayState.shared

    ...
    Text( state.daysUntilValue )

what is happening when I change the date on the iphone:

What I want to happen

Here is the code of my state object - what am I doing wrong?? (thx)

class OneDayState : NSObject, ObservableObject, WCSessionDelegate
{
    
    static let shared = OneDayState()
    
    //
    // connection to the settings
    //
    let session = WCSession.default

    //
    // connection to the user defaults
    //
    let settings =  UserDefaults(suiteName: "[removed]")!;

    //
    // what is watched by the UI
    //
    var daysUntilValue : String {
        return  String( Calendar.current.dateComponents( [.day], from: .now, to: theDate).day!)
    }
    
    //
    // the target date
    //
    @Published var theDate : Date = Date.now

    //
    // setup this
    //
    override init()
    {
        super.init()
        session.delegate = self
        session.activate()
        theDate = settings.object(forKey: "target" ) as? Date ?? Date.now;
    }

    //
    // you seem to have to override this
    //
    func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
        print("sesison activated")
    }

    //
    // when the application context changes, we just store the new date
    //
    func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any])
    {
        let newDate = applicationContext["target"] as? Date ?? Date.now;
        DispatchQueue.main.async
        {
            self.settings.set( newDate, forKey: "target")
            self.theDate = newDate;
        }
    }
        
}

Solution

  • When your watch app is running in background, you should use WKWatchConnectivityRefreshBackgroundTask to get the data from iPhone.

    WKWatchConnectivityRefreshBackgroundTask

    Currently WKWatchConnectivityRefreshBackgroundTask, so you watch won't get the data until it goes foreground.

    Then you need to manually update your complication yourself.