Intermédiaire

Passer de XAML/C# à iOS/Swift : Mode d’emploi

Swift logo Quand on est développeur Microsoft et que l’on a ses habitudes, il peut être fastidieux de s’intéresser à une autre plateforme, d’autant plus si celle-ci est la plateforme d’Apple. Dans cet article, j’expliquerai les raisons qui peuvent pousser un développeur XAML/C# à faire ce genre d’exercice technique, mais aussi quels sont les éléments à connaître et maîtriser pour que ce défi technique se passe en douceur, avec un parallèle occasionnel entre les technologies de Microsoft et les technologies d’Apple.

Pourquoi passer de Microsoft à Apple ?

 

Ici, je ne parle pas d’opérer une migration ou un abandon radical d’une plateforme à une autre, mais plutôt des occasions qui peuvent pousser à s’intéresser à d’autres plateformes. Et elles sont nombreuses :

  • Opportunités professionnelles : Quand vous avez des relations de confiance avec vos clients, que vous souhaitez les conserver, qu’ils souhaitent entretenir ses relations sans intermédiaire, etc….
  • Limitations technologiques : Si vous souhaitez travailler avec une montre connectée, seules les plateformes Android et iOS le permettent pour le moment. Si l’on souhaite travailler avec l’Apple Watch, seule la plateforme d’Apple est envisagée, etc…
  • Limitations techniques : Quand les outils de développement multiplateformes que vous utilisez ne couvrent pas encore l’intégralité des SDK des plateformes cibles. C’est un cas que je rencontre souvent avec Xamarin, pour le support de nouveaux appareils (Android Wear / Apple Watch / Apple TV). Bien que les équipes de Xamarin travaillent ardemment pour une mise à disposition des outils N+1, le support complet peut prendre quelques jours de plus, ce qui parfois ne peut pas convenir au client.
  • Extension de l’expertise technique : Quand vous faites de la mobilité et que vous souhaitez étendre votre connaissance de la mobilité globale, sans vous restreindre à une seule plateforme.
  • Curiosité : Sans aucune motivation particulière immédiate (ou tout autre intérêt personnel/professionnel)

Me concernant, je dois avouer qu’à l’époque, toutes ces raisons avaient été une motivation, ne souhaitant pas me cantonner à une unique plateforme (avec un zeste de curiosité).

Par ailleurs, l’expertise Microsoft dont on bénéficie aujourd’hui, agrémentée d’une connaissance et/ou expertise des autres plateformes est le meilleur moyen… d’intégrer l’écosystème et les services Microsoft (notifications, cloud, office, etc…) au sein de la concurrence.

 

Les outils indispensables pour commencer à développer

 

Il faudra être honnête, développer pour la plateforme d’Apple revient à faire des investissements conséquents. Il ne faut d’ailleurs pas non plus spéculer sur les retours sur investissements immédiats, mais plutôt y voir une stratégie long terme. En résumé, développer pour Apple coûte un peu cher mais peut s’avérer rentable sur plusieurs aspects globaux (expertise, business, etc…).

 

Hardwares

Le premier outil indispensable est bel et bien un Mac. C’est une limitation technique imposée par Apple, un prérequis obligatoire. Les modèles sont nombreux et votre choix sera fonction des moyens dont vous disposez.
Si vous envisagez de développer pour un appareil spécifique, bien que des simulateurs soient disponibles, il est vivement recommandé de disposer de l’appareil en question (Apple Watch, iPhone, etc…) pour avoir le rendu réel pendant les tests de vos applications. Bien entendu, leur achat peut être “retardé” pour “préparer les dépenses”.

 

SDK & IDE

Apple offre, avec son IDE Xcode, le SDK nécessaire au développement d’applications pour ses appareils. Contrairement à Microsoft qui offre la possibilité de choisir éventuellement les outils/SDK utiles à nos besoins, Apple embarque tous ses SDK complets pouvant être utilisés (Watch/TV/Mac/Phone/CloudKit). Si Xcode convient largement pour créer nos applications, il est possible d’utiliser Visual Studio Code pour éviter d’avoir à ouvrir l’espace de travail Xcode et porter des modifications sur des fichiers, sans forcément avoir besoin de compiler, mais tout en gardant une colorisation syntaxique.

 

