Transmettre des données à L'application Apple Watch

j'essaie de passer des données de mon application dans mon Apple Watch app. Fondamentalement, j'utilise la même méthode que j'ai utilisée pour créer le widget d'aujourd'hui et donc je passe des données par NSUserDefaults.

le problème est que lorsque j'exécute mon application, les données ne mettent pas à jour les étiquettes de L'application Watch comme je m'y attendais.

voilà ce que j'ai...

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)")
    }
}

j'ai essayé de mettre ce code dans willActivate() , cependant que ne semble pas faire une différence.

quelqu'un sait où je vais mal?

23
demandé sur user3746428 2014-11-19 22:40:45

4 réponses

Je l'ai fait fonctionner en utilisant votre méthode. Je suppose qu'il y a quelques choses que vous pouvez vérifier:

1) synchronisez-vous les valeurs par défaut après avoir défini la valeur:

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

2) Avez-vous activé le groupe App à la fois dans votre application et dans votre extension?

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

3) Utilisez-vous le groupe app correctement nommé lors de la construction des NSDefaults? Par exemple, j'utilise:

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

une fois que tout ce qui est mis en place, je lance l'application, fixe la valeur par défaut, puis lance la cible coup d'oeil qui lit la valeur par défaut et qui semble fonctionner!

enter image description here

  1. toujours coincé? vérifiez vos groupes d'applications dans votre compte apple
25
répondu brindy 2015-08-06 05:31:52

la réponse acceptée s'applique à apple watch os 1. Voir Nsuerdefaults ne fonctionne pas sur Xcode beta avec montre OS2

pour OS2 - vous aurez besoin d'utiliser les cadres WatchConnectivity et mettre en œuvre le 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")

        }
    }

}

Exemple D'Utilisation

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)
    }

}

enter image description here

dans mon code iphone / je peux invoquer le partage données ici

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

et ailleurs j'ai un autre singleton discret pour 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)
            })

        }

    }

}

voir l'exemple de regarder os2 app

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

20
répondu johndpope 2017-05-23 12:02:08

comme l'a dit @johndpope, les Nuserdefaults partagées ne fonctionnent plus sur WatchOS2.

j'affiche une solution simplifiée qui n'est pas aussi complète que celle de john, mais qui fera le travail dans la plupart des cas.

dans votre application iPhone , suivez ces étapes:

choisir trouver le contrôleur de vue que vous voulez pousser des données à la montre Apple à partir et ajouter le cadre en haut.

import WatchConnectivity

maintenant, établir une session de WatchConnectivity avec la montre et envoyer quelques données.

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)
        }
    }
}

s'il vous plaît noter, cela ne fonctionnera pas si vous sautez la configuration du délégué, donc même si vous ne l'utilisez jamais, vous devez le définir et ajouter cette extension:

extension MyViewController: WCSessionDelegate {

}

maintenant, dans votre application de montre (ce code exact fonctionne pour les regards et d'autres types d'app kit de montre ainsi) vous ajoutez le cadre:

import WatchConnectivity

Ensuite, vous mettez en place la session de connectivité:

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

et vous simplement écouter et gérer les messages de l'application iOS:

extension InterfaceController: WCSessionDelegate {

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

}

C'est tout.

les Éléments de la note:

  1. , Vous pouvez envoyer un nouveau applicationContext aussi souvent que vous le souhaitez et il peu importe si la montre est à proximité et connecté ou si la montre application est en cours d'exécution. Cela fournit les données en arrière-plan dans un d'une manière intelligente et que les données sont assis là à attendre quand le regarder application est lancée.
  2. si votre application de montre est réellement active et en cours d'exécution, il doit recevoir le message immédiatement dans la plupart des cas.
  3. vous pouvez inverser ce code pour que la montre envoie des messages à la l'application iPhone de la même façon.
  4. applicationcontexte que votre application watch reçoit quand il est vu sera seulement le dernier message que vous avez envoyé. Si vous avez envoyé 20 messages avant que l'application watch soit visualisée, elle ignorera les 19 premiers et traitera le 20ème.
  5. pour faire une connexion directe/dure entre les 2 applications ou pour les transferts de fichiers d'arrière-plan ou la messagerie en file d'attente, consultez le vidéo WWDC .
11
répondu William T. 2017-04-13 12:31:05

une autre façon de communiquer entre l'application et la montre est par vortex:

https://github.com/mutualmobile/MMWormhole

Envoyer:

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

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

Recevoir:

[self.wormhole listenForMessageWithIdentifier:@"messageIdentifier" 
listener:^(id messageObject) {
// Do Something
}];
6
répondu Paul Wand 2015-01-13 20:32:08