Kotlin Multiplatform Mobile: expect-actual Concept
Overview
When developing a multiplatform app, there will be a specific case that needs the advantage of native features by each platform, and KMM handles this by providing us expect-actual
that works with function, class, etc.
Basics
expect-actual
is quite self-explained, expect
is what KMM expects about it (abstraction) and actual
is what you actually do for it (implementation).
just imagine an interface/protocol
interface TellmeTheName {
fun doName(): String
}class MyAndroidApp: TellmeTheName {
override fun doName(): String = "Android"
}class MyiOSApp: TellmeTheName {
override fun doName(): String = "iOS"
}
Then convert to expect-actual
:
expect fun doName(): Stringactual fun doName(): String = "Android"actual fun doName(): String = "iOS"
then when we want to create some function or classes with specific implementations in each platform, inside someProject/shared/commonMain/SomeFile.kt
we added expect
like this:
expect fun formatDate(dateString: String, format: String): String
☝🏽 adding
expect
tocommonMain
means that you have to write theactual
in every supported platform, in this case, is android and iOS.
Android Implementation
So after making an expect
function, the IDE will start to complain to add the actual
, so this time we add android implementation inside someProject/shared/androidMain/SomeFile.kt
like this:
import java.text.SimpleDateFormat
import java.util.*actual fun formatDate(dateString: String, format: String): String {
val date = if (dateString.isNotEmpty()) SimpleDateFormat(Constants.normalDateFormat).parse(dateString) else Date()
val dateFormatter = SimpleDateFormat(format, Locale.getDefault())
return dateFormatter.format(date ?: Date())
}
iOS Implementation
Android’s done, but IDE still complaining us to add the actual
, for sure we need to add iOS implementation inside someProject/shared/iosMain/SomeFile.kt
like this:
import platform.Foundation.* // yes you can use classic swift's Foundation in KMMactual fun formatDate(dateString: String, format: String): String {
val dateFormatter = NSDateFormatter().apply {
dateFormat = Constants.normalDateFormat
} val formatter = NSDateFormatter().apply {
dateFormat = format
locale = NSLocale(localeIdentifier = "id_ID")
} return formatter.stringFromDate(dateFormatter.dateFromString(dateString) ?: NSDate())
}
💡 You’ll notice that
actual
insomeplatformMain
have to be in the same path asexpect
insidecommonMain
.
So basically, just imagine expect
is some kind of interface, and the actual
is where the implementation of the interface is come, and finally in both platform you can use formatDate(dateString: String, format: String): String
and it will do exactly what you tell them to do inside their main in KMM
Closing
Hopefully by understanding the concept of expect-actual
, we can grow our KMM codebase to be limitless for any specific implementation.