Il y a 3 années · 7 minutes · iOS, Mobile

WatchKit: Episode II – Codez une application Apple Watch en Swift

watchkit

Dans notre précédent article nous vous avions présenté les APIs de WatchKit, le kit de développement pour Apple Watch. Aujourd’hui, nous allons vous expliquer pas-à-pas comment coder une application Swift dédiée aux Apple Watch.
Vous y apprendrez comment réaliser une interface graphique pour une Apple Watch, partager du code entre application iOS et Apple Watch, ainsi que configurer l’UI depuis un jeu de données.

Le projet : codez une application Apple Watch en Swift

Le but de ce tutoriel est de créer une application permettant d’afficher des données relatives à une station de ski. L’interface se composera de deux vues (ou scènes) :

  1. La première affichera une liste de stations de ski à l’intérieur d’un Table
  2. La seconde vue affichera les informations relatives à la station de ski sélectionnée par l’utilisateur

Si vous souhaitez tester l’application ou comparer votre code pendant votre avancée dans l’exercice, libre à vous de le récupérer depuis notre repository Github.

watchkit-exercice
watchkit-exercice2

Pour réaliser l’exercice, ouvrez Xcode et créez un projet vierge nommé XebiaSkiDemo. Ensuite, ajoutez une nouvelle target pour avoir le support Apple Watch : File > New… > Target… > Apple Watch > Watch App

watchkit-exercice-xebiawatchkit-xebia-exercice

Vous remarquerez qu’en réalité Xcode a créé 2 nouvelles targets:

  1. XebiaSkiDemo WatchKit Extension
  2. XebiaSkiDemo Watch App

Pour connaître le rôle de chacune d’entre-elles n’hésitez pas à aller (re)lire notre article sur les APIs de WatchKit.

Ces deux targets vont nous donner les étapes à suivre pour la réalisation de l’application:

  1. D’abord la réalisation de l’UI dans XebiaSkiDemo Watch App (Watch App dans la suite de l’article)
  2. Puis le code de logique associé, dans XebiaSkiDemo WatchKit Extension (WatchKit Extension dans la suite de l’article)

1. Watch App

Le but de cette section est de réaliser l’UI pour les deux scènes de notre application:

  1. La liste des stations de ski
  2. Les informations d’une station de ski

Ces deux scènes sont à réaliser dans le storyboard contenu dans Watch App. Le travail est laissé comme exercice au lecteur. Voici cependant quelques conseils:

  1. La première vue est une liste. N’hésitez donc pas à utiliser des objets Table (WKInterfaceTable)
  2. La seconde vue est plus complexe : pensez à utiliser des Group pour pouvoir aligner les éléments (notamment horizontalement)

N’hésitez pas à aller voir notre exemple en cas de besoin ou à regarder le screenshot ci-dessous de notre storyboard.

watchkit-exercice3

Une fois terminée la première partie, vous aurez une UI prête à l’emploi. Ou presque. En effet, aucune donnée n’y sera affichée. Vous allez résoudre cet affront avec l’étape 2 : l’extension !

2.1 Prélude à l’extension : Cocoa Touch Framework

Comme déjà évoqué, WatchKit Extension contient toute la logique associé à Watch App. Cependant, dans la plupart des cas votre application iOS et la WatchKit Extension vont posséder des classes communes tels que les modèles, la couche réseau ou encore des catégories utilitaires.

Afin d’éviter de dupliquer cette logique, dans le respect du principe DRY (Don’t Repeat Yourself), il faudra partager un module parmi deux targets. Pour ce faire, il est nécessaire de mettre en place un framework. La création des frameworks est possible depuis Xcode 6 en générant une target de type « Cocoa Touch Framework » qui devra ensuite être ajoutée en tant que dépendance dans les autres targets de notre projet.

Pour créer le framework, dans le menu sélectionnez File > New… > Target… > Framework&Library > Cocoa Touch Framework. Le nom choisi sera XebiaSkiDemoFramework

watchki-exercice5
watchkit-xebia-exercice
watchkit-exercice6

 

Ensuite créez une classe, nommée SkiResort, afin de représenter les stations de ski.

public class SkiResort: NSObject {
    public var name: String
    public var photoURL: NSURL
    public var temperature: Int

 // L'implémentation du ctor est laissé comme exercice
}

Puis créez la classe SkiResortDataSource. Pour éviter d’implémenter des Web Services, qui ne sont pas le but de cet exercice, celle-ci va vous renvoyer une liste statique de stations de type SkiResort.

public class SkiResortDataSource {
    var allObjects: Array<SkiResort>
    
    public init() {
        self.allObjects = [
            SkiResort(name: "Arcabulle", photoURL: NSURL(string: "http://www.trinum.com/ibox/ftpcam/les-arcs_arcabulle.jpg")!, temperature: 5),
            SkiResort(name: "Arcs 1600 Pistes", photoURL: NSURL(string: "http://static1.lesarcsnet.com/image_uploader/webcam/large/lesarcs-1600-cam.jpg")!, temperature: -2),
            SkiResort(name: "Vanoise Express", photoURL: NSURL(string: "http://trinum.com/ibox/ftpcam/Peisey-Vallandry_vanoise-expresse.jpg")!, temperature: 4),
            SkiResort(name: "Arc 1950 Village", photoURL: NSURL(string: "http://www.trinum.com/ibox/ftpcam/arc-1950-haut-village.jpg")!, temperature: 0)
        ]
    }

    public var count: Int {
        get {
            return self.allObjects.count
        }
    }
    
    public subscript(index: Int) -> SkiResort {
        return self.allObjects[index]
    }
}

