¡Atención! Este sitio utiliza cookies.
Si no cambias la configuración de tu navegador, aceptas su uso.

WatchKit – Cómo funcionan las apps del nuevo reloj de Apple

En este artículo se recorre de manera sencilla cómo es el desarrollo de una aplicación trivial para el Watch, y de paso se compara esta nueva caja de herramientas con la que ya conocemos en iOS: UIKit.

LimpIco

Qué es WatchKit

WatchKit es el conjunto de herramientas de desarrollo que proporciona Apple para crear Aplicaciones para el Apple Watch, solamente a partir de iOS 8.2. Se encuentra disponible en su entorno de desarrollo nativo Xcode, en concreto desde la versión 6.2, en la que se ha introducido una plantilla dentro de los proyectos para iOS.

Y es que, por extraño que pueda parecer, no es posible crear una aplicación específica y exclusiva para el Apple Watch, sino que hay que contenerla en una app de iOS. Es decir, que no busques “Apple Watch” dentro del asistente de Nuevo Proyecto, porque no lo vas a encontrar.

Antes de nada, si no es un proyecto específico de Apple Watch, ¿qué tipo de aplicaciones podemos crear?

Una aplicación para Apple Watch requiere de 2 targets más que cualquier otra aplicación sencilla: el target por defecto del proyecto, el de tests, así como una extensión y otro más con la interfaz del reloj.

¿Solo la interfaz? Sí. Como veremos más adelante, estas apps están separadas en dos módulos bien diferenciados: el código (WatchKit Extension) y la interfaz de usuario (WatchApp). Eso sí, la manera en la que se comunican es totalmente transparente para nosotros. No verás nada de CoreBluetooth.

WatchKit Architecture

¿Y por qué esto?

Simplemente, el código se ejecuta íntegramente en el iPhone, mientras que la app del reloj —la cual se instala automáticamente— solo contiene las vistas, y no posee más responsabilidad que la de contenerlas. Esto evidentemente nos limita bastante a la hora de modificar las pantallas de forma dinámica o por código, o crear animaciones (de momento solo a través de sucesiones de imágenes), etc.

Michael Knight no utiliza su AppleWatch solamente. Lleva desde los 90 un iPhone en el bolsillo derecho de los vaqueros

Michael Knight no utilizaba su AppleWatch como tal. Ya en los 80 llevaba un iPhone en el bolsillo derecho de los vaqueros.

Así que define bien tu interfaz, porque las pantallas se pintan una sola vez.

¿Entonces no estamos peor que cuando presentaron iPhoneOS?

Las limitaciones iniciales —en gran parte por cuestiones de rendimiento y batería— nos impiden acceder a los sensores del reloj, tales como el motor de vibraciones integrado, o leer los latidos del corazón del usuario. Irán evolucionando conforme avancen las sucesivas versiones; pero sí, parece que estamos en una situación similar. Lo cual no es malo del todo.

Tipos de presentación

  • Jerárquica: Solo una pantalla por vez, similar a una app en iOS. Es la recomendada por Apple, ya que cometer una sola acción por pantalla suele revertir en mejor usabilidad.
  • Paginada: Varias pantallas simultáneas entre las que nos movemos horizontalmente. Es lo que sustituye al que sería un TabBar en iOS.

WatchKit Navigation

Es muy importante notar que no es posible combinar ambos estilos. Decide bien, porque no será posible utilizar el otro más tarde.

UIKit vs WatchKit

WatchKit y sus herramientas de desarrollo se han concebido con un propósito claro: hacer de las aplicaciones del reloj algo sencillo —casi humilde comparado con su hermano mayor, UIKit—, y por ello su forma de trabajar puede sorprender a los acostumbrados a crear apps para el actual ecosistema iOS.

En primer lugar, sus clases llevan el prefijo WKInterface en todas sus vertientes —probablemente debido a que “WebKit” comparte las mismas iniciales que “WatchKit”—, y pese a lo que uno pueda pensar en un principio, son pocas y no siempre idénticas en funcionamiento a sus respectivas en UIKit.

WatchKit vs UIKit

UIKit WatchKit
UIViewController WKInterfaceController
UIView WKInterfaceObject
UITableView WKInterfaceTable
UILabel WKInterfaceLabel
UIButton WKInterfaceButton
UIImage WKInterfaceImage
Superview WKInterfaceGroup
UIInterfaceDevice WKInterfaceDevice
MKMapView WKInterfaceMap

