Theodo France

Theodo France

IT / Digital, Logiciels

Paris, Casablanca, London, Lyon, Nantes

Explorez leurs posts

Parcourez les posts publiés par l’entreprise pour une immersion dans leur culture et leurs domaines d’expertise.

Theodo Named 2025 Google Cloud Services Partner of the Year

Las Vegas, April 8, 2025 Theodo today announced that it has received the 2025 Google Cloud Services Partner of the Year. Theodo is being recognized for its achievements in the Goog…

04/07/2025

REX après la migration d’une feature Android/iOS vers KMP

Dans un premier article, nous avons exploré comment migrer progressivement une application native Android/iOS vers Kotlin Multiplatform (KMP). Si vous avez suivi ce guide, vous ave…

04/07/2025

ShedLock : Gérer efficacement les tâches planifiées dans une architecture multi-instances

Introduction Pour les applications d'entreprise, en 2025 l’exécution de tâches planifiées est un besoin courant : génération de rapports, traitements par lots, synchronisation de d…

04/07/2025

Comment diviser par 2 votre temps de CI grâce à ces simples astuces

Chez Theodo HealthTech, notre politique est de créer un code de qualité tout en respectant nos délais de livraison. Cependant, pendant trois sprints consécutifs, nous avons livré d…

08/04/2025

How QRQC helps me better manage bugs on my project?

As a software developer, you spend most of your time delivering code and then fixing bugs you introduced in your code. The Pareto principle is a great way to represent our day-to-d…

04/07/2025

How we migrated from AWS Glue to Snowflake and dbt

Today, I’ll tell you about our ETL migration from AWS Glue to the Snowflake and dbt modern data stack. My team’s mission is to centralize and ensure data reliability from multiple…

04/07/2025

Sécuriser les partages Notion : guide pour tous

Chez Theodo Fintech, nous avons fait de Notion notre QG digital. Documentation produit, projets tech, comptes rendus, référentiels clients ou financiers… tout y passe. Et c’est bie…

04/07/2025

Construire un produit Gen AI : le guide de survie pour les PMs

Bienvenue dans l'ère de l'IA générative, où les machines créent du contenu de manière autonome. Pour les product managers (PMs), cela représente une révolution autant qu'un défi. L…

08/04/2025

Qu’est-ce que le scaling ?

Une bonne application est une application qui tient sa charge d’utilisateurs, notamment grâce à un scaling controlé. Dans cet article nous aborderons ce sujet, et plus particulière…

04/07/2025

How LLM Monitoring builds the future of GenAI ?

Discover how Langfuse offers secure, open-source monitoring for LLM and GenAI solutions. Large Language Models (LLMs) are popping up everywhere and are more accessible than ever. W…

04/07/2025

Les annotations java custom pour respecter l’architecture hexagonale

Le problème que l’on veut résoudre Lorsque l’on développe une API avec Spring Boot, il est fréquent d’utiliser les annotations fournies par le framework, telles que @Service, @Comp…

04/07/2025

Le kit de survie du Product Manager responsable en 4 étapes

Alors que j’étais tranquillement en train de me laisser charmer par la dégustation gratuite de tofu fumé de mon Biocoop l’année dernière, une soudaine prise de conscience a heurté…

08/04/2025

Faites des Plugins pas la Guerre: REX sur ma bataille pour écrire un plugin

Imaginez commencer chaque projet avec tous les outils configurés et prêts à l’emploi. Le rêve, non ? En tant que développeur Android, j’ai toujours eu à portée de main les outils n…

04/07/2025

Don’t use Langchain anymore : Atomic Agents is the new paradigm !

Introduction Since the rise of LLMs, numerous libraries have emerged to simplify their integration into applications. Among them, LangChain quickly established itself as the go-to…

04/07/2025

Optimize Your Google Cloud Platform Costs with Physical Bytes Storage Billing

In today's data-driven world, cloud providers are essential for efficiently managing, processing, and analyzing vast amounts of data. When choosing one such provider, Google Cloud…

08/04/2025

Tech Radar Cloud

