Kotlin Multiplatform est-il l'avenir du développement multiplateforme ? Conseils pour démarrer
Publié: 2021-01-29De nos jours, nous pouvons observer une tendance dans le développement mobile à publier des applications plus rapidement. Il y a eu de nombreuses tentatives pour réduire le temps de développement en partageant des parties de code communes entre différentes plates-formes telles qu'Android et iOS. Certaines solutions ont déjà gagné en popularité, tandis que d'autres sont encore en cours de développement. Aujourd'hui, j'aimerais discuter de l'une des approches les plus récentes du deuxième groupe - Kotlin Multiplatform Mobile (KMM en abrégé).
Qu'est-ce que Kotlin Multiplatform Mobile ?
KMM est un SDK qui vise principalement à partager la logique métier entre les plates -formes - la partie qui, dans la plupart des cas, doit de toute façon être la même. Ceci est réalisé grâce à un ensemble de plusieurs compilateurs pour un module partagé. Par exemple, la cible Android utilise une variante Kotlin/JVM, et pour iOS, il existe une variante Kotlin/Native. Un module partagé peut ensuite être ajouté aux projets d'applications natives typiques et les développeurs responsables de l'interface utilisateur peuvent se concentrer sur la fourniture de la meilleure expérience pour les utilisateurs dans un environnement qui leur est familier - Android Studio pour Android et Xcode pour iOS.
Kotlin Multiplateforme vs Flutter
Actuellement, l'une des solutions les plus populaires pour le développement d'applications multiplateformes est Flutter. Il se concentre sur la règle "écrire une application et l'exécuter partout" - qui fonctionne, mais uniquement pour les applications simples. Dans des scénarios de cas réels, les développeurs doivent souvent écrire du code natif pour chaque plate-forme de toute façon pour combler les lacunes , par exemple, lorsqu'un plugin est manquant. Avec cette approche, l'application a la même apparence sur différentes plates-formes, ce qui est parfois souhaitable, mais dans certains cas, elle peut enfreindre des directives de conception spécifiques.
Prêt à créer votre propre application ?
Choisissez FlutterBien qu'ils puissent sembler similaires, Kotlin Multiplatform n'est pas une solution multiplateforme - il n'essaie pas de réinventer la roue. Les développeurs peuvent toujours utiliser des outils qu'ils connaissent et apprécient. Cela simplifie simplement le processus de réutilisation de parties de code qui auraient dû être écrites plusieurs fois auparavant, comme faire des requêtes réseau, stocker des données et d'autres logiques métier.
Avantages et inconvénients de Kotlin Multiplateforme
Avantages de KMM :
- L'application développée est 100% native pour chaque plate -forme - elle est facile à intégrer avec le code actuellement utilisé et les bibliothèques tierces
- Facile à utiliser - presque tous les développeurs Android utilisent déjà Kotlin, il leur faut donc très peu de connaissances supplémentaires pour démarrer
- L'interface utilisateur peut être divisée pour chaque plate-forme cible - l'application se sentira cohérente avec n'importe quel écosystème donné
- La logique partagée permet aux développeurs d'ajouter de nouvelles fonctionnalités et de corriger les bogues sur les deux systèmes d'exploitation en même temps
Inconvénients de KMM :
- De nombreux composants sont encore en phase Alpha/Bêta et peuvent potentiellement être instables ou changer à l'avenir
Quelles entreprises utilisent KMM ?
Selon le site officiel, les entreprises s'intéressent de plus en plus à cette technologie et la liste ne cesse de s'allonger. Parmi eux, il y a des marques bien connues comme Autodesk, VMWare, Netflix ou Yandex.
Comment démarrer avec Kotlin Multiplatform ?
Le meilleur endroit pour plonger pour des informations détaillées est le guide officiel, mais dans cet article, je voudrais montrer un exemple assez simple, mais plus intéressant qu'un simple "Hello World", qui serait la récupération et l'affichage d'applications la dernière bande dessinée de Randall Munroe (sous licence CC BY-NC 2.5) avec son titre de l'API xkcd.com.
Fonctionnalités à couvrir :
- Configuration du projet
- Mise en réseau dans le module partagé
- Interface utilisateur simple pour Android et iOS
Remarque : je voulais que cet exemple soit aussi facile à lire pour les développeurs Android et iOS, donc à certains endroits, j'ai intentionnellement omis certaines bonnes pratiques spécifiques à la plate-forme juste pour clarifier ce qui se passe
Configuration du projet
Tout d'abord, assurez-vous que les dernières versions d'Android Studio et de Xcode sont installées car les deux seront nécessaires pour la construction de ce projet. Ensuite, dans Android Studio, installez le plugin KMM. Ce plugin simplifie beaucoup de choses - pour créer un nouveau projet, cliquez simplement sur Créer un nouveau projet et sélectionnez Application KMM.
Une fois le projet créé, accédez au fichier build.gradle.kts
dans le répertoire partagé . Ici, vous devez spécifier toutes les dépendances requises. Dans cet exemple, nous utiliserons ktor pour la couche réseau, kotlinx.serialization
pour analyser les réponses json du backend et les coroutines kotlin pour tout faire de manière asynchrone.
Pour plus de simplicité, je fournis ci-dessous des listes montrant toutes les dépendances qui doivent être ajoutées à celles déjà présentes. Lorsque vous ajoutez des dépendances, synchronisez simplement le projet (une invite apparaîtra). Tout d'abord, ajoutez le plugin de sérialisation à la section plugins.
plugins { kotlin("plugin.sérialisation") version "1.4.0" }
Ajoutez ensuite les dépendances.
ensembles de sources { val commonMain en obtenant { dépendances { implémentation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.0") implémentation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9-native-mt-2") implémentation("io.ktor:ktor-client-core:1.4.1") implémentation("io.ktor:ktor-client-json:1.4.1") implémentation("io.ktor:ktor-client-serialization:1.4.1") } } val androidMain en obtenant { dépendances { implémentation("io.ktor:ktor-client-android:1.4.1") } } val iosMain en obtenant { dépendances { implémentation("io.ktor:ktor-client-ios:1.4.1") } } }
Il convient de mentionner qu'au moment de la rédaction de cet article, il y a quelques problèmes avec la version stable de la bibliothèque de coroutines sur iOS - c'est pourquoi la version utilisée a le suffixe native-mt-2 (qui signifie multithreading natif). Vous pouvez vérifier l'état actuel de ce problème ici.
Mise en réseau dans le module partagé
Tout d'abord, nous avons besoin d'une classe représentant la réponse - ces champs sont présents dans json renvoyé par le backend.
importer kotlinx.serialization.Serializable @Serializable classe de données XkcdResponse( val img : chaîne, titre de la valeur : Chaîne, val jour : Int, val mois : Int, val année : Int, )
Ensuite, nous devons créer une classe représentant l'API avec un client HTTP . Si nous n'avons pas fourni tous les champs présents dans json, nous pouvons utiliser la propriété ignoreUnknownKeys
afin que le sérialiseur puisse ignorer ceux qui manquent. Cet exemple a un seul point de terminaison représenté par une fonction suspendue. Ce modificateur indique au compilateur que cette fonction est asynchrone. Je vais le décrire plus en détail avec un code spécifique à la plate-forme.
importer io.ktor.client.* importer io.ktor.client.features.json.* importer io.ktor.client.features.json.serializer.* importer io.ktor.client.request.* classe XkcdApi { private val baseUrl = "https://xkcd.com" valeur privée httpClient = HttpClient() { install(JsonFeature) { sérialiseur = KotlinxSerializer( kotlinx.serialization.json.Json { ignoreUnknownKeys = vrai } ) } } suspendre fun fetchLatestComic() = httpClient.get<XkcdResponse>("$baseUrl/info.0.json") }
Lorsque notre couche réseau est prête, nous pouvons passer à la couche domaine et créer une classe représentant le modèle local de données. Dans cet exemple, j'ai sauté quelques champs supplémentaires et laissé juste le titre de la bande dessinée et l'URL de l'image.
classe de données ComicModel( val imageUrl : chaîne, titre de la valeur : Chaîne )
La dernière partie de cette couche consiste à créer un cas d'utilisation qui déclenchera une requête réseau, puis mappera la réponse au modèle local.

