39 votes

"Réponse à un Message trop long." - Regarder les Problèmes de Connectivité avec Watch OS 3

Dans mon projet, j'utilise Watch Connectivity pour envoyer des messages vers et à partir de la Montre et l'iPhone. Je peux envoyer un message au téléphone et de recevoir un tableau de chaînes de caractères lors du lancement de l'application, cependant lors de l'utilisation des actions j'obtiens l'erreur suivante;

Erreur de Domaine=WCErrorDomain Code=7012 "réponse à un Message trop long."

Voici comment les choses sont mises en place;

Tout d'abord, la montre envoie un message sur le téléphone, puis le téléphone envoie un tableau de chaînes de caractères à afficher dans une WKInterfaceTable. Parfois, cela fonctionne lors du chargement de l'application. ( Je récupère tous les NSManagedObjects appelés Items et l'utilisation de leur title chaîne de propriétés à stocker dans un array appelés watchItems.

Cependant, j'ai une action sur la montre pour supprimer tous les éléments dans le tableau et actualiser le tableau avec les nouvelles données.

L'action sur la montre utilise un sendMessage fonction pour envoyer l' item pour le téléphone pour supprimer à partir du tableau, puis le téléphone envoie la nouvelle mise à jour de la matrice de la regarder et de regarder les mises à jour de la table. Cependant, je obtenir le même tableau ou une erreur.

Assez simple à droite, donc en fait, tout a bien fonctionné avant Swift 3 et Regarder OS3/iOS 10; la totalité de l'app l'habitude de travailler.

Voici comment j'ai tout mis en place;

Téléphone Délégué D'Application

import WatchConnectivity

class AppDelegate: UIResponder, UIApplicationDelegate, WCSessionDelegate {

var session : WCSession!

var items = [Items]()

func loadData() {
    let moc = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext
    let request = NSFetchRequest<Items>(entityName: "Items")

    request.sortDescriptors = [NSSortDescriptor(key: "date", ascending: true)]
    request.predicate = NSPredicate(format: "remove == 0", "remove")

    do {
        try
            self.items = moc!.fetch(request)
        // success ...
    } catch {
        // failure
        print("Fetch failed")
    }
}

//WATCH EXTENSION FUNCTIONS
//IOS 9.3 
/** Called when the session has completed activation. If session state is WCSessionActivationStateNotActivated there will be an error with more details. */


//HAVE TO INCLUDE
@available(iOS 9.3, *)
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?){
   print("iPhone WCSession activation did complete")
}


@available(iOS 9.3, *)
func sessionDidDeactivate(_ session: WCSession) {}

func sessionWatchStateDidChange(_ session: WCSession) {}

func sessionDidBecomeInactive(_ session: WCSession) {

}

//APP DELEGATE FUNCTIONS

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {

    //Check if session is supported and Activate
    if (WCSession.isSupported()) {
        session = WCSession.default()
        session.delegate = self;
        session.activate()
    }
    return true
}


}

//DID RECIEVE MESSAGE
func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: @escaping ([String : Any]) -> Swift.Void) {


    loadData()

    func loadItems() {
        watchItems.removeAll()

        for a in self.items {
            watchItems.append(a.title)
        }
    }

    var watchItems = ["1","2","3","4","5"]

    let value = message["Value"] as? String

    //This is called when user loads app, and takes some time when using refresh action, sometimes times out 

    if value == "HELLOiPhone/+@=" {

        print("Hello Message Recieved")

        loadItems() 

        //send a reply
        replyHandler( [ "Items" : Items ] )

    }

    //Not sure if receiving but does not delete array and send back to watch
    if value == "removeALL@+=-/" {                        
        for index in self.items {
            index.remove = 1
            //Saves MOC
        }

        loadData()
        loadTasksData()

        //send a reply
        replyHandler( [ "Items" : Items ] )

    }
    else {
        for index in self.items {
            if index.title == value {
            index.remove = 1
            //Saves MOC
            }
        }

        loadData()
        loadTasksData()

        //send a reply
        replyHandler( [ "Items" : Items ] )
    }
}

REGARDER

import WatchConnectivity

class SimplelistInterfaceController: WKInterfaceController, WCSessionDelegate  {


/** Called when the session has completed activation. If session state is WCSessionActivationStateNotActivated there will be an error with more details. */
@available(watchOS 2.2, *)
public func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {

   //Fetch data is a function which sends a "HELLOiPhone/+@=" message to receive the array and displays in the table. This works 
   fetchData()
}


var session : WCSession!
var items = ["Refresh Items"]

override func didAppear() {
    fetchData()
}

override func willActivate() {
    // This method is called when watch view controller is about to be visible to user
    super.willActivate()
    //Check if session is supported and Activate
    if (WCSession.isSupported()) {
        session = WCSession.default()
        session.delegate = self
        session.activate()
    }
    fetchData()
}

override func awake(withContext context: Any?) {
    super.awake(withContext: context)
    fetchData()
}

@IBAction func refresh() {
    print("Refresh")
    //Works but sometimes message is delayed
    fetchData()
}

@IBAction func removeAll() {
    print("Remove All Items is called")
    if WCSession.default().isReachable {
        let messageToSend = ["Value":"removeALL@+=-/"]
        print("\(messageToSend)")
        session.sendMessage(messageToSend, replyHandler: { replyMessage in
            if let value = replyMessage["Items"] {
                self.items = value as! [String]

                Not receiving message
                print("Did Recieve Message, items = \(self.items)")
            }

            }, errorHandler: {error in
                // catch any errors here
                print(error)
        })
    }
    fetchData()
}

}