Ce Tech radar regroupe une cinquantaine de technologies Cloud et DevOps éprouvées par les experts de Theodo Cloud durant plus de 4 ans de projets. Téléchargez le 2ème volume de not…

08/04/2025

REX après la migration d’une feature Android/iOS vers KMP

Theodo France

REX après la migration d’une feature Android/iOS vers KMP

Dans un premier article, nous avons exploré comment migrer progressivement une application native Android/iOS vers Kotlin Multiplatform (KMP). Si vous avez suivi ce guide, vous avez probablement une base de code KMP fonctionnelle… et une liste de problèmes que vous avez rencontrés !

Effectivement des problèmes j’en ai rencontré en suivant ce guide pour la migration d’une feature. Maintenant, je vous fais mon retour d’expérience pour vous préparer aux difficultés. Car oui, malgré ses promesses, une migration vers KMP n’est pas toujours un long fleuve tranquille. Certains types standards ne sont pas supportés, des frameworks courants deviennent incompatibles et certaines intégrations nécessitent des ajustements parfois contre-intuitifs.

Nous verrons ensemble les pièges liés aux types, aux systèmes réactifs, aux ressources et même aux cycles de vie des objets. Mais rassurez-vous : tout n’est pas compliqué et certaines migrations sont étonnamment simples. Alors, prêt à affronter les dernières étapes de votre transition vers KMP ?

Points difficiles

Interopérabilité Kotlin-Swift

Capture d’écran 2025-07-04 à 10.44.39.png

Suite à un choix historique en 2018 et afin d’être compatible avec le maximum de projets, Kotlin n’est pas interopérable directement avec Swift, mais avec Objective-C. Ce qui nous apporte quelques limitations que vous pourrez retrouver à cette adresse : https://github.com/kotlin-hands-on/kotlin-swift-interopedia. Heureusement, l’interopérabilité fonctionne normalement pour les choses simples, et pour certains autres éléments plus complexe, SKIE vous permettra d’améliorer l’interop. Il sera utilise par exemple pour mieux traduire en swift les enums, les sealed classes, les Flows et bien d’autres.

Types Java et Android manquant

Certains types pourtant simples et régulièrement utilisés en Kotlin/Android ne sont pas disponibles en KMP, il vous faudra donc trouver des équivalents :

  • java.util.UUID : arrivé en version expérimentale des uuid en 2.0.20 pour Kotlin, vous devrez quand même changer de type

  • java.util.SortedSet: utilisez des set et triez-les à la demande

  • java.net.URL : pour les URI vous trouverez des solutions dans les librairies de la communauté comme celle-ci.

Si vous rencontrez d'autres soucis concernant les types, vous pourrez bien souvent utiliser le type Android et créer un équivalent pour iOS. Par exemple, pour les Bundle, vous pouvez utiliser une Map sur iOS et sur android il vous suffit d'utiliser la vraie implementation des bundles:

Capture d’écran 2025-07-04 à 10.45.11.png

Rx / LiveData

Capture d’écran 2025-07-04 à 10.45.28.png

Si vous utilisez Rx, LiveData permettant à votre application d’être réactive aux changements, sachez que cela ne sera pas disponible en multiplateforme. Pour pallier cela, migrez vers les coroutines et/ou Kotlin Flow couche par couche dans vos features en utilisant un adaptateur pour communiquer avec les couches qui utilisent encore l’ancien système. En soi, ce n’est pas vraiment difficile, juste un peu long. Par contre, si votre couche présentation chaîne les observables de manière complexe, il se peut que la migration souffre de cette complexité.

Pour moi ce qui est le plus difficile sur ce sujet, c'est que les test unitaires ne sont pas les mêmes entre un test Rx et un test de coroutine. Mais il est tout de même important de s'attarder sur les tests, ils sont le meilleur garant pour vous éviter les régressions.

