Passing data to Apple Watch app

communication between apple watch and iphone
share data between ios app and watch
send data from apple watch to iphone swift
apple watch connectivity
apple watch app development tutorial
apple watch connectivity framework
send data to apple watch
apple watch api

I am trying to pass data from my app into my Apple Watch app. Basically, I am using the same method as I used for creating the today widget and so I am passing data through NSUserDefaults.

The problem is, that when I run my app, the data does not update the labels in the Watch app as I would expect it to.

Here is what I have...

override init(context: AnyObject?) {
    // Initialize variables here.
    super.init(context: context)

    // Configure interface objects here.
    NSLog("%@ init", self)

    var defaults = NSUserDefaults(suiteName: "group.AffordIt")
    var totalBudgetCalculation = ""
    if (defaults!.stringForKey("totalBudgetWidget") != nil) {
            println("Worked")
        totalBudgetCalculation = defaults!.stringForKey("totalBudgetWidget")!
        initialBudgetLabel.setText("Initial: \(totalBudgetCalculation)")
    }

    var currentBudgetCalculation = ""
    if (defaults!.stringForKey("currentBudgetWidget") != nil) {
        currentBudgetCalculation = defaults!.stringForKey("currentBudgetWidget")!
        currentBudgetLabel.setText("Current: \(currentBudgetCalculation)")
    }
}

I tried putting this code in willActivate(), however that doesn't seem to make a difference.

Anyone know where I am going wrong?

This applies to OS 1 only. See below for better answers.

I got it working using your method. I guess there's a couple of things you can check:

1) Are you synchronising the defaults after you set the value:

defaults?.synchronize();
NSLog("%@ ", defaults?.dictionaryRepresentation())

2) Have you enabled the App Group in both your app and your extension?

3) Are you using the correctly named app group when constructing the NSDefaults? For example, I use:

NSUserDefaults(suiteName: "group.com.brindysoft.MyWatch");

Once all that's set up I run the app, set the value in the defaults, then run the glance target which reads the value from the default and that seems to work!

  1. Still stuck? check your app groups in your apple account

Using Watch Connectivity to Communicate Between Your Apple , Most Apple Watch apps require an exchange of data with a paired iPhone app. This sample demonstrates how to use the Watch Connectivity APIs to: Update� To check your cellular data usage, use the Apple Watch app. Open the app on your iPhone, tap the My Watch tab, tap Cellular, then scroll to the Cellular Data Usage section. To turn your cellular connection on or off, swipe up from the watch face to open Control Center. Tap the cellular button, then turn Cellular on or off.

The accepted answer applies to apple watch os 1. See NSUserDefaults not working on Xcode beta with Watch OS2

For OS2 - you will need to use the WatchConnectivity frameworks and implement the WCSessionDelegate.

import WatchConnectivity
import WatchKit

@available(iOS 9.0, *)
var alertDelegate:HomeIC? = nil

public class WatchData: NSObject,WCSessionDelegate {
    var session = WCSession.defaultSession()
   //

    class var shared: WatchData {
        struct Static {
            static var onceToken: dispatch_once_t = 0
            static var instance: WatchData? = nil
        }
        dispatch_once(&Static.onceToken) {
            Static.instance = WatchData()
        }
        return Static.instance!
    }

    public func session(session: WCSession, didReceiveFile file: WCSessionFile){
        print(__FUNCTION__)
        print(session)

    }

    public func session(session: WCSession, didReceiveApplicationContext applicationContext: [String : AnyObject]) {
        print(__FUNCTION__)
        print(session)

        alertDelegate?.showMessage("didReceiveApplicationContext")
    }


    public func sessionReachabilityDidChange(session: WCSession){
        print(__FUNCTION__)
        print(session)
        print("reachability changed:\(session.reachable)")
        let text = session.reachable ? "reachable" : "unreachable"
        alertDelegate?.showMessage(text)
    }

