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:
- Android and Desktop implementations build fine with no problem.
- However, iOS implementation doesn’t recognize RoomDatabase dependencies. Infact it doesn’t recognize any of the nonJS dependencies or files as AppDatabase.
- There is nothing difference between Android, Desktop and iOS.
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??