A estas hay que sumarles otras que no tienen equivalente directo en UIKit, como:

  • WKInterfaceTimer
  • WKUserNotificationInterfaceController
  • WKInterfaceDate
  • WKInterfaceSlider

A modo de apunte totalmente personal, he visto bastantes similitudes con el desarrollo en Android (en el buen sentido). Las vistas no se guían por coordenadas ni en relación con otras dentro del lienzo, sino que, al igual que ocurre en el sistema de Google, se utiliza una disposición lineal, a modo de lista, y sobre este se van colocando los elementos. Dicho de otra forma, las vistas se colocan una debajo de la otra, siguiendo un orden, de arriba a abajo. De esta forma eliminamos el tener que manejar el scroll, ya que todos los elementos de la interfaz “flotan” hacia arriba.

Otra similitud agradable es que los controladores se inicializan con un parámetro genérico al que han llamado contexto. Esto quiere decir que ya no es necesario que creemos métodos propios para pasar el modelo de un controlador a otro, sino que lo incorpora el framework. Para mi gusto esto es un gran avance, especialmente si tenemos en contra su contrapartida en UIKit con los prepareForSegue: , donde no tenemos más remedio que esperar a que el sistema instancie el controlador destino para configurarlo. A título personal me parece una absoluta aberración que rompe un poco mi predilección por los Storyboards.

Ahora cada WKInterfaceController se crea con un contexto que recibimos como parámetro en su método awakeWithContext(). El contexto es de tipo AnyObject?, así que no tenemos absurdas limitaciones de ningún tipo en este caso. Una gozada, pero ya digo, pura opinión personal.

Y dicho esto… FIGHT!

Star Wars - Obi Wan vs Vader

UIViewController vs WKInterfaceController

Desciende de NSObject y realmente no gestiona las vistas, sino que las configura y responde a sus eventos. Las comparo porque tienen un propósito equivalente, pero no busques su propiedad view porque no la tiene.

Inicialización

  • UIKit: viewDidLoad:
  • WatchKit: init(:)  (inicializador designado), awake(context) (posterior a init())

En UIKit Las aplicaciones no reciben parámetros en su inicialización y dejan el estado del controlador a merced de quien lo ha llamado. Solamente podemos sobrescribir el método que se ejecuta (viewDidLoad:) cuando se carga la vista principal en memoria. En WatchKit tenemos este awake(context: AnyObject?) con el que podemos “recuperar” cualquier objeto en el momento en que se crea el controlador. Muy útil en Swift, en donde es muy importante instanciar las propiedades de la clase para evitar los a veces tediosos optionals.

Además de este awake, también tenemos otros dos métodos más similares a viewDidLoad:, viewWillAppear:, etc, que tampoco reciben parámetros y que simplemente se llaman cuando el contralor va a mostrar las vistas en pantalla. Son willActivate() y willDeactivate().

Algunos métodos comunes

  • pushControllerWithName(_:context:)
  • popController()
  • presentControllerWithName(_:context:)
  • presentControllerWithNames(_:contexts:) : en WatchKit es posible crear una suerte de PageViewController de forma automática y definida en tiempo de diseño. Son las presentaciones paginadas de las que he hablado antes.
  • becomeCurrentPage() (para mandar el foco a una pantalla en modo paginado).
  • dismissController()

Y estos cuatro que personalmente voy a pedir a Apple para reyes.

  • contextForSegueWithIdentifier(_:)
  • contextsForSegueWithIdentifier(_:)
  • contextForSegueWithIdentifier(_:inTable:rowIndex:)

UIView vs WKInterfaceObject

Desciende de NSObject y curiosamente, Apple la considera una clase abstracta, porque especifica que no debemos instanciarlani siguiera crear subclases de ella. ¿Y si queremos crear un elemento propio? En ese caso heredas directamente de NSObject, o utilizas un IBOutlet y conectas esa vista en particular en tu controlador, que en tiempo de ejecución WatchKit ya se encargará de crear el objeto pertinente.

Algunos métodos…

  • setHidden(_:). Es importante notar que en WatchKit ocultar una vista significa dejar libre el espacio que ocupaba, similar al efecto que ocurre en CSS con display:none; y no con el de visibility:hidden;. Si ocultas una vista, otra ocupará su sitio de forma automática.
  • setAlpha(_:)
  • setWidth(_:)
  • setHeight(_:)

UITableView vs WKInterfaceTable

Desciende de WKInterfaceObject. Es quizá una de las clases que más descolocado deja cuando se empieza a trabajar con ella viniendo directamente de UIKit.