    public func sessionWatchStateDidChange(session: WCSession) {
        print(__FUNCTION__)
        print(session)
        print("reachable:\(session.reachable)")
       // alertDelegate?.showMessage("sessionWatchStateDidChange")
        if !session.receivedApplicationContext.keys.isEmpty {
            alertDelegate?.showMessage(session.receivedApplicationContext.description)
        }
    }

    public func session(session: WCSession, didReceiveMessageData messageData: NSData){

        if !session.receivedApplicationContext.keys.isEmpty {
            alertDelegate?.showMessage(session.receivedApplicationContext.description)
        }
    }


    public func session(session: WCSession, didReceiveMessage message: [String : AnyObject]){
        print(__FUNCTION__)
        if let data = message["data"] {
            alertDelegate?.showMessage(data as! String)
            return
        }
    }

    public func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void) {
        print(__FUNCTION__)
        if let data = message["data"] {
            alertDelegate?.showMessage(data as! String)
            return
        }
        guard message["request"] as? String == "showAlert" else {return}

    }


    public func activate(){

        if WCSession.isSupported() {    //  it is supported
            session = WCSession.defaultSession()
            session.delegate = self
            session.activateSession()
            print("watch activating WCSession")
        } else {

            print("watch does not support WCSession")
        }

        if(!session.reachable){
            print("not reachable")
            return
        }else{
            print("watch is reachable")

        }
    }

}

Sample Usage

class HomeIC: WKInterfaceController {
    // MARK: Properties


    override func awakeWithContext(context: AnyObject?) {
        super.awakeWithContext(context)

        // Initialize the `WCSession`.
        WatchData.shared.activate()
        alertDelegate = self
    }

    internal func showMessage(msg:String){
       let defaultAction = WKAlertAction(title: msg, style: WKAlertActionStyle.Default) { () -> Void in }
       let actions = [defaultAction]
       self.presentAlertControllerWithTitle(  "Info",  message: "",  preferredStyle: WKAlertControllerStyle.Alert, actions: actions)
    }

}

in my iphone code / I can invoke sharing data here

 if #available(iOS 9.0, *) {
        WatchData.shared.sendInbox()
    } else {
        // Fallback on earlier versions
    }

And somewhere else I have another discrete singleton for watch data session.

@available(iOS 9.0, *)
public class WatchData: NSObject,WCSessionDelegate {
    var session = WCSession.defaultSession()
    var  payload:String = ""



    class var shared: WatchData {
        struct Static {
            static var onceToken: dispatch_once_t = 0
            static var instance: WatchData? = nil
        }
        dispatch_once(&Static.onceToken) {
            Static.instance = WatchData()
        }
        return Static.instance!
    }


    public func sessionReachabilityDidChange(session: WCSession){
        print(__FUNCTION__)
        print(session)
        print("reachability changed:\(session.reachable)")
        if (session.reachable){

        }

    }


    public func sessionWatchStateDidChange(session: WCSession) {
        print(__FUNCTION__)
        print(session)
        print("reachable:\(session.reachable)")
    }

    public func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void) {
        print(__FUNCTION__)
        guard message["request"] as? String == "showAlert" else {return}
        guard let m = message["m"] as? String else { return }
        print("msg:",m)
    }


    public func sendInbox(){



        if (!session.reachable){
            if WCSession.isSupported() {    //  it is supported
                session = WCSession.defaultSession()
                session.delegate = self
                session.activateSession()
                print("iphone activating WCSession")
            } else {
                print("iphone does not support WCSession")
            }
            session.activateSession()
        }

        if(session.paired){
            if(session.watchAppInstalled){
                print("paired | watchAppInstalled")
            }
        }else{
           print("not paired | or no watchAppInstalled")
        }


        if(!session.reachable){
            print("not reachable")
            return
        }else{

            /*let transfer:WCSessionUserInfoTransfer =  (session.transferUserInfo(["data" : "Test2"]) as WCSessionUserInfoTransfer?)!
            if(transfer.transferring){
                print("-> iphone")
            }else{
                print("!-> iphone")
            }*/

            session.sendMessage(["data" :"test"],
                replyHandler: { reply in
                },
                errorHandler: { error in
                      print(error)
            })

        }

    }

}

