I am building a KMP project that supports Android, iOS, desktop(jvm) and Web(wasmJs)... Within, I am implementing Room for database storage.
Since WasmJS doesn't support Room, I created a new source set for Android, iOS and Desktop and called it nonJS
Here is my gradle:
kotlin {
@OptIn(ExperimentalWasmDsl::class)
wasmJs {
moduleName = "data"
browser {
commonWebpackConfig {
outputFileName = "composeApp.js"
devServer = (devServer ?: KotlinWebpackConfig.DevServer()).apply {
static = (static ?: mutableListOf()).apply {
// Serve sources to debug inside browser
add(project.projectDir.path)
}
}
}
}
binaries.executable()
}
androidTarget {
@OptIn(ExperimentalKotlinGradlePluginApi::class)
compilerOptions {
jvmTarget.set(JvmTarget.JVM_17)
}
}
listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
).forEach {
it.binaries.framework {
baseName = "data"
isStatic = true
}
}
jvm("desktop")
@OptIn(ExperimentalKotlinGradlePluginApi::class)
applyDefaultHierarchyTemplate {
// create a new group that
// depends on `common`
common {
// Define group name without
// `Main` as suffix
group("nonJs") {
// Provide which targets would
// be part of this group
withAndroidTarget()
withIos()
withJvm()
}
}
}
sourceSets {
all{
languageSettings {
@OptIn(ExperimentalKotlinGradlePluginApi::class)
compilerOptions{
freeCompilerArgs.add("-Xexpect-actual-classes")
}
}
}
commonMain.dependencies {
api(project(":domain"))
implementation(libs.ktor.client.logging)
implementation(libs.ktor.client.content.negotiation)
}
val nonJsMain by getting {
dependencies {
api(libs.room.runtime)
implementation(libs.sqlite.bundled)
}
}
androidMain.dependencies {
implementation(libs.ktor.client.android)
implementation(libs.ktor.client.okhttp)
implementation(libs.paging.room)
}
iosMain.dependencies {
implementation(libs.ktor.client.darwin)
}
val desktopMain by getting {
dependencies {
implementation(libs.ktor.client.okhttp)
}
}
wasmJsMain.dependencies {
implementation(libs.ktor.client.js)
}
}
task("testClasses")
}
Then I Created an expected Database Builder for these platforms in the nonJS folder.
DatabaseBuilder.kt
expect class DatabaseBuilder() {
fun databaseBuilder(): RoomDatabase.Builder<AppDatabase>
}
Then I started implementing the actual files
example DatabaseBuilder.jvm.kt
actual class DatabaseBuilder {
actual fun databaseBuilder(): RoomDatabase.Builder<AppDatabase> {
val dbFile = File(System.getProperty("java.io.tmpdir"), "movies_database.db")
return Room.databaseBuilder<AppDatabase>(
name = dbFile.absolutePath,
)
}
}
Also DatabaseBuilder.iOS.kt
actual class DatabaseBuilder {
actual fun databaseBuilder(): RoomDatabase.Builder<AppDatabase> {
val dbFilePath = NSHomeDirectory() + "/movies_database.db"
return Room.databaseBuilder<AppDatabase>(
name = dbFilePath,
factory = { AppDatabase::class.instantiateImpl() }
)
}
}
Now the problem is:
I think there is something wrong with my nonJS declaration block
@OptIn(ExperimentalKotlinGradlePluginApi::class)
applyDefaultHierarchyTemplate {
// create a new group that
// depends on `common`
common {
// Define group name without
// `Main` as suffix
group("nonJs") {
// Provide which targets would
// be part of this group
withAndroidTarget()
withIos()
withJvm()
}
}
}
Any help with that?? OR Is there a better approach to my project??
I found out what was wrong... As expected the issue was in my Hierarchy
Wrong Hierarchy:
@OptIn(ExperimentalKotlinGradlePluginApi::class)
applyDefaultHierarchyTemplate {
common {
group("nonJs") {
withAndroidTarget()
withIos()
withJvm()
}
}
}
As you can see iOSMain target doesn't exist... Instead, iOS is separated into its main components IosArm64 and IosX64... That is why my iOS classes in my iOSMain folder couldn't resolve any dependencies.
Correct Hierarchy:
@OptIn(ExperimentalKotlinGradlePluginApi::class)
applyDefaultHierarchyTemplate {
common {
group("nonJs") {
withAndroidTarget()
withJvm()
group("ios") {
withIos()
}
}
}
}
As you can see... Here, Ios is created a stand alone group within nonJs... IosArm64 and IosX64 are added within the "iOSMain" after that. This way my iOS classes in my iOSMain folder could resolve dependencies.