3

I need to get a number from userDefaults to use in an Apple Watch app to make some calculations, I'm using the WatchConnectivity framework to get this piece of information but what I don't like about the way I have it right now is that the Phone only sends the data to the Watch when the iPhone app is loaded (viewDidLoad), in other words is I launch the Watch app I need to open the iPhone app in order to get the data to the Apple Watch.

Is it possible to get data from iPhone when it is not active?

Here is the code I'm using:

iOS View Controller

class ViewController: UIViewController, WCSessionDelegate {
    var session: WCSession!

    override func viewDidLoad() {
        super.viewDidLoad()

        if WCSession.isSupported() {
            session = WCSession.default()
            session.delegate = self
            session.activate()
        }
    }

    func session(_ session: WCSession, activationDidCompleteWith activationState:WCSessionActivationState, error: Error?) {}
    func sessionDidDeactivate(_ session: WCSession) { }
    func sessionDidBecomeInactive(_ session: WCSession) { }

    func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: @escaping ([String : Any]) -> Void) {
        // Reply to watch with data from user defaults
        replyHandler(["dataFromiPhone": readDoubleFromUserDefaults()])
    }
}

WatchOS InterfaceController

class InterfaceController: WKInterfaceController, WCSessionDelegate{

    var session: WCSession!

    var myNumber:Double = 0

    override func willActivate() {
        super.willActivate()

        if (WCSession.isSupported()) {
            session = WCSession.default()
            session.delegate = self
            session.activate()
        }
        getDataFromiPhone()
    }

    override func didDeactivate() {
        super.didDeactivate()
    }
    /// Delegate required method
    func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {}

    func getDataFromiPhone(){
        //Send Message to phone - I'm not sure if I need this message
        let messageToSend = ["askiPhone":"Hi Phone, send me data from userDefaults."]
        session.sendMessage(messageToSend, replyHandler: { replyMessage in
            /// handle the reply
            let dataFromPhone = replyMessage["dataFromiPhone"] as? String
            DispatchQueue.main.async {
                self.myNumber = Double(dataFromPhone!)!
            }
        }, errorHandler: {error in
            /// catch any errors here
            print("ERROR: \(error)")
        })
    }
}
fs_tigre
  • 10,650
  • 13
  • 73
  • 146

1 Answers1

1

I would recommend using App Groups for this. Add an App Group under "Capabilities" for your app's target and the watch extension's target:

Add App Group And then set your UserDefaults using that App Group:

let appGroupName = "group.mobilemind.SpeedDial"
let appGroupUserDefaults = UserDefaults(suiteName: appGroupName)!

appGroupUserDefaults.set(NSNumber(value: newValue), forKey: "hasRated")
appGroupUserDefaults.synchronize()

Use UserDefaults this way on the app and the watch extension and both will be able to get and set the UserDefaults for the app group.

Edit

This approach does not work on WatchOS 2.0+. However, this approach still works on other types of app extensions.

Jake
  • 13,097
  • 9
  • 44
  • 73
  • I thought this method has been obsoleted and no longer works in iOS9+/WathOS2+. Are you using this method, does it work for you? – fs_tigre Dec 12 '16 at 18:55
  • I did some more research and you are correct: http://stackoverflow.com/questions/27007288/watchkit-sdk-not-retrieving-data-from-nsuserdefaults – Jake Dec 12 '16 at 19:40