Si has creado alguna App para el reloj de Apple, sabrás que la comunicación entre dispositivos no es fácil.
En watchOS 2 por suerte esto se ha mejorado, y podemos comunicar dispositivos usando un nuevo Framework llamado Watch Connectivity.
Esto es nuevo, y cambia por completo la forma de comunicación entre el iPhone y el Watch que existía hasta el momento.
Con watchOS 1 únicamente disponíamos de una forma de comunicación, era el método openParentApplication pero este ya no se puede usar en watchOS 2, y debemos hacer uso de la nueva librería que Apple ha creado para tal efecto.
Cómo comunicar dispositivos usando Watch Connectivity
Lo primero es crear una sesión.
Esto es muy fácil y basta con incluir esta condición en el método viewDidLoad de nuestro ViewController en la parte del iPhone, o bien en el método awayWithContext o willActivate en la parte del watch:
//Swift if (WCSession.isSupported()) { let session = WCSession.defaultSession() session.delegate = self session.activateSession() }
//Objective-C if ([WCSession isSupported]) { WCSession *session = [WCSession defaultSession]; session.delegate = self; [session activateSession]; }
Con esta condición comprobamos si podemos establecer una conexión, de poder hacerlo creamos un objeto WCSession y le pasamos su delegado.
No hay que olvidar que debemos importar el Framework WatchConnectivity a nuestro proyecto, e importar la cabecera del Framework en cada una de las clases en las cuales queramos usarlo.
Basta con incluir en nuestro fichero de cabecera de la clase la linea de código:
//Objective-C #import <WatchConnectivity/WatchConnectivity>;
//Swift import WatchConnectivity
Enviando y recibiendo
Hay dos tipos de comunicación en WatchConnectivity.
Transferencias en background y paso de mensajes.
Tenemos tres tipos de transferencias en background, dependiendo de lo que queramos hacer usaremos una u otra.
Transferencias en background
Usaremos este tipo de comunicación cuándo queramos mantener una comunicación que no sea inmediata, ya que estos métodos los ejecutará el sistema operativo cuándo crea conveniente.
El contenido se añade a colas que el sistema operativo libera a su conveniencia.
Disponemos de tres tipos:
- updateApplicationContext
- transferUserInfo
- transferFile
updateApplicationContext
Con este método podremos pasar datos de actualización.
Esto significa que sólo se envían y reciben los datos más actualizados, esta forma de comunicación es ideal si nuestra aplicación recibe datos de un servidor y sólo queremos mostrar los últimos datos recibidos al usuario.
Es decir, sólo se transfiere los últimos datos recibidos para actualizar el contexto.
Podemos hacer uso de este método de este modo:
//Swift do { let diccionarioDatos = // Un diccionario try WCSession.defaultSession().updateApplicationContext(diccionarioDatos) } catch { // Errores }
//Objective-C NSDictionary *diccionarioDatos = // Un diccionario [[WCSession defaultSession] updateApplicationContext:diccionarioDatos error:nil];
Enviamos un diccionario, en la otra parte (ya sea en la parte del Watch o en la parte del iPhone) debemos recibirlo.
WatchConnectivity hace uso del patrón del delegado, así que recibiremos el envío a través de un método delegado, es el siguiente:
//Swift func session(session: WCSession, didReceiveApplicationContext applicationContext: [String : AnyObject]) { #code# }
//Objective-C -(void)session:(WCSession *)session didReceiveApplicationContext:(NSDictionary; *)applicationContext{ #code# }
transferUserInfo
Antes hablamos del método opentParentApplication, esta era la única forma de comunicarnos entre dispositivos con watchOS 1.
Bien, pues aquí tenemos a su sustituto 😉
Podemos hacer uso de esta forma de comunicación de la siguiente manera:
//Swift let diccionario = // Un diccionario let transfer = WCSession.defaultSession().transferUserInfo(diccionario)
//Objective-C NSDictionary * diccionario = // Un diccionario [[WCSession defaultSession] transferUserInfo: diccionario];
Y en la otra parte, para recibir:
//Swift func session(session: WCSession, didReceiveUserInfo userInfo: [String : AnyObject]){ }
//Objective-C - (void)session:(WCSession *)session didReceiveUserInfo:(NSDictionary *)userInfo{ }
transferFile
Tercera y última forma de comunicación en background.
Usaremos transferFile para enviar y recibir cualquier tipo de archivo entre dispositivos.
Esta es la forma de uso:
//Swift let url = // URL let diccionario = // Un diccionario let fileTransfer = WCSession.defaultSession().transferFile(url, metadata:diccionario)
//Objective-C NSURL *url = // URL NSDictionary *diccionario = // Un diccionario WCSessionFileTransfer *fileTransfer = [[WCSession defaultSession] transferFile:url metadata: diccionario];
También usaremos un método delegado para recibir el archivo en cuestión.
//Swift func session(session: WCSession, didReceiveFile file: WCSessionFile){ }
//Objective-C - (void)session:(WCSession *)session didReceiveFile:(WCSessionFile *)file{ }
Paso de mensajes
Este tipo de comunicación es inmediata.
Es un paso de mensajes de un dispositivo a otro.
Para que este tipo de comunicación funcione, el watch debe estar emparejado con el iPhone, y con el BlueTooth activado en ambos dispositivos, para hacer esta comprobación usaremos la propiedad reachable.
Tenemos dos formas de pasar mensajes:
- sendMessage
- sendMessageData
La diferencia entre uno y otro es que con el primero enviaremos un diccionario, y en el segundo método podemos pasar un objeto de la clase NSData.
sendMessage
Podemos enviar un diccionario.
Lo haremos de la siguiente manera:
//Swift let diccionario = // Un diccionario WCSession.defaultSession().sendMessage(diccionario, replyHandler: { ([String : AnyObject]) ? Void in // Recibimos la respuesta }) errorHandler: { (NSError) ? Void in // Errores });
//Objective-C NSDictionary * diccionario = // Un diccionario [[WCSession defaultSession] sendMessage: diccionario replyHandler:^(NSDictionary *replyHandler) { // Recibimos la respuesta } errorHandler:^(NSError *error) { // Errores } ];
sendMessageData
Para enviar un objeto de la clase NSData, lo haremos así:
//Swift
let nsdataObject = // Objeto NSData WCSession.defaultSession().sendMessageData(nsdataObject, replyHandler: { ([String : AnyObject]) ? Void in // Recibimos la respuesta }) errorHandler: { (NSError) ? Void in // Errores });
//Objective-C
NSData * nsdataObject = // Objeto NSData [[WCSession defaultSession] sendMessageData:nsdataObject replyHandler:^(NSDictionary *replyHandler) { // Recibimos la respuesta } errorHandler:^(NSError *error) { // Errores } ];
Recibir mensajes
Para ambos envíos podemos usar dos tipos de recepción.
- didReceiveMessage
- didReceiveMessage replyHandler
El primero únicamente recibe el mensaje.
El segundo método recibe el mensaje pero además devuelve una respuesta.
didReceiveMessage
Para recibir el mensaje usaremos el siguiente código:
//Swift func session(session: WCSession, didReceiveMessage message: [String : AnyObject]){ }
//Objective-C - (void)session:(WCSession *)session didReceiveMessage:(NSDictionary<NSString *, id> *)message{ }
didReceiveMessage replyHandler
Si lo que queremos es que además de recibir un mensaje, recibamos una respuesta de la otra parte, usaremos este método.
//Swift func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void){ }
//Objective-C - (void)session:(WCSession *)session didReceiveMessage:(NSDictionary *)message replyHandler:(void (^)(NSDictionary<NSString *, id) *replyMessage))replyHandler{ }
Pues esto es todo. Te dejo un enlace a la documentación oficial de Apple.
Y ya sabes, si tienes alguna duda, o quieres decirme algo, déjame un comentario 😉
Hola, que tal, me gustaría saber como puedo hacer que se muestren imágenes desde una url y se visualicen en el apple watch, se ven en el simulador, pero no en el reloj físico, ¿Alguna idea? gracias!
Hola Edgar,
No puedo ayudarte con las indicaciones que me dices, te pueden estar pasando tantas cosas…
Gracias por visitar el Blog y por comentar.
Un abrazo.
Sergio Becerril