En WatchKit no encontrarás ni un protocolo Delegate ni un Datasource como lo harías en su versión iOS. El número de filas se especifica a mano durante la inicialización de la misma:

  • setNumberOfRows(_ numberOfRows: Int, withRowType rowType: String!)

No existen las cabeceras, ni las secciones, ni la edición… Mucho más sencillo para el tipo de uso que requiere el reloj.

Ahora lo que hacemos es especificar cuántas filas queremos y de qué tipo en willActivate(). El número lo provee nuestro modelo, al igual que hacíamos antes, y el tipo un String que deberemos haber registrado previamente en una fila del Storyboard, dentro de la tabla.

¿Una fila?

Pues sí, en WatchKit no existe la clase ‘celda’ propiamente, sino que las tablas se rellenan con filas. Eso sí, no busques la clase WKInterfaceRow, porque no existe: las filas son controladores que descienden directamente de NSObject.

Así que, en lugar de responder a los métodos de un delegado, tenemos que configurar en el Storyboard, dentro del WKInterfaceTable, de qué clase van a ser las filas, enlazar los respectivos IBOutlets, especificar un identificador para el nombre de la celda con una cadena de texto; y después, ya en el controladorestablecer el número de filas, el identificador anterior, e iterar manualmente para crear el objeto fila con rowControllerAtIndex() , por cada una de ellas.

Eso sí, el evento didSelectRowAtIndex() sí que está disponible, pero en la clase WKInterfaceController…

Y como habrás deducido, no tenemos una clase tipo TableViewController.

Superview vs WKInterfaceGroup

Desciende de WKInterfaceObject

Como he mencionado más arriba, los elementos de la interfaz se colocan uno tras otro, a modo de lista, similar a como creamos las tablas estáticas, de modo que un elemento como ScrollView no resulta necesario, pero sí un contenedor que permita agruparlos y manejar su disposición.

Los grupos sirven, esencialmente, para establecer vínculos más específicos entre diferentes controles, y poder manejarlos como una unidad.

Group

Por ejemplo, si tuviésemos tres secciones en la pantalla, digamos un temporizador arriba, una botonera abajo, una imagen y una etiqueta con su definición, y quisiéramos separar las dos últimas para que quedasen una a la par que la otra (en lugar de encima y debajo), y además colocarlas en el medio de la pantalla, utilizaríamos un grupo para definir una relación de posición solo vinculante a estas dos: temporizador, imagen junto a etiqueta en un grupo, y debajo la botonera.

En realidad, lo más parecido sería una UIView vacía, ya que solemos utilizarlas para contener otras subvistas.

UILabel vs WKInterfaceLabel

Desciende de WKInterfaceObject

¡Sin cambios! Además soporta NSAttributedString y permite especificar con una propiedad llamada “Min. Font Scale” qué escalado puede tener la fuente para adaptarse automágicamente a la pantalla del reloj, en un rango de valores de 0 a 1.

MKMapView vs WKInterfaceMap

Desciende de WKInterfaceObject.

Es una vista no interactuable de una región en un mapa. Se configuran dinámicamente en su controlador. Permite añadir anotaciones (hasta 5) y especificar el área visible que se ve en ella. Al tocar sobre la vista se abre la aplicación de Mapas en el AppleWatch del usuario.

Para cargar cualquier mapa es necesaria la conexión a datos del iPhone.

El resto de controles…

Los nuevos son…

  • WKInterfaceDate: Una etiqueta especial que muestra la fecha, y la hora con precisión de segundos y en el formato que queramos (con su zona horaria, con letras…)
  • WKInterfaceTimer: Una etiqueta especial que muestra una cuenta numérica en varios formatos.
  • WKInterfaceSeparator: Un simple separador como el utilizado en las celdas de las UITableView.
  • WKInterfaceSlider: Un control similar en apariencia a una barra de progreso con un stepper (un menos y un más a cada lado) para movernos por un rango de valores numérico.

Concluyendo

Creo que hay un gran interés en los wereables, al menos yo lo tengo, pese a lo limitado de esta plataforma de momento, y pienso que irá en aumento conforme se nos permita hacer más cosas con los sensores.

Si quieres añadir algo, crees que hay alguna errata o corrección, o simplemente quieres saludar, te animo a usar los comentarios.

Para más información, te recomiendo que eches un vistazo a la documentación oficial de Apple, que está bastante bien:

¡Nos vemos!

Escrito por Miguel Hernández Jaso

Autor del blog. Desarrollador especializado en iOS.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Mi Gobierno me obliga a decirle que utilizo 'cookies' en mi página. Si continúa navegando, quiere decir que está conforme con ello.