Mécanisme expect/actual pour les API de plateforme
Déclarez les éléments attendus dans le code commun et fournissez des implémentations actual pour chaque plateforme.
Mécanisme expect/actual pour les API de plateforme est une leçon Kotlin Academy gratuite sur CoddyKit. Ceci est la leçon 2 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Kotlin Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Kotlin Academy comprend 4 leçons au total.
Le modèle expect/actual
expect déclare un contrat d'API dans commonMain. Chaque plateforme fournit une implémentation actual. Le compilateur vérifie que toutes les cibles disposent d'une implémentation actual.
// commonMain:
expect fun platformName(): String
// androidMain:
actual fun platformName(): String = "Android ${android.os.Build.VERSION.SDK_INT}"
// iosMain:
actual fun platformName(): String = UIDevice.currentDevice.systemName()Classe expect
expect class déclare une classe avec son API dans commonMain. Chaque plateforme en fournit l'implémentation complète.
// commonMain:
expect class DateTime {
fun format(pattern: String): String
val timestamp: Long
}
// androidMain:
actual class DateTime {
actual val timestamp = System.currentTimeMillis()
actual fun format(pattern: String): String =
java.text.SimpleDateFormat(pattern).format(java.util.Date(timestamp))
}Objet expect
expect object déclare un singleton avec son contrat. Cette approche est utile pour les utilitaires propres aux plateformes, comme la journalisation, les paramètres ou l'analyse.
// commonMain:
expect object Logger {
fun debug(msg: String)
fun error(msg: String, cause: Throwable? = null)
}
// androidMain:
actual object Logger {
actual fun debug(msg: String) = android.util.Log.d("App", msg)
actual fun error(msg: String, cause: Throwable?) =
android.util.Log.e("App", msg, cause)
}expect val / fun au niveau supérieur
Les expect val et expect fun de niveau supérieur sont simples et conviennent bien aux utilitaires de plateforme sans état.
// commonMain:
expect val isDebugBuild: Boolean
expect fun generateUUID(): String
// androidMain:
actual val isDebugBuild: Boolean = BuildConfig.DEBUG
actual fun generateUUID(): String = java.util.UUID.randomUUID().toString()
// iosMain:
actual val isDebugBuild: Boolean = false // or a native flag
actual fun generateUUID(): String = NSUUID().UUIDString()expect fun avec implémentation par défaut
Depuis Kotlin 1.9+, expect fun peut avoir une implémentation par défaut via expect fun f() { }. Les plateformes peuvent la remplacer ou utiliser celle par défaut.
// commonMain (Kotlin 1.9+):
expect fun log(msg: String) {
println("[DEFAULT] $msg") // used if no actual overrides
}
// androidMain:
actual fun log(msg: String) = android.util.Log.d("KMP", msg)
// iosMain (uses default):
// no actual needed — default is usedAlias de type actual
Si une plateforme possède déjà la classe exacte dont vous avez besoin, utilisez actual typealias pour la référencer au lieu de l'encapsuler.
// commonMain:
expect class AtomicInt {
fun get(): Int
fun incrementAndGet(): Int
}
// androidMain / jvmMain:
actual typealias AtomicInt = java.util.concurrent.atomic.AtomicInteger
// iosMain:
actual class AtomicInt {
private var value = 0
actual fun get() = value
actual fun incrementAndGet() = ++value
}Interface expect (modèle indirect)
Pour plus de flexibilité, déclarez une interface dans commonMain et utilisez expect/actual uniquement pour la fabrique qui crée l'instance propre à la plateforme.
// commonMain:
interface FileStorage {
suspend fun readFile(path: String): ByteArray
suspend fun writeFile(path: String, data: ByteArray)
}
expect fun createFileStorage(): FileStorage
// androidMain:
actual fun createFileStorage(): FileStorage = AndroidFileStorage()
// iosMain:
actual fun createFileStorage(): FileStorage = IosFileStorage()Tests avec expect/actual
Dans commonTest, testez l'API commune. Les implémentations actual s'exécutent lors des tâches de test propres aux plateformes (testDebugUnitTest sur Android, iosX64Test sur iOS).
// commonTest:
import kotlin.test.Test
import kotlin.test.assertNotNull
class PlatformTest {
@Test
fun testUUID() {
val uuid = generateUUID()
assertNotNull(uuid)
println("UUID: $uuid")
}
}Pièges courants
Chaque déclaration expect doit avoir une implémentation actual dans toutes les cibles configurées (ALL), sinon la compilation échoue. Les implémentations manquantes sont détectées au moment de la compilation.
// If you add a new target (e.g., jvmMain), you must add:
// actual fun platformName(): String = "JVM"
// Otherwise:
// error: Expected function platformName has no actual declaration in module :shared for JVM
fun main() { println("Missing actuals = compile error") }Classe d'annotation expect
expect annotation class permet de faire correspondre des annotations propres aux plateformes, par exemple une annotation commune semblable à @Parcelize avec le plugin Parcelize d'Android.
// commonMain:
expect annotation class CommonParcelize()
// androidMain:
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
actual annotation class CommonParcelize
// iosMain:
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
actual annotation class CommonParcelizeCas réel : trousseau/préférences
Un cas réel typique d'expect/actual est une interface de stockage sécurisé où Android utilise EncryptedSharedPreferences et iOS le trousseau.
// commonMain:
expect class SecureStorage {
fun save(key: String, value: String)
fun get(key: String): String?
}
// androidMain:
actual class SecureStorage {
private val prefs = /* EncryptedSharedPreferences */ mapOf<String,String>()
actual fun save(key: String, value: String) { /* ... */ }
actual fun get(key: String): String? = null // simplified
}Vérification rapide
Que se passe-t-il au moment de la compilation si une déclaration expect n'a aucune implémentation actual pour une cible ?
Récapitulatif
expect déclare l'API dans commonMain. actual fournit l'implémentation de la plateforme. Utilisez actual typealias lorsque la plateforme possède déjà le type nécessaire. Les implémentations manquantes sont détectées au moment de la compilation : aucune surprise à l'exécution.
Questions Fréquemment Posées
La leçon « Mécanisme expect/actual pour les API de plateforme » est-elle gratuite ?
Oui — le texte complet de « Mécanisme expect/actual pour les API de plateforme » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Kotlin Academy, passe à CoddyKit PRO. Le cours Kotlin Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Mécanisme expect/actual pour les API de plateforme » ?
Déclarez les éléments attendus dans le code commun et fournissez des implémentations actual pour chaque plateforme. Tu pratiques Kotlin Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer Kotlin Academy ?
Aucune expérience préalable n'est requise. Kotlin Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 2 sur 4.
Combien de temps prend la leçon « Mécanisme expect/actual pour les API de plateforme » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon Kotlin Academy ?
Oui. Chaque leçon Kotlin Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Structure d’un projet KMP : commonMain, androidMain, iosMain
- Mécanisme expect/actual pour les API de plateforme
- Partager les couches de dépôt et de cas d’utilisation
- Injection de dépendances dans KMP avec Koin