Migration du design system

  • Les polices de caractères ne se chargent pas exactement de la même manière en Compose Android et Compose Multiplatform. Vous aurez peut-être quelques ajustements à faire selon la manière dont vous les utilisez sur votre projet. D'ailleurs attention, en multimodules, il faudra bien configurer vos ressources pour avoir accès à vos Fonts.

  • Lottie n'est pas multiplateforme, mais il existe Kottie et Compottie pour utiliser vos animations JSON en CMP (Compose multiplatform).

  • Si vous utilisez plutôt Rive pour vos animations, à ma connaissance il n’existe pas de version multi-platforme, à vous donc d’adapter les versions des différents runtimes. rive-cpp fonctionne avec Skia, à voir à quel point il faut l’adapter pour du CMP.

  • Pour les images distantes, il est probable que la solution que vous aviez ne soit pas compatible avec KMP. Vous pouvez donc choisir de migrer vers Coil, ce qui sera d'autant plus simple si vous utilisiez Landscapist.

Les ressources

Les ressources avec Compose peuvent être utilisées sur iOS uniquement avec l'intégration locale et pas via un .xcframework.

Par ailleurs, pour un projet multi-module, il ne faut pas oublier de spécifier la génération des ressources dans l'umbrella module pour iOS :

Capture d’écran 2025-07-04 à 10.45.50.png

Pour les polices de caractères, il y a une règle supplémentaire pour les utiliser: il faut qu'elles soient dans le module top-level et il faut les injecter dans les autres modules. Voir YouTrack CMP-4111.

Il y a encore des éléments que je n'ai pas bien saisis à ce sujet. J'ai eu des versions de mon code qui fonctionnaient avec des polices chargées dans un submodule et puis plus tard non. Il y a peut-être une histoire de cache qui joue. J'investiguerai ce point plus tard, faites-moi savoir si vous avez des infos.

Migration des vues

Le souci majeur est l'absence de previews en Compose Multiplatform sur la partie commune. La solution que j'ai choisie est de déplacer toutes mes vues dans le module commun en laissant les previews dans le code de l'app Android. J'ai choisi cette solution, car cela m'évitait également d'avoir à déplacer mes tests snapshots de non-régression paparazzi.Il est possible de visualiser vos previews Compose Multiplatform de la partie commune avec l'IDE Fleet. Malheureusement, je n'ai pas réussi à faire en sorte que fleet fonctionne sur mon projet complexe. Par ailleurs, Fleet a été abandonné par JetBrains. On croise les doigts pour que cette fonctionnalité arrive bientôt sur Android Studio.

Migration de la navigation

Selon la solution de navigation que vous aviez sur Android, la migration de cette couche peut être complètement différente.Pour ma part, c'était de la navigation entre fragments, j'ai choisi de migrer vers une navigation compose, mais il existe peut-être des solutions plus proches de la navigation android.

Intégration dans un projet Tuist

Capture d’écran 2025-07-04 à 10.46.16.png

Dans un projet iOS géré par Tuist, j'ai eu des soucis pour que Xcode reconnaisse les dépendances de mon module KMP. Il faut intégrer le .framework généré par Kotlin dans la déclaration des dépendances de Tuist.

Attention, Kotlin génère par défaut un .framework et non un .xcframework, ce qui veut dire que le .framework n'est compatible que pour une architecture. L'intégration n'est donc pas des plus simples. Le mieux à faire est sûrement de compléter la tâche Gradle de génération du .framework avec une modification des dépendances de Tuist et un tuist generate. Je suis preneur de toute solution plus simple.

Sinon il y a toujours la solution de la communauté pour générer les .xcframework . Cela prend évidemment plus de temps que de builder un .framework pour une seule architecture.

Peut-être qu’une solution serait d’utiliser le .framework en debug et le .xcframework en release.

Par ailleurs, dans un projet Tuist, si vous utilisez l'intégration directe, il faudra ajouter la configuration à Tuist car sinon, la commande tuist generate va vous l'écraser

Intégration du projet KMP dans un projet iOS en archi micro-features

Au début, j'avais besoin de builder l'app deux fois pour voir mes changements dans le code commun apparaître dans mon app iOS. C'était parce que j'avais ajouté la dépendance KMP au projet de l'app plutôt que de l'ajouter aux sous-projets qui utilisaient réellement la dépendance KMP.

Les cycles de vie

