web-dev-qa-db-fra.com

Transmission de données à Apple Watch app

J'essaie de transmettre des données de mon application dans mon Apple Watch app. Fondamentalement, j'utilise la même méthode que celle utilisée pour créer le widget d'aujourd'hui et je transmets donc des données via 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.

Voici 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(), mais cela ne semble pas faire de différence.

Quelqu'un sait où je me trompe?

28
user3746428

Je l'ai fait fonctionner en utilisant votre méthode. Je suppose qu'il y a deux ou trois 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 d'applications dans votre application et votre extension?

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

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

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

Une fois tout ce qui est configuré, j'exécute l'application, définit la valeur dans les valeurs par défaut, puis exécute la cible de coup d'œil qui lit la valeur par défaut et cela semble fonctionner!

enter image description here

  1. Toujours coincé? vérifiez vos groupes d'applications dans votre Apple
25
brindy

La réponse acceptée s'applique à Apple watch os 1. Voir NSUserDefaults ne fonctionne pas sur Xcode beta avec Watch OS2

Pour OS2 - vous devrez utiliser les frameworks WatchConnectivity et implémenter 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 de 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 la session de données de surveillance.

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

        }

    }

}

Reportez-vous à l'exemple d'application montre os2

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

23
johndpope

Comme l'a dit @johndpope, les NSUserDefaults partagés ne fonctionnent plus sur WatchOS2.

Je publie une solution simplifiée qui n'est pas aussi complète que John's mais qui fera le travail dans la plupart des cas.

Dans votre application iPhone , procédez comme suit:

Choisissez trouver le contrôleur de vue que vous souhaitez pousser les données vers le Apple Watch from et ajoutez le cadre en haut.

import WatchConnectivity

Maintenant, établissez une session WatchConnectivity avec la montre et envoyez des 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)
        }
    }
}

Veuillez noter que cela ne fonctionnera PAS si vous ignorez la définition 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 également pour Glances et d'autres types d'applications de kit de montre), vous ajoutez le cadre:

import WatchConnectivity

Ensuite, vous configurez la session de connectivité:

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

et vous écoutez et gérez simplement 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 ce qu'on peut en dire.

Éléments à noter:

  1. Vous pouvez envoyer un nouveau contexte d'application aussi souvent que vous le souhaitez et peu importe si la montre est à proximité et connectée ou si l'application de montre est en cours d'exécution. Cela fournit les données en arrière-plan de manière intelligente et que les données sont là en attente lorsque l'application montre est lancée.
  2. Si votre application de surveillance est réellement active et en cours d'exécution, elle devrait recevoir le message immédiatement dans la plupart des cas.
  3. Vous pouvez inverser ce code pour que la montre envoie des messages à l'application iPhone de la même manière.
  4. application Le contexte que votre application montre reçoit lorsqu'elle est affichée sera UNIQUEMENT le dernier message que vous avez envoyé. Si vous avez envoyé 20 messages avant que l'application Watch ne soit affichée, elle ignorera les 19 premiers et traitera le 20e.
  5. Pour établir une connexion directe/matérielle entre les 2 applications ou pour les transferts de fichiers en arrière-plan ou la messagerie en file d'attente, consultez la vidéo WWDC .
18
William T.

Une autre façon de communiquer entre l'application et la montre est via le trou de ver:

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
Paul Wand

Utilisez simplement la connectivité de veille pour communiquer entre ces deux plates-formes, vous pouvez en savoir plus à ce sujet dans le document Apple document

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

0
sadegh bitarafan