Where best to call updateApplicationContext using Watch Connectivity?
Asked Answered
L

1

5

Several of the good blog posts detailing Watch Connectivity (http://www.kristinathai.com/watchos-2-tutorial-using-application-context-to-transfer-data-watch-connectivity-2/ and http://natashatherobot.com/watchconnectivity-application-context/) use simple app examples that send data to the watch when you tap on UI on the iPhone.

My app simply lists the data from my iPhone app, so I don't need to send data immediately, I just wanted to send it when the app loads or enters background...to this end I've made the updateApplicationContext in didFinishLaunching and didEnterBackground...however my dataSource delegate in my watch interface controllers are very spotting at getting triggered...particularly the glance only loads on the simulator and never on device. Is there a better time and place to push the info?

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    WatchSessionManager.sharedManager.startSession()      
    do {
         try WatchSessionManager.sharedManager.updateApplicationContext(["peopleDict" : peopleDict])                                        
    } catch {
        print(error)
    }
     return true
}

func applicationDidEnterBackground(application: UIApplication) {     
     do {
         try WatchSessionManager.sharedManager.updateApplicationContext(["peopleDict" : peopleDict])                                      
     } catch {
         print(error)
     }
}

below is my WatchSessionManager I used to call activiateSession in my extensionDelegate's appliciationDidFinishLaunching

import WatchConnectivity

protocol DataSourceChangedDelegate {
    func dataSourceDidUpdate(dataSource: DataSource)
}


class WatchSessionManager: NSObject, WCSessionDelegate {

    static let sharedManager = WatchSessionManager()
    private override init() {
        super.init()
    }

    private var dataSourceChangedDelegates = [DataSourceChangedDelegate]()

    private let session: WCSession = WCSession.defaultSession()

    func startSession() {
        session.delegate = self
        session.activateSession()
    }

    func addDataSourceChangedDelegate<T where T: DataSourceChangedDelegate, T: Equatable>(delegate: T) {
        dataSourceChangedDelegates.append(delegate)
    }

    func removeDataSourceChangedDelegate<T where T: DataSourceChangedDelegate, T: Equatable>(delegate: T) {
        for (index, indexDelegate) in dataSourceChangedDelegates.enumerate() {
            if let indexDelegate = indexDelegate as? T where indexDelegate == delegate {
                dataSourceChangedDelegates.removeAtIndex(index)
                break
            }
        }
    }
}

// MARK: Application Context
// use when your app needs only the latest information
// if the data was not sent, it will be replaced
extension WatchSessionManager {

    // Receiver
    func session(session: WCSession, didReceiveApplicationContext applicationContext: [String : AnyObject]) {

        dispatch_async(dispatch_get_main_queue()) { [weak self] in
            self?.dataSourceChangedDelegates.forEach { $0.dataSourceDidUpdate(DataSource(data: applicationContext))}
        }

    }
}
Locker answered 21/10, 2015 at 19:15 Comment(1)
#73769669 can anyone help me to solve this problemMicronesia
H
8

As updateApplicationContext only stores the newest application context you can update it whenever you like. The watch will only get the newest data. There is no queue with old contexts.

On the watch side the most secure location to activate the session and set the WCSessionDelegate is in the ExtensionDelegate init method:

class ExtensionDelegate: NSObject, WKExtensionDelegate {

    override init() {
        super.init()
        WatchSessionManager.sharedManager.startSession()
    }
    ...
}

Your Glance does not update because when the Glance is shown, applicationDidFinishLaunching is not being called (because the watch app is not launched when only the Glance is launched)

Helgeson answered 21/10, 2015 at 21:7 Comment(8)
Thank you, and maybe I'm misunderstanding the API then... I thought that updateApplicationContext would send the data to the watch, and when the session was activated on the watch, the dataSourceDelegate would observe the updated context and make it available for use? Said another way, how can I get the updated information to my glance? I do activateSession in the ExtensionDelegate.Locker
No, you do not misunderstand the API that's how it works. Where exactly in your ExtensionDelegate do you activate the session? In applicationDidFinishLaunching or do you override init like I suggested in my answer?Helgeson
I added my WatchSessionManager class to my questionLocker
I update my answer so it calls your WatchSessionManager from the ExtensionDelegate's init method. Is this still not working?Helgeson
so take startSession out of applicationDidFinishLaunching and put it in the init only?Locker
Yes please try that. And also make sure that you added your glance view controller to the SessionManager by calling addDataSourceChangedDelegateHelgeson
it works much better now, thanks again...I've been staring at this for a week.Locker
did you manage to get data to the Glance as described above? (session setup in ExtensionDelegate init). In my app this works perfect on simulator but on device the Glance does not trigger extensionDelegate to initiate connection.Pericranium

© 2022 - 2024 — McMap. All rights reserved.