Souvent, sur Android, vos objets ont un cycle de vie bien précis, ils sont liés à une activité ou un fragment. Quand vous allez migrer vos écrans sur iOS avec Compose puis la navigation également, il faudra redéfinir la durée de vie de vos objets. Vous aurez probablement quelques petites régressions à ce sujet. Par exemple, le focus d'un champ de texte qui n'est pas réinitialisé lorsqu'on revient sur l'écran. Pour vous aider à gérer les cycles de vie les plus simple, je pense que l’on peut se débrouiller avec les scopes de Koin.Attention, si vous voulez bind le cycle de vie de votre viewModel Kotlin avec votre vue SwiftUI, vous allez avoir du travail. Vous pouvez aller voir le travail de François qui s'est attelé à cette tâche.

Le maintien d'un état commun entre votre app iOS et sa partie KMP

Capture d’écran 2025-07-04 à 10.47.47.png

Par exemple, le token d'authentification. Pour ma part, il est récupéré par la partie native iOS, mais je veux m'en servir dans des appels en KMP. Pour cela, j'ai créé une classe qui s'occupe de la gestion de ce token, elle est accessible depuis la partie KMP et la partie iOS. Cela me permet d'utiliser le token généré par iOS dans mes appels réseaux KMP.Plus globalement, il faudra créer des composants qui passent d'une plateforme à l'autre quand vous voulez partager ces infos.Une astuce est d'utiliser votre framework d'injection de dépendances pour créer des composants dont votre code commun se sert et qui sont implémentés par les plateformes.

Facilités

Retrofit vers KtorFit

Retrofit n'est pas compatible KMP et n'a pas prévu de l'être, pas de panique, KtorFit l'est et vous pourrez très simplement migrer vos appels réseaux.

Room

Si vous utilisiez Room sur Android, vous pouvez facilement migrer vers Room KMP à l’aide de la documentation : migration vers Room KMP et de l’exemple Fruitties. Par ailleurs, Room est enfin stable sur KMP !

Coroutines et Kotlin Flow

Si vous utilisez déjà les coroutines et Kotlin Flow sur Android, cela vous simplifiera la migration de nombreuses parties du code. Sinon faites cette migration au préalable. Regardez la partie Rx/Livedata plus haut.

Conseils

Il est plus facile d’ajouter une nouvelle feature en KMP sur les deux plateformes que de migrer une feature existante en KMP.Donc si vous en avez l'occasion, testez une nouvelle feature en KMP pour confirmer que KMP convient à votre équipe avant d'entamer une migration. L'engagement sera bien moindre et vous aurez déjà une bonne idée de ce que cela implique pour votre projet.

Avoir déjà des tests unitaires en place fait partie des points nécessaires pour faire un refactoring correct. Cela permettra de faire votre migration progressive plus rapidement et surtout qu'elle soit plus robuste.

Quand vous passez une classe du package Android vers le module commun, gardez le même nom de package pour vous éviter d'avoir à retoucher toutes les classes qui l’utilisent.

Passez par des interfaces quand cela vous facilite le refactoring.

Migrer, c’est refactorer. Apprenez à dompter les outils de refacto de votre IDE, sinon vous allez en baver. Une bonne maitrise vous permettra de limiter les régressions et améliorer votre vitesse de refactoring.

Conclusion

Migrer une application native vers Kotlin Multiplatform n’est pas un exercice anodin, mais ce n’est pas non plus une montagne infranchissable. Avec une approche progressive et une bonne préparation, vous pouvez transformer une migration en une opportunité d’améliorer votre base de code, de simplifier vos architectures et d’harmoniser vos pratiques entre plateformes.

Le principal enseignement de cette transition, c’est qu’il n’existe pas de recette universelle : chaque projet à ses spécificités et ses défis. Mais avec des tests solides, un bon usage des outils de refactoring et une stratégie de migration bien pensée, vous pouvez limiter les régressions et maximiser les bénéfices du passage à KMP.

Et si vous avez déjà migré un projet vers KMP, quelles ont été vos principales difficultés ? Faites-moi part de votre expérience, ça m’intéresse, car une migration réussie est avant tout une aventure.

Article rédigé par Dennis Bordet