Passing data to Apple Watch app

后端 未结 5 895
天涯浪人
天涯浪人 2020-11-29 03:34

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

相关标签:
5条回答
  • 2020-11-29 03:54

    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

    0 讨论(0)
  • 2020-11-29 03:55

    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.
    0 讨论(0)
  • 2020-11-29 04:08

    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?

    App Group capability for App Target App Group capability for Watch Extension Target

    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
    0 讨论(0)
  • 2020-11-29 04:08

    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
    }];
    
    0 讨论(0)
  • 2020-11-29 04:16

    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

    0 讨论(0)
提交回复
热议问题