Mecanismo expect/actual para APIs de plataforma
Declare declarações esperadas no código comum e forneça implementações reais por plataforma.
Mecanismo expect/actual para APIs de plataforma é uma aula grátis de Kotlin Academy no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Kotlin Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Kotlin Academy inclui 4 aulas no total.
O padrão expect/actual
expect declara um contrato de API em commonMain. Cada plataforma fornece uma implementação actual. O compilador garante que todos os destinos tenham uma implementação 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 declara uma classe com sua API em commonMain. Cada plataforma fornece a implementação completa.
// 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))
}objeto expect
expect object declara um singleton com seu contrato. É útil para utilitários específicos da plataforma, como registro em log, configurações ou análises.
// 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 no nível superior
expect val e expect fun no nível superior são simples e funcionam bem para utilitários de plataforma sem estado.
// 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 com implementação padrão
A partir do Kotlin 1.9+, expect fun pode ter uma implementação padrão por meio de expect fun f() { }. As plataformas podem substituir a implementação padrão ou usá-la.
// 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 tipo actual
Se uma plataforma já tiver exatamente a classe de que você precisa, use actual typealias para apontar para ela em vez de envolvê-la.
// 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 (padrão indireto)
Para obter mais flexibilidade, declare uma interface em commonMain e use expect/actual somente para a fábrica que cria a instância da plataforma.
// 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()Testes com expect/actual
Em commonTest, teste a API comum. As implementações actual são executadas durante as tarefas de teste específicas da plataforma (testDebugUnitTest no Android, iosX64Test no iOS).
// commonTest:
import kotlin.test.Test
import kotlin.test.assertNotNull
class PlatformTest {
@Test
fun testUUID() {
val uuid = generateUUID()
assertNotNull(uuid)
println("UUID: $uuid")
}
}Armadilhas comuns
Cada expect declarado deve ter um actual em TODOS os destinos configurados, caso contrário a compilação falha. As implementações actual ausentes são detectadas em tempo de compilação.
// 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 de anotação expect
expect annotation class permite o mapeamento de anotações específicas da plataforma — por exemplo, mapear uma anotação comum semelhante a @Parcelize para o plug-in Parcelize do 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 CommonParcelizeExemplo real: Keychain/Preferences
Um exemplo típico de expect/actual do mundo real é uma interface de armazenamento seguro em que o Android usa EncryptedSharedPreferences e o iOS usa Keychain.
// 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
}Verificação rápida
O que acontece em tempo de compilação se uma declaração expect não tiver um actual para um destino?
Recapitulação
expect declara a API em commonMain. actual fornece a implementação da plataforma. Use actual typealias quando a plataforma já tiver o tipo necessário. As implementações actual ausentes são detectadas em tempo de compilação — sem surpresas em tempo de execução.
Perguntas Frequentes
A aula “Mecanismo expect/actual para APIs de plataforma” é grátis?
Sim — o texto completo de “Mecanismo expect/actual para APIs de plataforma” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Kotlin Academy, atualize para CoddyKit PRO. O curso de Kotlin Academy inclui 4 aulas no total.
O que vou aprender em “Mecanismo expect/actual para APIs de plataforma”?
Declare declarações esperadas no código comum e forneça implementações reais por plataforma. Você pratica Kotlin Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar Kotlin Academy?
Nenhuma experiência prévia é necessária. Kotlin Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.
Quanto tempo leva a aula “Mecanismo expect/actual para APIs de plataforma”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de Kotlin Academy?
Sim. Cada aula de Kotlin Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Estrutura de projeto KMP: commonMain, androidMain, iosMain
- Mecanismo expect/actual para APIs de plataforma
- Compartilhando camadas de repositório e casos de uso
- Injeção de dependências em KMP com Koin