La dernière classe est une classe pour télécharger les images. Celle-ci est également laissée comme exercice. Vous pouvez aussi remplacer les URLs dans le code par le nom de ressources statiques ou encore récupérer la solution depuis le GitHub du projet.

Le framework est prêt, il est temps de passer à la dernière partie: l’extension !

2.2 WatchKit Extension

Cette section va se dérouler en deux grandes étapes:

  1. La logique associée à la liste des stations
  2. La logique associée à une station

Configurer la liste des stations

La liste des stations étant le point d’entrée dans notre Watch App, vous allez ici réutiliser le WKInterfaceController principal déjà crée par Xcode: InterfaceController, qui sera renommé en MasterInterfaceController.

Ensuite, déclarez les IBOutlets et effectuez la liaison dans le storyboard.

import WatchKit
import Foundation
import XebiaSkiFramework

class MasterInterfaceController: WKInterfaceController {
    @IBOutlet weak var mainTable: WKInterfaceTable!

watchkit-exercice7

 

Par la suite, configurez la WKInterfaceTable de la vue pour afficher les stations de ski provenant du SkiResortDataSource (créée précédemment dans le framework):

// A ajouter dans MasterInterfaceController

private var dataSource = SkiResortDataSource()
    override init() {
        super.init()
        
        reloadTableData()
    }
    
    func reloadTableData() {
        mainTable.setNumberOfRows(self.dataSource.count, withRowType: "SkiResortTableRow")  // bien vérifier l’identifiant “SkiResortTableRow” dans votre storyboard (cf screenshot suivant)
        for var index = 0; index < self.dataSource.count; ++index {
            let row = mainTable.rowControllerAtIndex(index) as SkiResortTableRowController
            row.configureWithSkiResort(self.dataSource[index])
        }
    }

watchkit-exercice3

Pour effectuer cette configuration, utilisez une classe custom : SkiResortTableRowController, qui sera utilisée par chacune de nos cellules. Malgré un nom qui peut prêter à confusion, SkiResortTableRowController ne sera pas un WKInterfaceController mais bien un NSObject !

import WatchKit
import XebiaSkiFramework

class SkiResortTableRowController: NSObject {
    @IBOutlet weak var titleLabel: WKInterfaceLabel!
    
    func configureWithSkiResort(skiResort: SkiResort) {
        self.titleLabel.setText(skiResort.name)
    }
}

Voila vous pouvez (enfin !) lancer le simulateur et voir votre application tourner.

Afficher une station

Le but est de configurer l’application pour afficher les détails d’une application. Pour cela, 3 étapes seront nécessaires :

  1. Ajouter un interface controller
  2. Ajouter un segue de type Push
  3. Configurer le interface controller

Pour la première étape, ajoutez tout simplement un nouveau controller à XebiaSki WatchKit Extension, que vous nommerrez DetailInterfaceController. Configurez votre scène dans storyboard pour lui attribuer une classe custom et définir ses IBOutlet.

import WatchKit
import XebiaSkiFramework

class DetailInterfaceController: WKInterfaceController {
    @IBOutlet weak var nameLabel: WKInterfaceLabel!
    @IBOutlet weak var temperatureLabel: WKInterfaceLabel!
    @IBOutlet weak var photoImageView: WKInterfaceImage!
    @IBOutlet weak var dateLabel: WKInterfaceDate!

Deuxième étape, ajoutez un push segue entre SkiResortTableRow et DetailInterfaceController dans le storyboard. Compilez et lancez. Vous devriez voir le template de votre vue apparaître lorsque vous cliquez sur une cellule.
Troisième et dernière étape, configurez le DetailInterfaceController. Pour ce faire il faudra utiliser une fonctionnalité propre à WatchKit : les contextes. Les contextes sont des objets (arbitraires) que l’on peut passer aux WKInterfaceController afin de les configurer.

 private var skiResort: SkiResort? // on garde une réf le contexte pour pouvoir le réutiliser ailleurs dans le controller
    
 override awakeWithContext(context: AnyObject!) {
     super.awakeWithContext(context)

     if let skiResort = context as? SkiResort {
         self.skiResort = skiResort

   // Une fois le contexte défini, on peut configurer les InterfaceObject de notre vue
   self.nameLabel.setText(skiResort.name)
         self.temperatureLabel.setText(String(skiResort.temperature) + "°C ")
   self.photoImageView = // Ajouter ici le code pour afficher la photo de la station selon que vous téléchargiez l'image ou que vous utilisiez une ressource statique
    }
 }

Compilez et lancez. Et voila, vous avez réalisé votre première Watch App !

Conclusion

Ce tutoriel vous a montré comment réaliser une application simple mais complète pour Apple Watch. Le prochain vous montrera comment ajouter des Glances et des notifications pour lancer votre Watch App et la rendre encore plus « badass » aux yeux de vos utilisateurs.

En attendant n’hésitez pas à relire cet article ainsi que celui sur les API WatchKit.

Simone Civetta

Simone est responsable technique des équipes mobilités chez Xebia.

Il est également formateur au sein de Xebia Training .

Jean-Christophe Pastant

Consultant iOS, fervent défenseur du code de qualité.

One thought on “WatchKit: Episode II – Codez une application Apple Watch en Swift”

  1. Publié par hadrienbbt, Il y a 10 mois

    Hi,

    I’m a begginer in Swift development, and I see that error in the InterfaceController class:
    « fatal error: unexpectedly found nil while unwrapping an Optional value »

    It is due to the mainTable Optional variable in the reloadTableData method, but I don’t know how can I fix this…

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *