Accélérez la compilation Xcode avec cocoapods-binary

Illustration des plugins Cocoapods

TLDR : Dans cet article je présente comment nous avons réduit de 22% le temps de compilation du projet RocketSkill. Cela représente 67 secondes sur chaque compilation. Ce gain a été obtenu avec 1 seule modification du podfile du projet qui nécessite l’utilisation d’un plugin CocoaPods : cocoapods-binary.


Pour rappel, CocoaPods est un gestionnaire de dépendances.

  1. Il sert à assurer la cohérence entre les librairies que l’on importe dans le projet. Il vérifie et s’assure de la compatibilité entre toutes les versions des librairies (et des dépendances) que le projet utilise.
  2. L’ outil, en ligne de commande, est aussi utilisé pour configurer le projet suivant les instructions de chaque librairie. En effet, chaque pod possède un fichier podspec qui explique « ou trouver les sources », « quelles sont les dépendances » et « comment configurer le projet pour cette librairie ».

En gros, on perd LARGEMENT moins de temps en préparation du projet et on se focalise un peu plus sur le produit !

Avant CocoaPods

🤠 Il faut dire qu’avant c’était quand le « Far West ». Pour utiliser des librairies externes dans un projet il fallait intégrer et tout configurer à la main. Cela prenait un temps assez considérable pour uniquement réussir à compiler le projet.

On se rappelle la joie de rajouter des « static library », de la gestion des « Header Search Path » et la gestion des flags de compilation. On a mieux à faire, non ?

L’arrivée de CocoaPods

😇 En 2011 arrive CocoaPods. La configuration est un peu magique mais elle fonctionne car les développeurs ont bien préparé leurs librairies.

La communauté iOS est très active et il existe beaucoup de projets OpenSource. Pourquoi intégrer ces projets OpenSource dans vos projets ? Pour déléguer des parties de son code à la communauté, ça fait moins de code à maintenir. Et par nature, un développeur veut optimiser son temps et n’a pas forcément envie de développer des choses qui existent déjà « gratuitement ».

Les reverts de CocoaPods

Beaucoup de choix ! (Trop?)

Actuellement, le 17 décembre 2019, il existe 65 318 pods distincts disponible sur CocoaPods. Cela fait beaucoup de choix et il est parfois dur de s’y retrouver. Il existe plusieurs moyens de trouver son bonheur :

  • Par CocoaPods directement, je ne suis pas spécialement emballé des résultats de recherches…
  • Par CocoaControls, une bonne source car c’est illustré et les tags aident bien à se fouiller.
  • Par Github directement, on peut tomber sur son bonheur.

Des choix qui peuvent être « lourd »

Les développeurs ont bien fait les choses, les fichiers .podspec décrivent la configuration du projet et ses dépendances. Ces fichiers sont même parfois un peu trop fournis et on se retrouve à importer des tonnes de librairies ! Oui je pense beaucoup à toi Firebase. Certaines dépendances tirent énormément d’autres sources et c’est là que le temps de compilation se trouve impacter et on arrive au coeur de l’article !

Le temps de compilation

Quels événements déclenchent une compilation du projet ?

  • Quand on fait un pod install / update
  • Quand on « build » le projet
  • Quand on change d’architecture (simulateurs/appareils)
  • Quand on supprime les « derived data »
  • Quand on fait un Clean dans Xcode (Xcode > Product > Clean Folder)
  • Quand on change de version d’Xcode ou de version de Swift

J’en ai eu mare de perdre 15 à 20 minutes à chaque compilation et je ne parle même pas des 45 minutes pour archiver RocketSkill-iOS, il me fallait quelques pistes pour réduire ce temps :

  • Retirer certaines dépendances
  • Passer à Carthage le projet

Je n’avais pas parlé Carthage avant et c’est normal. Je trouve que Carthage demande trop manipulations et de configuration. On ne va pas se mentir, j’aime le confort de CocoaPods et la configuration presque automatique du projet. MAIS il y a une chose me plaisait bien dans Carthage, la pre-compilation des libraires externes !

A vrai dire, je m’étais déjà posé la question plusieurs fois, pourquoi avoir les sources des librairies externes dans le projet, sachant que je ne les modifie pas. C’est du temps de compilation perdu de les recompiler à chaque fois et une bonne idée d’optimisation !

Après de multiple tests et tentatives je fini par tomber CocoaPods-Plugin qui répond exactement à mes besoins :

  1. Avoir une installation toujours aussi simple (vive CocoaPods)
  2. Pré-compiler mes librairies (vive Carthage)

Cocoapods-plugin pour gagner du temps !

J’ai réalisé un petit test, en prenant un podfile simplifié de mon projet avec 18 librairies externes. (le projet sur GitHub ou les sources) et voici les temps de compilation obtenu.

pod install
(seconds)
Build project
(seconds)
Build project other device/arch
(seconds)
Archive
(seconds)
CocoaPods105050120
CocoaPods + plugin
cocoapods-binary
2805520

On prend plus de temps à faire le « pod install ». C’est normal, le plugin compile les frameworks pour les simulateurs et les appareils mobiles.

On passe moins de temps pour compiler et archiver le projet. C’est normal, le projet de démo est petit et les dépendances sont compilées dans la phase d’installation.

Fréquence à laquelle on fait cette actionGain de temps
Faire un « pod install« Rarement– – –
« Builder » un projetTrès souvent+++
Changer d’appareil
(« Builder » un projet)
Souvent+++
Archiver un projetDe temps en temps++

Quand on y pense, c’est pas mal ! On gagne beaucoup de temps sur des actions que l’on fait souvent !

Un gain appréciable !

Sur RocketSkill, j’avais 25 librairies. Ces 25 librairies produisent un total de 50 dépendances à compiler. J’ai réussi à migrer 20 librairies en compilation en phase d’installation (cocoapod-binary).

pod install
(seconds)
Build project
(seconds)
CocoaPods10300
CocoaPods + plugin
cocoapods-binary
274233

On passe de 300 à 233 secondes pour compiler le projet. On gagne 67 secondes sur chaque compilation. Il suffit de penser au nombre de développeurs sur votre projet et au nombre de compilations réalisées chaque jour pour y voir un retour rapide sur investissement.

En migrant une partie des librairies en compilation pré-installation, on gagne 22% de temps de compilation !

Comment on migre les librairies

Ce n’est pas très compliqué, il suffit d’installer cocoapods-binary et modifier un peu le podfile de votre projet.

pod 'Alamofire', '4.8.0'
pod 'Alamofire', '4.8.0', :binary => true

La limite de cocoapods-binary

Si c’était possible, j’aurais migré 100% de mes dépendances en mode « pré-compilées ». Malheureusement, je n’ai pas réussi, j’ai rencontré des difficultés avec certaines librairies (par exemple les SDK Facebook) qui sont codées en Objective-C et pour lequel certains header posent problèmes.

La limite est donc la manière dont sont codées certaines libraires, mais cela peut s’arranger, ça sert à ça l’OpenSource 💪.