2voto

Vivek Gupta Points 94
  1. Vous ne devriez pas envoyer ou recevoir des objets de la classe à partir d'une cible(iOS) à la seconde cible(watchOS), vous devez envoyer/recevoir des données au format du dictionnaire comme [Chaîne: Tout] et ce dictionnaire doit contenir tableau de vos objets personnalisés propriétés requises en valeur de la clé de la paire en simple dictionnaire. Cela pourrait être facilement décodable à regarder de côté.

  2. Vous devriez faire une découplé classe étendant WCSessionDelegate comme ci-dessous afin que cette classe pourrait être utilisé non seulement dans ExtensionDelegate, mais également dans toute WKInterfaceController.

    class WatchSessionManager: NSObject, WCSessionDelegate {
    
        static let sharedManager = WatchSessionManager()
    
        private override init() {
            super.init()
            self.startSession()
        }
    
        private let session: WCSession = WCSession.default
    
        func startSession() {
            session.delegate = self
            session.activate()
        }
    
        func tryWatchSendMessage(message: [String: Any], completion: (([String: Any]) -> Void)? = nil) {
            print("tryWatch \(message)")
            weak var weakSelf = self
            if #available(iOS 9.3, *) {
                if weakSelf?.session.activationState == .activated {
                    if weakSelf?.session.isReachable == true {
                        weakSelf?.session.sendMessage(message,
                                                      replyHandler: { [weak self]  ( response )  in
                                                        guard let slf = self else {return}
                                                        //Get the objects from response dictionary
                                                        completion?(response)
                            },
                                                      errorHandler: { [weak self] ( error )  in
                                                        guard let slf = self else {return}
                                                        print ( "Error sending message: % @ " ,  error )
                                                        // If the message failed to send, queue it up for future transfer
                                                        slf.session.transferUserInfo(message)
                        })
                    } else {
                        self.session.transferUserInfo(message)
                    }
                }else{
                    self.session.activate()
                    self.session.transferUserInfo(message)
                }
            } else {
                // Fallback on earlier versions
                if self.session.activationState == .activated {
                    if self.session.isReachable == true {
                        self.session.sendMessage(message,
                                                 replyHandler: {  ( response )  in
                                                    //Get the objects from response dictionary
                                                    completion?(response)
                        },
                                                 errorHandler: {  ( error )  in
                                                    print ( "Error sending message: % @ " ,  error )
                                                    // If the message failed to send, queue it up for future transfer
                                                    self.session.transferUserInfo(message)
                        })
                    } else {
                        self.session.transferUserInfo(message)
                    }
                }else{
                    self.session.activate()
                    self.session.transferUserInfo(message)
                }
            }
        }
    
    
    }
    

Maintenant, vous pouvez facilement envoyer un message à votre application iOS afin de réveiller et d'obtenir des données à partir de là (e.g de CoreData) à l'aide de la fonction ci-dessus dans toute WKInterfaceController et la fin du bloc aurez vos données requises telles que

let dict: [String: Any] = ["request": "FirstLoad"]
WatchSessionManager.sharedManager.tryWatchSendMessage(message: dict,completion:{ (data) in print(data)})

Même façon, vous devez utiliser cette WatchSessionManager sur iOS côté et de recevoir la demande, et par la clé demandée, vous devriez prendre des données de base de stockage/db et envoyer la liste des objets personnalisés dans simple clé-valeur Dictionnaire modèle dans replyHandler de didreceiveMessage fonction comme ci-dessous.

 func session(_ session: WCSession, didReceiveMessage message: [String: Any], replyHandler: @escaping ([String: Any]) -> Void) {
 var dict: [String: Any] = [String: Any]()
 replyHandler(dict) //This dict will contain your resultant array to be sent to watchApp.
}

Certains temps de l'Application iOS(Tué en état) n'est pas accessible à WatchApp, pour résoudre ce problème, vous devez appeler "tryWatchSendMessage" au sein de la Minuterie de près de 3 secondes d'intervalle. Et quand vous obtenez la connexion de watchApp alors vous devez invalider la minuterie.

Le sendMessage fonctionnalité de WatchConnectivity est si puissant pour réveiller votre application. Vous devriez l'utiliser de manière optimisée.

0voto

iWheelBuy Points 352

J'ai juste eu mon WatchOS app. Et il y avait une situation, quand j'ai reçu le Message "réponse a pris trop de temps".

Puis j'ai ajouté un gestionnaire de tâche en tâche de fond pour mon application iOS et a commencé à envoyer des messages à chaque seconde WatchOS app. Le message contenait UIApplication.shared.backgroundTimeRemaining. Donc, je reçois: 45sec, 44sec, ..., 6sec, 5sec, ... Si le compteur fonctionne en dessous de 5 sec pas les messages seront envoyés à/de l'application pour iOS et nous allons obtenir une "réponse à un Message trop long". La solution la plus simple était de les envoyer vierge messages de montre de téléphone à chaque fois que le timer passe en dessous de 15 sec. L' backgroundTimeRemaining sera mis à jour à 45 secondes: 45, 44, 43, ..., 17, 16, 15, (message vide), 45, 44, 43, ...

Espérons que cela aide quelqu'un

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X