classe GetLatestComicUseCase (valeur privée xkcdApi : XkcdApi) { suspendre fun run() = xkcdApi.fetchLatestComic() .let { ComicModel(it.img, it.title) } }
Interface utilisateur simple pour Android
Il est temps de passer au répertoire androidApp
- c'est là que l'application Android native est stockée. Tout d'abord, nous devons ajouter des dépendances spécifiques à Android à l'autre fichier build.gradle.kts
situé ici. Encore une fois, la liste ci-dessous ne montre que les dépendances qui doivent être ajoutées à celles déjà présentes. Cette application va utiliser l'architecture Model-View-ViewModel (les deux premières lignes) et Glide pour charger une image comique à partir de l'URL renvoyée (les deux secondes lignes)
dépendances { implémentation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0") implémentation("androidx.lifecycle:lifecycle-livedata-ktx:2.2.0") implémentation("com.github.bumptech.glide:glide:4.11.0") annotationProcessor("com.github.bumptech.glide:compiler:4.11.0") }
Par défaut, un projet nouvellement créé doit contenir MainActivity et son fichier de mise en page activity_main.xml
. Ajoutons-y quelques vues - une TextView
pour le titre et une ImageView pour la bande dessinée elle-même.
<?xml version="1.0" encoding="utf-8" ?> <LinearLayout xmlns:andro Android: Android : layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" Android :orientation="vertical"> <TextView Android: Android : layout_width="wrap_content" android:layout_height="wrap_content"/> <ImageView Android: Android : layout_width="match_parent" Android : layout_height="wrap_content"/> </LinearLayout>
Ensuite, nous aurons besoin d'une représentation de l'état de l'application - il peut s'agir de charger une nouvelle bande dessinée, de l'afficher ou de rencontrer une erreur lors du chargement.
État de classe scellé { objet Chargement : State() class Success(résultat val: ComicModel) : State() Erreur d'objet : État() }
Ajoutons maintenant un ViewModel minimal en utilisant la logique métier créée précédemment . Toutes les classes peuvent être importées. MutableLiveData
est un champ observable - la vue observera les changements et se mettra à jour en conséquence. viewModelScope
est une portée coroutine liée au cycle de vie du modèle de vue - si l'application est fermée, elle annulera automatiquement les tâches en attente.
class MainViewModel : ViewModel() { valeur privée getLatestComicUseCase = GetLatestComicUseCase(XkcdApi()) val comic = MutableLiveData<State<ComicModel>>() amusant chercherComic () { viewModelScope.launch { comic.value = État.Chargement() runCatching { getLatestComicUseCase.run() } .onSuccess { comic.value = State.Success(it) } .onFailure { comic.value = State.Error() } } } }
Une dernière chose - MainActivity pour tout câbler.
classe MainActivity : AppCompatActivity(R.layout.activity_main) { private val viewModel : MainViewModel par paresseux { ViewModelProvider(this).get(MainViewModel::class.java) } override fun onCreate(savedInstanceState: Bundle ?) { super.onCreate(savedInstanceState) viewModel.comic.observe(this) { quand cela) { est State.Loading -> { findViewById<TextView>(R.id.titleLabel).text = "Chargement" } est State.Success -> { findViewById<TextView>(R.id.titleLabel).text = it.result.title Glisser.avec(ceci) .load(it.result.img) .into(findViewById(R.id.image)) } est État. Erreur -> { findViewById<TextView>(R.id.titleLabel).text = "Erreur" } } } viewModel.fetchComic() } }
Ça y est, l'application Android est prête !
Interface utilisateur simple pour iOS
Tout ce qui précède a été fait dans Android Studio, donc pour cette partie, passons à Xcode pour le rendre plus pratique. Pour ce faire, ouvrez simplement Xcode et sélectionnez le répertoire iosApp - il contient un projet Xcode préconfiguré. Par défaut, ce projet utilise SwiftUI pour l'interface graphique, alors restons-y pour des raisons de simplicité.
La première chose à faire est de créer une logique de base pour récupérer les données comiques. Tout comme avant, nous avons besoin de quelque chose pour représenter l'état.
énumérer État { chargement de cas cas de réussite (ComicModel) erreur de cas }
Ensuite, préparons à nouveau un ViewModel
classe ViewModel : ObservableObject { laissez getLatesteComicUseCase = GetLatestComicUseCase(xkcdApi: XkcdApi()) @Published var comic = State.loading init() { self.comic = .chargement getLatestComicUseCase.run { récupéréComic, erreur dans si récupéréComic != nil { self.comic = .success(fetchedComic!) } autre { self.comic = .error } } } }
Et enfin la vue.
Remarque : pour plus de simplicité, j'ai utilisé le composant SwiftUI RemoteImage pour afficher l'image, tout comme j'ai utilisé Glide sur Android.
structure ContentView : Afficher { @ObservedObject private(set) var viewModel : ViewModel corps de var : quelques vues { comicView() } -- fonction privée comicView () -> une vue { basculer viewModel.comic { cas .chargement : return AnyView(Text("Chargement")) case .result(let comic): retourner AnyView(VStack { Texte (bande dessinée.titre) RemoteImage (url : bande dessinée.img) }) cas .erreur : renvoie AnyView(Text("Erreur")) } } }
Et ça y est, l'application iOS est également prête !
Sommaire
Enfin, pour répondre à la question du titre – Kotlin Multiplatform est-il l'avenir du développement multiplateforme ? – tout dépend des besoins. Si vous souhaitez créer une petite application identique pour les deux plates-formes mobiles en même temps, alors probablement pas, car vous devez avoir les connaissances requises en matière de développement pour les deux plates-formes.
Développez votre prochaine application avec nos experts
Obtenir un devisCependant, si vous avez déjà une équipe de développeurs Android et iOS et que vous souhaitez offrir la meilleure expérience utilisateur, cela peut réduire considérablement le temps de développement . Comme dans l'exemple fourni, grâce à un module partagé, la logique d'application n'a été implémentée qu'une seule fois et l'interface utilisateur a été créée de manière entièrement spécifique à la plate-forme. Alors pourquoi ne pas essayer ? Comme vous pouvez le voir, il est facile de commencer.
Vous êtes curieux d'en savoir plus sur le développement multiplateforme d'un point de vue commercial ? Consultez notre article sur les avantages du développement multiplateforme.