Refer to sample watch os2 app

https://github.com/shu223/watchOS-2-Sampler/tree/20eeebeed66764d0814603e97d3aca5933236299

Keeping Your watchOS Content Up to Date, You can also share data from a paired iPhone, although this can't be your app's primary way of accessing data. Because Apple Watch has several different ways � Bring your iPhone near your Apple Watch, wait for the Apple Watch pairing screen to appear on your iPhone, then tap Continue. Or open the Apple Watch app on your iPhone, then tap Pair New Watch. When prompted, position your iPhone so that your Apple Watch appears in the viewfinder in the Apple Watch app. This pairs the two devices.

As @johndpope said, shared NSUserDefaults no longer work on WatchOS2.

I'm posting a simplified solution that's not as full featured as john's but will get the job done in most cases.

In your iPhone App, follow these steps:

Pick find the view controller that you want to push data to the Apple Watch from and add the framework at the top.

import WatchConnectivity

Now, establish a WatchConnectivity session with the watch and send some data.

if WCSession.isSupported() { //makes sure it's not an iPad or iPod
    let watchSession = WCSession.defaultSession()
    watchSession.delegate = self
    watchSession.activateSession()
    if watchSession.paired && watchSession.watchAppInstalled {
        do {
            try watchSession.updateApplicationContext(["foo": "bar"])
        } catch let error as NSError {
            print(error.description)
        }
    }
}

Please note, this will NOT work if you skip setting the delegate, so even if you never use it you must set it and add this extension:

extension MyViewController: WCSessionDelegate {

}

Now, in your watch app (this exact code works for Glances and other watch kit app types as well) you add the framework:

import WatchConnectivity

Then you set up the connectivity session:

override func awakeWithContext(context: AnyObject?) {
    super.awakeWithContext(context)
    let watchSession = WCSession.defaultSession()
    watchSession.delegate = self
    watchSession.activateSession()
}

and you simply listen and handle the messages from the iOS app:

extension InterfaceController: WCSessionDelegate {

    func session(session: WCSession, didReceiveApplicationContext applicationContext: [String : AnyObject]) {
        print("\(applicationContext)")
        dispatch_async(dispatch_get_main_queue(), {
            //update UI here
        })
    }

}

That's all there is to it.

Items of note:

  1. You can send a new applicationContext as often as you like and it doesn't matter if the watch is nearby and connected or if the watch app is running. This delivers the data in the background in an intelligent way and that data is sitting there waiting when the watch app is launched.
  2. If your watch app is actually active and running, it should receive the message immediately in most cases.
  3. You can reverse this code to have the watch send messages to the iPhone app the same way.
  4. applicationContext that your watch app receives when it is viewed will ONLY be the last message you sent. If you sent 20 messages before the watch app is viewed, it will ignore the first 19 and handle the 20th one.
  5. For doing a direct/hard connection between the 2 apps or for background file transfers or queued messaging, check out the WWDC video.

Apple Watch Tutorials, Learn how to pass data between the iPhone and Apple Watch! ▻Get my Apple Watch Duration: 16:02 Posted: Jun 7, 2015 There is a paragraph on sharing data between the watch app and the extension on the iPhone. To quote the first paragraph. Sharing Data with Your Containing iOS App. If your iOS app and WatchKit extension rely on the same data, use a shared app group to store that data. An app group is a secure container that multiple processes can access.

Another way to communicate between the app and the watch is via wormhole:

https://github.com/mutualmobile/MMWormhole

Send:

[self.wormhole passMessageObject:@{@"titleString" : title} 
                  identifier:@"messageIdentifier"];