Gestionnaire de paquets

En utilisant les outils de Microsoft, il est courant (quasiment indispensable) d’utiliser Nuget pour la gestion de paquets. Pour le développement avec Xcode et la gestion de paquets, il existe des outils intéressants avec leurs avantages et leurs inconvénients, comme CocoaPods et Carthage. Chacun de ces outils a un principe similaire dans la mesure où les dépendances seront définies dans un fichier (propre à chaque gestionnaire). Ces outils n’ont cependant aucun soutien de la part de Apple et sont maintenus par des développeurs indépendants.

 

CocoaPods

CocoaPods est le gestionnaire de paquet historique pour les projets Xcode. Supportant les projets Swift et Objective-C, il apporte une bibliothèque de dizaine de milliers de librairies permettant d’accroître (plus ou moins) la productivité au sein de votre projet.
J’ai quand même à déplorer quelques problèmes plus ou moins gênants en l’utilisant :

  • son caractère intrusif : Bien que son installation soit facile, son intégration modifie systématiquement l’espace de travail Xcode (par opposition à une solution avec Visual Studio) pour y rajouter un nouveau projet. Ce dernier va contenir une cible qui embarque toutes les dépendances (et leurs sources) nécessaires à votre projet. Un projet de dépendances lui-même étant une dépendance… En bref, pour la clarté de mes projets, je préfère minimiser les modifications de mon espace de travail (le terme courant pour Visual Studio serait solution).
  • une gestion des paquets locaux fastidieuse : De par le fait que CocoaPods ne soit pas intégré à Xcode, il n’est pas possible d’avoir une visibilité constante sur le statut des paquets, ni même aisé de les mettre à jour. Il faudra manuellement le faire via le terminal. Il existe toutefois des plugins Xcode pour gérer CocoaPods, mais j’avoue ne pas les avoir testés afin de minimiser les plugins tiers.
  • des problèmes de résolution de dépendances : Il est souvent arrivé que des dépendances ne soient pas mises à jour, peu importe le moyen utilisé (automatique, manuel…). Il a fallu souvent réhydrater l’espace, en supprimant le fichier de dépendances, les dépendances elles-mêmes et en les installant de nouveau.
  • des problèmes dans la suppression complète de Cocoapods : Si, pour une raison quelconque, vous souhaitez ne plus utiliser de dépendances (ou alors, ne plus utiliser Cocoapods), vous devez nettoyer l’espace de travail en supprimant les dépendances créées par l’outil. Cependant, quelques liaisons fortes sont créées avec votre projet principal et il faut utiliser un outil pour supprimer l’outil d’origine… Il s’agit de Cocoapods-deintegrate.

Autrement, le site est bien fait et la recherche des dépendances est claire, avec des exemples la plupart du temps sur l’utilisation des frameworks, ce qui est fort appréciable.

 

Carthage

Carthage est plutôt un gestionnaire de paquets indépendant et décentralisé qui n’est pas aussi intrusif que Cocoapods. En effet, il n’altère pas l’espace de travail, construit les binaires grâce à xcodebuild et laisse au développeur la responsabilité d’ajouter à ses projets les dépendances qui auront été récupérées et compilées.
Cette simplicité, de laisser la responsabilité au développeur, aura la charge de complexifier un “peu” l’intégration des dépendances dans le processus de compilation : il faudra éditer les phases de compilation pour assurer la copie des frameworks ajoutés manuellement à votre projet.
Par ailleurs, il n’existe pas de catalogue de librairies comme pour Cocoapods, bien que la majorité des librairies les plus importantes proposent une intégration avec Carthage. Le seul moyen de s’en assurer sera de vérifier la compatibilité sur les pages des sources des différents frameworks souhaités.

 

Quel gestionnaire de paquets choisir ?

Chaque solution a ses avantages et ses inconvénients. J’ai pu utiliser l’un ou l’autre de ces outils (selon les projets des clients pour lesquels je suis intervenu) et je n’ai pas vraiment de préférences si ce n’est le fait de privilégier le moins de dépendances possible. J’avoue avoir eu aussi à intégrer certaines dépendances dans mes projets sans aucun gestionnaire (en y copiant les sources). Cela peut être pratique dans le cas d’un projet où l’on a peu de dépendances, pour un besoin par ailleurs très ponctuel.

Si vous vous intéressez aux librairies les plus utilisées, un article récent parle des librairies les plus utilisées dans le Top 100 des Apps iOS sur le store US.

 

Pourquoi Swift ?

L’idée n’est pas du tout de débattre sur le sujet et ne reflète que mon point de vue pur et simple.
A mes débuts avec iOS, j’ai trouvé très fastidieux d’utiliser Objective-C comme langage. C’est vrai que mes années d’expérience reposent sur une syntaxe de langage beaucoup moins verbeuse que celle que présente ce langage.

NSString *funString = @"Ceci est une blague.";
NSString *fullString = [funString stringByAppendingString:@", lololol!"];

Je dois admettre que l’on avait tendance à taper un peu plus de caractères que la normale (beaucoup de crochets), argument peu recevable dans mon exemple mais qui pouvait facilement dériver beaucoup plus loin.

Swift avait des arguments qui ont attiré mon attention :

  • Une popularité grandissante : Bien qu’elle ne puisse pas être concrètement mesurée, on peut tout de même remarquer :
    • Une très grande mise en avant de Swift par Apple sur le site développeur
    • De plus en plus de Frameworks utilisant Swift disponibles sur GitHub
    • De plus en plus de librairies/SDK créés uniquement en Swift (cas de la dernière version du SDK Dropbox )
  • Une syntaxe agréable et un peu plus claire par rapport à l’expérience des langages comme le C#/C++/Java, etc…

L’affinité pour Swift ne peut donc qu’être plus naturelle par rapport au profil d’un développeur Microsoft.

Si vous souhaitez en savoir plus, en plus de la documentation Swift d’Apple qui est assez bien faite et qui regorge d’exemples et de ressources, certaines ressources peuvent vous apporter des compléments d’information, que ce soit sur le langage ou le développement iOS en lui-même, comme par exemple This Week in Swift et iOS Dev Weekly.

 

Préparer les bases de sa première application

Une fois que vous avez commencé à appréhender les bases de Swift, vous serez un peu plus prêts pour pouvoir poser les bases de votre application. Entre la gestion du layout, ou encore les classes et API existantes, je ne pourrai pas parler en détails de tout mais j’évoquerai les pistes pratiques à savoir en me servant de petites bases de la dernière application iOS que j’ai pu créer.

 

XCode et AutoLayout

Il faudrait des articles entiers pour parler de XCode, ou encore de la gestion de l’interface avec AutoLayout d’une application iOS. Mais d’autres l’ont déjà fait sans aucun doute mieux que je ne le pourrais. Toutefois, il existe de bonnes ressources qui ont pu m’aider :

D’autres ressources peuvent notamment exister sur les principaux sites e-learning (Pluralsight, CodeSchool, etc..). Je vous laisse le soin de les découvrir.

 

Pattern d’architecture MVC & MVVM

La création d’une application iOS se base sur un pattern d’architecture quasiment imposé (voir même indispensable) qui est Model-View-Controller (MVC). En très peu de mots, nous pourrions dire que :

  • Le modèle encapsule non seulement les données spécifiques d’une application mais aussi la logique métier.
  • La vue est un composant visuel dans l’application capable de gérer son apparence, afficher des données/du contenu et/ou répondre aux actions de l’utilisateur.
  • Le contrôleur quant à lui est un composant intermédiaire entre une vue et un ou plusieurs modèles. C’est lui qui est capable d’orchestrer l’application et d’assurer la cohésion entre la vue et les modèles, ainsi que de gérer le cycle de vie des objets, etc…

En développant vos applications XAML et en industrialisant vos projets, vous avez sans aucun doute été familiarisés à l’utilisation du pattern Modèle-Vue-VueModel (MVVM). Il est possible d’utiliser ce pattern également avec Swift.

  • Les notions de vues et de contrôleur (ou plutôt de “contrôleur de vue”) restent identiques à celles modèle MVC, à l’exception du fait que le contrôleur ne parle plus directement au modèle mais c’est la responsabilité du “modèle-vue” (ViewModel).
  • Le modèle ne communique avec aucune des couches mais est sollicité par le modèle-vue uniquement.
  • Le modèle-vue est utilisé uniquement par le contrôleur et il gère toute la logique de présentation, déchargeant ainsi le contrôleur.

On retrouve donc (dans le désordre) une architecture de type Vue – Contrôleur – VueModel – Model.

La structure de l’application offre ainsi une plus grande souplesse architecturale, plus de scalabilité et de possibilité d’isolation. On arrive ainsi à conserver les habitudes liées à notre plateforme favorite (Microsoft en l’occurrence).

 

Cas d’une application spécifique

Imaginons une application consommant donc des services REST exposant des données au format JSON.
Il y a plusieurs façons d’aborder la création de cette application :

  • Soit on utilise des API tierces encapsulant les API natives, mais en échange, le risque est pris qu’une éventuelle migration (vers Xamarin, par exemple) serait beaucoup plus complexe
  • Soit on favorise les API natives (pour faciliter une migration probable vers une technologie comme Xamarin).

J’aurais voulu n’utiliser que des APIs natives, mais parfois, c’est un peu compliqué de ne se reposer que sur elles, d’autant plus si le temps est limité.

 

Gestion des requêtes HTTP

Dans nos applications C#, il est courant d’utiliser la classe HttpClient (que ce soit la version initiale pour des raisons de rétro-compatibilité ou celle rendue disponible via les API WinRT).

Dans les applications iOS, avec Swift, pour gérer les requêtes HTTP, on a tendance à privilégier la classe NSUrlRequest ou sa sous-classe variable NSMutableUrlRequest

Voici un exemple de code pour créer une fonction de base dédiée à la création d’une requête :

let defaultJsonAcceptHeader = "application/json";

private func buildRequest(url: String, httpMethod: String, requestBody: String?) -> NSMutableURLRequest {

    let request = NSMutableURLRequest(URL: NSURL(string: url)!)
    request.HTTPMethod = httpMethod
    request.addValue(defaultJsonAcceptHeader, forHTTPHeaderField: "Accept"

    if requestBody != nil {
      request.HTTPBody = requestBody!.dataUsingEncoding(NSUTF8StringEncoding)
    }
    return request
}

Quand bien même vous ne seriez pas familiers avec Swift, le code reste assez compréhensible. Il faut noter que l’url au format string doit être passée à notre requête via un objet de type NSURL.

Dès lors que notre requête est créée, il va falloir utiliser un autre objet afin de l’exécuter. Depuis iOS 7, c’est l’objet NSURLSession qui est privilégié pour ce cas.

let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request) {
    (data, response, error) -> Void in
        //TODO
}
task.resume()

Au premier coup d’œil, vous aurez sans doute remarqué que contrairement à HttpClient, la gestion de l’asynchronisme ne présente pas de contrôle d’exécution de type en ligne (rendu possible grâce à async/await) mais est rendue possible grâce à un modèle de programmation asynchrone qui peut presque rappeler ce que l’on connait avec l’Asynchronous Programming Model (APM).

Grâce à la méthode dataTaskWithRequest, il est possible de créer une tâche de session (NSURLSessionTask) et de récupérer via un handler (completionHandler) le résultat de notre requête quand le chargement de la requête sera complet.

L’inconvénient de cette méthode est qu’il faudra au niveau des contrôleurs ou vues-modèles également passer des callback à nos méthodes pour récupérer nos résultats au plus haut niveau de notre logique métier et l’interface de notre vue.

Une programmation type async / await est possible, mais il faut créer une surcouche d’exécution de vos méthodes, et cela peut être fastidieux et compliquer vos services.

Petite astuce, il faut penser à configurer la clé de configuration NSAppTransportSecurity dans le fichier Info.plist, clé relative au transport de sécurité au sein de l’application :

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

 

Gestion du JSON

Tout comme en .NET, il y a possibilité de manipuler le JSON d’une façon native grâce à l’objet NSJSONSerialization.
Pour l’utiliser, c’est relativement simple :

let json = "{\"code\":\"ERR_00003\", \"message\":\"Unexpected error.\"}"
let data = (json as NSString).dataUsingEncoding(NSUTF8StringEncoding)
let decodedJson = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! Dictionary<String, AnyObject>

Le résultat de mon JSON est encodé comme un dictionnaire de clé-valeur ou la clé est toujours au format string et la valeur peut être de différents types. Pour récupérer ma valeur, on procède ainsi :

let message = decodedJson["message"] //affiche Unexpected error.

Le problème est qu’il devient vite fastidieux de mapper l’intégralité de notre dictionnaire vers un objet. C’est ce qui avait bien entendu motivé le fait que je choisisse finalement une librairie existante qui fait le même travail que JSON.NET (que l’on ne présente plus). L’idée est de pouvoir désérialiser, par exemple, du JSON directement vers un objet. Il existe pas mal de librairies qui le permettent, mais c’est EVReflection qui avait le plus attiré mon attention. En effet, c’est la librairie la moins intrusive que j’avais pu trouver, et celle qui supporte le plus de plateformes (ios/wos/tvOs), la plus souvent mise à jour aussi, etc…

Il faut tout d’abord créer ses modèles (et les faire hériter de NSObject). Voici un exemple d’objet représentant une activité :

public class ActivityResponseModel : NSObject {
    var id: Int = -1
    var name: String = ""
    var  activityType: String = ""

    public override init() { }
}

Et pour désérialiser mon JSON vers une liste d’activité avec EVReflection, on procède ainsi (cas de désérialisation d’un tableau) :

let activitiesResponse:[ActivityResponseModel] = EVReflection.arrayFromJson(ActivityResponseModel(), json: jsonString)

Et voilà !
Nous ne verrons pas davantage de choses concernant la programmation de C# vers Swift tant il y a à dire, mais ce que nous avons pu voir ici constitue un bon petit début (en dehors du langage Swift en lui-même).

 

La publication de son app, kezako

 

Pour accéder au portail de publication d’Apple, iTunesConnect, il est nécessaire de disposer d’un compte développeur. Une fois les frais de souscription payés, il sera possible d’accéder au portail.

iTunes Connect

Là aussi, il y a tant à dire car il est aussi riche en fonctionnalités que les autres portails de publication.
Toutefois, ce que j’ai apprécié par rapport au portail de publication Windows, c’est :

  • la simplicité (et la gestion) des publications et des versions
  • la gestion des screenshots (et des vidéos) par plateforme et facteur de forme
  • la possibilité de gérer des profils et des rôles pour le compte de publication
  • la gestion des tests avec TestFlight
    • la notion d’utilisateurs externes et internes pour les betas testeurs
    • la gestion des retours utilisateurs via l’application TestFlight
    • la gestion des plateformes (iOS et tvOS) et de leurs tests

Il me tarde du coup de voir les évolutions du portail développeur Microsoft par rapport à l’arrivée de Windows (Mobile) 10.

 

Mon recul sur le développement iOS par rapport à mon expérience Microsoft

 

L’expérience passée à développer des applications Microsoft m’a beaucoup aidé à appréhender le développement iOS. C’est vrai qu’il y a une phase assez importante de documentation et de formation sur le sujet, y compris le langage en lui-même (Swift) mais il est possible de s’en sortir. Maîtriser Xcode et la gestion de l’UI a été, c’est vrai, un peu fastidieux au tout début. Je me souviendrai longtemps de mes réflexes de développeur Windows avec XCode (à essayer de générer des événements en double clic ou à rechercher mes raccourcis préférés), et c’est bien sur ce dernier point qu’il faudra sans aucun doute passer un peu plus de temps.

 

Conclusion

 

Pour un petit mode d’emploi, j’espère que vous aurez eu suffisamment d’informations sur le sujet pour bien démarrer. Il y a encore bien des choses dont je n’ai pas parlé (la gestion de ses appareils, des certificats de développement ou de publications, etc…), mais je pense vous avoir mis un peu sur la bonne voie. Voilà, je ne peux plus que vous souhaiter un bon développement !

Nombre de vue : 139

COMMENTAIRES 1 commentaire

  1. Merci David pour cet article intéressant, instructif et complet !
    Je pense qu’il peut intéresser nombre de développeurs Microsoft s’intéressant à IOS et ne sachant pas par où commencer

AJOUTER UN COMMENTAIRE