Kotlin/Native est un nouveau dialecte de Kotlin permettant de prendre en charge la compilation de code vers du code machine autonome, qui ne nécessite pas de JVM pour être exécuté. Le compilateur Kotlin/Native, nommé Konan, s’interface avec l’infrastructure du compilateur LLVM afin de prendre en charge un bon nombre de cibles, telles qu’Android Natif, Linux, macOS, iOS, Web Assembly et d’autres.
Annoncé en avril, Kotlin/Native a maintenant atteint la version 0.6, publiée en février 2018. À partir de la version 0.5, Kotlin/Native introduit une nouvelle cible, qui peut jouer un rôle fondamental dans le cadre des projets iOS, à savoir les Frameworks.
Dans cet article, nous verrons comment créer un framework iOS en utilisant du code Kotlin. Notre bibliothèque ne fera rien d’extraordinaire, mais ce sera un excellent point de départ pour des évolutions futures.
Pour porter à terme ce tutoriel vous aurez besoin d’une machine fonctionnant sous macOS et Xcode 9.2.
Comment fonctionne Konan
Comme mentionné ci-dessus, Konan s’interface avec le compilateur backend LLVM afin de prendre en charge un certain nombre de cibles, telles que Linux, macOS, iOS, Web Assembly et d’autres. Le compilateur LLVM prend en entrée une représentation intermédiaire (IR, ou LLVM-IR) et génère du code machine (ou, mieux, du code objet) pour un certain nombre d’architectures CPU supportées (telles que ARM, x86 et bien d’autres).
Dit autrement, Konan compilera le code Kotlin à LLVM-IR et LLVM s’occupera du reste, en compilant LLVM-IR jusqu’à ARM (ou d’autres processeurs).
Pour commencer: Gradle
Pour commencer, vous devez d’abord installer Gradle (https://gradle.org/install/). Si cela ne vous parle pas, Gradle est l’outil de construction principal dans l’environnement JVM et il est utilisé par la grande majorité des projets Android. Avec Gradle, nous serons en mesure de définir les dépendances et les tâches dont nous avons besoin dans le cadre de la compilation de notre projet. De plus, Gradle est facilement extensible via des plugins, et nous utiliserons l’un d’entre eux pour nous aider à créer les tasks dont nous avons besoin pour compiler notre framework.
Le moyen le plus simple d’installer Gradle est via Homebrew, à l’aide de la commande brew install gradle.
Configuration du projet
Créons un nouveau dossier de projet, par exemple « MyProject ». Nous pouvons maintenant ouvrir le shell dans « MyProject » et lancer
gradle init
Cette opération va créer la configuration de base pour notre projet.
Maintenant, nous allons ajouter les ressources suivantes à « MyProject » :
- Un fichier gradle.properties vide
- Un dossier, nommé « myframework », qui contiendra code et propriétés de notre bibliothèque. Cette dernière, dans notre configuration, est déclarée en tant que sous-projet de « MyProject ».
- Dans le dossier « myframework », nous ajouterons:
- L’arbre de dossiers suivant : src/main/kotlin/fr/xebia/myframework
- Un autre fichier build.gradle vide
Le résultat devra être le suivant:
├── build.gradle ├── gradle ├── gradlew ├── gradlew.bat ├── myframework │ ├── build.gradle │ └── src │ └── main │ └── kotlin │ └── fr │ └── xebia │ └── myframework └── settings.gradle |
Cette structure suit les conventions de la plupart des projets Java et Kotlin et nous permet de préparer notre projet pour accueillir d’autres sous-projets dans le futur au cas où nous en aurions besoin – et ça sera le cas d’un autre article.
Configuration de l’environnement
Nous allons maintenant définir les propriétés de base de notre environnement.
Le fichier settings.gradle référence les modules du projet que nous construisons, dans notre cas, « myframework ». Nous allons donc ajouter au fichier la ligne suivante :
include ':myframework'
Le fichier build.gradle situé à la racine contiendra la configuration principale utilisée dans notre projet et sous-projet. En particulier, nous allons définir la version de kotlin à utiliser (1.2.21) et la version du compilateur Konan (0.6). Également, il faudra définir les repositories qui seront utilisés par notre script de génération, c’est-à-dire JCenter.
allprojects { buildscript { ext.kotlin_version = '1.2.21' ext.konan_version = '0.6' repositories { jcenter() } } }
Configuration de « myframework »
Ouvrons le build.gradle contenu dans le sous-projet « myframework ». Ce fichier indique à Konan sur quoi et comment il devra gérer la compilation.
En particulier, via la directive apply plugin, nous allons définir le plugin à utiliser dans notre contexte, c’est-à-dire ‘konan’, qui est bien évidemment le plugin utilisé pour s’interfacer facilement avec le compilateur Kotlin/Native.
En outre, nous allons instruire notre script à propos de ses repositories: c’est-à-dire, maven, et ses dependencies, le kotlin-native-gradle-plugin.
// Le plugin ‘konan’ crée une interface entre Gradle et le compilateur Kotlin/Native. apply plugin: 'konan' buildscript { repositories { maven { url “https://dl.bintray.com/jetbrains/kotlin-native-dependencies” } } dependencies { classpath “org.jetbrains.kotlin:kotlin-native-gradle-plugin:$konan_version” } }
Enfin, nous ajouterons au même fichier build.gradle les directives pour la création du framework iOS.
Nous allons cibler l’iPhone et l’iPhone Simulator, qui se basent sur deux architectures différentes, à savoir ARM pour iPhone et x86 pour le simulateur. Nous définissons également, dans les paramètres du framework, le nom du fichier de sortie de notre task : ‘MyKotlinFramework’. Nous précisons également quel dossier contient notre code source, dans notre cas src/main/kotlin. Pour terminer, nous pouvons penser à activer le mode de débogage, via la ligne enableDebug true.
// The binaries that will be produced by konan konanArtifacts { framework('MyKotlinFramework', targets: ['iphone', 'iphone_sim']) { srcDir 'src/main/kotlin' enableDebug true } }
Ajouter du code source
Il est maintenant temps d’ajouter du code Kotlin.
class Foo() { fun bar() = “bar” }
Comme vous le comprendrez clairement, ce code ne fait pas grand-chose, mais c’est tout dont nous avons besoin afin d’essayer les fonctionnalités de base de Kotlin/Native.
Compilation
Et c’est à peu près tout. Nous avons juste besoin de compiler notre projet en cours d’exécution.
Avant cela, nous pouvons nous concentrer brièvement sur le résultats de la commande
./gradlew tasks
Cela imprime à l’écran un certain nombre de tâches préconfigurées par Gradle. Parmi elles, les tasks compileKonan, compileKonanMyKotlinFrameworkIphone, compileKonanMyKotlinFrameworkIphone_sim sont générées par le plugin konan appliqué dans le fichier build.gradle : comme les noms le disent, elles vont compiler le code Kotlin et produire des frameworks pour iPhone et iPhone Simulator.
Nous pouvons maintenant exécuter
./gradlew compileKonan
et attendre que le projet compile. Veuillez noter que Gradle se charge également de télécharger automatiquement le compilateur Kotlin/Native pour nous, même si cela peut prendre un certain temps.
Lorsque la compilation est terminée, vérifiez le contenu du dossier myframework/build/konan/bin/iphone_sim. Il devra contenir trois fichiers :
- MyKotlinFramework.framework
- MyKotlinFramework.framework.dSYM
- MyKotlinFramework.kt.bc
Quels sont ces trois fichiers?
Le premier est, bien sûr, le framework que nous venons de produire. Le second fichier, avec l’extension dSYM, contient les informations nécessaires pour déboguer notre framework avec un débogueur lldb, tel que celui fourni par Xcode. Enfin, le fichier .kt.bc est le fichier bitcode de notre programme. En d’autres termes, c’est la forme binaire de la Représentation Intermédiaire LLVM de notre code.
Intégration dans un projet iOS
Pour utiliser le framework à l’intérieur d’une application iOS, ajoutons-le à la section « Embedded Binaries » de notre cible.
Ensuite, dans notre code Swift, nous aurons juste besoin d’importer la bibliothèque et d’utiliser la méthode bar() de notre classe Foo. Veuillez également noter que Konan préfixe toutes vos classes avec le trigramme de votre nom de sortie de framework. Dans notre cas, MyKotlinFramework. Ici, la classe Foo deviendra visible dans Objective-C et Swift sous le nom MKFFoo.
import MyKotlinFramework // ... func something() { let bar = MKFFoo().bar() print(bar) }
Le code complet de ce tutoriel est disponible sur notre page GitHub.
Que faire ensuite ?
Inutile de dire que ce que nous avons vu aujourd’hui n’est que le début. Grâce à Kotlin/Native 0.6, il est maintenant facile de partager du code entre iOS et Android, en utilisant la fonctionnalité Multiplatform. Cela permettra une réutilisation plus efficace de votre logique métier entre vos applications mobiles, quelle que soit la plate-forme.