id messageObject = [self.wormhole messageWithIdentifier:@"messageIdentifier"];

Recieve:

[self.wormhole listenForMessageWithIdentifier:@"messageIdentifier" 
listener:^(id messageObject) {
// Do Something
}];

52-WatchOSAppXcode10-Navigate and passing data through , This video guides you how to navigate between screens in an Apple Watch App. Data will be Duration: 7:59 Posted: Sep 26, 2018 If you use Strava to track your workouts on an iPhone, you've probably wondered why you couldn't sync your Apple Health data with it. While there is a Strava app for the Apple Watch, there's not

Just use watch connectivity for communicate between these two platform you can read more about this in apple document

https://developer.apple.com/documentation/watchconnectivity

SWIFT : PASSING DATA TO APPLE WATCH APP., Today`s post will basically cover how to transfer/send basic data from iPhone application to apple Watch Application. There are different ways� For example, in watchOS 6 and later, apps that use HealthKit can request user authorization on Apple Watch. Download data directly to the watch. Independent apps can’t rely on Watch Connectivity to transfer data or files from an iOS companion app. If you need to sync data between devices, consider using CloudKit, or syncing through your own

Communicating between iOS and watchOS: WCSession, First the good news: for our purposes, communicating between Apple Watch and iOS the number of seconds that have passed since midnight on January 1st 2001. It doesn't matter what data we send, because in our app any data will be � Many commonly used apps — such as MyFitnessPal, Couch to 5K, Strava, and Nike Training — have made the process of using them with the Apple Watch pretty simple.

Sending Data From Your App to Apple Watch Using WCSession , In this post, we'll learn how to create a simple watchOS app, and pass that data to it. In the first part of the post, we'll learn about� To remove apps and their data: On your iPhone, in the Watch app, go to: My Watch > scroll down and tap on an app > turn off Show App on Apple Watch. Reduce your storage allowance for synced photos: On your iPhone, in the Watch app, go to: My Watch (tab) > Photos > Photos Limit > set a lower limit. Reduce your storage allowance for synced music:

WatchKit Apps & Sending Data From Apple Watch To iPhone , WatchKit Apps & Sending Data From Apple Watch To iPhone. by Greg Hogue you made. This dictionary is what is passed to the iPhone app:. The Apple Watch gives athletes the convenience of recording their training without having to open multiple fitness apps, use additional devices or manually record their workouts. With the new TrainingPeaks integration with Apple Health, you will now be able to sync your training plan , health metrics and workouts with your Apple Watch.

Comments
  • please rework this title to say OS1. this technique is no longer relevant in os2. stackoverflow.com/questions/30851729/…
  • Great! Thanks a lot. The problem was that I hadn't set up the App Group for the Watch.
  • Would this also work for Watch<-->Watch communication?
  • @Brindy : I followed same steps but it's not working for me. I am getting nil data . Any debugging help..
  • I did the same and I'm also getting nil data. Is this a problem with the simulator?
  • There is sample code using applicationContext() on github see: github.com/JohnGoodstadt/applicationContext
  • @JohnGoodstadt is it normal when send a message from phone to watch if is not reachable it does not deliver the message and will not retry later, but from watch to phone if is not reachable it wait until is reachable and the message finally is delivered?
  • Thank you! This was fantastic.
  • Have you tested this method? Is it reliable?
  • Mutual mobile has an example build that I ran, which did indeed transmit data from iPhone to the watch
  • MMWormhole just uses the low-level Darwin notification system that's been around for quite some time, they've just built a wrapper around it. In fact, I've seen this method recommended by Apple engineers. I'd say it's reliable enough.
  • for os 2 - use the apple WatchConnectivity frameworks.
  • MMWormhole is very useful, It works for watch OS 2 apis also. But I am facing issues while transferring custom class objects from iPhone to watch. But It works best for transferring simple objects like strings and dictionaries.