实际/预期类在 Kotlin Mutliplatform 项目中不起作用

发布于 2025-01-09 12:25:38 字数 5723 浏览 2 评论 0原文

我正在开发一个 KMM 应用程序,我尝试分别使用 SQLDelight 和 Ktor 实现常规的 localDatasource 和 RemoteDatasource。

当我尝试将 AndroidApp 和 iosMain 的本机代码共享到 commonModule 时,我的问题就出现了。我开始在我的 commonModule Expect 类中出现以下错误:

Expected function 'cache' has no actual declaration in module KMM-APP.shared for JVM
Expected function 'cache' has no actual declaration in module KMM-APP.shared.iosArm64Main for Native
Expected function 'cache' has no actual declaration in module KMM-APP.shared.iosX64Main for Native

这有点令人困惑,因为我不在我的项目中使用 jvm 模块,尽管我使用了 IOS 模块。

这是我的 AndroidApp 模块的 cacheAndroid.kt:

import android.content.Context
import com.example.kmp_app.db.PetsDatabase
import com.squareup.sqldelight.android.AndroidSqliteDriver

lateinit var appContext: Context

internal actual fun cache(): PetsDatabase {
  val driver = AndroidSqliteDriver(PetsDatabase.Schema, appContext, "petsDB.db")
  return PetsDatabase(driver)
}

这是我的 IOS 模块的类:

import com.example.kmp_app.db.PetsDatabase
import com.squareup.sqldelight.drivers.native.NativeSqliteDriver

internal actual fun cache(): PetsDatabase {
    val driver = NativeSqliteDriver(PetsDatabase.Schema, "petsDB.db")
    return PetsDatabase(driver)
}

以及 commonModule 的使用:

internal expect fun cache(): PetsDatabase

我在最后一行代码中收到了上面的错误,但我也将错误放入了实际的类中Android 和 IOS 模块,进入其期望类变体。

最后关于我的 build.gradle(common)

plugins {
    kotlin("multiplatform")
    kotlin("native.cocoapods")
    id("com.android.library")
    id("kotlinx-serialization")
    id("com.squareup.sqldelight")
}

version = "1.0"

kotlin {
    targets{
        ios {
            binaries {
                framework {
                    baseName = "shared"
                }
            }
        }
        // Block from https://github.com/cashapp/sqldelight/issues/2044#issuecomment-721299517.
        val onPhone = System.getenv("SDK_NAME")?.startsWith("iphoneos") ?: false
        if (onPhone) {
            iosArm64("ios")
        } else {
            iosX64("ios")
        }

        android()
        //iosSimulatorArm64() sure all ios dependencies support this target
    }

    cocoapods {
        summary = "Some description for the Shared Module"
        homepage = "Link to the Shared Module homepage"
        ios.deploymentTarget = "14.1"
        podfile = project.file("../iosApp/Podfile")
    }
    
    sourceSets {
        all {
            languageSettings.apply {
                useExperimentalAnnotation("kotlinx.coroutines.ExperimentalCoroutinesApi")
            }
        }

        val commonMain by getting{
            dependencies {
                implementation(kotlin("stdlib-common"))
                implementation(Coroutines.Core.core)
                implementation(Ktor.Core.common)
                implementation(Ktor.Json.common)
                implementation(Ktor.Logging.common)
                implementation(Ktor.Serialization.common)
                implementation(SqlDelight.runtime)

            }
        }
        val commonTest by getting {
            dependencies {
                implementation(kotlin("test-common"))
                implementation(kotlin("test-annotations-common"))
                implementation(Ktor.Mock.common)
            }
        }
        val androidMain by getting{
            dependencies {
                implementation(kotlin("stdlib"))
                implementation(Coroutines.Core.core)
                implementation(Ktor.android)
                implementation(Ktor.Core.jvm)
                implementation(Ktor.Json.jvm)
                implementation(Ktor.Logging.jvm)
                implementation(Ktor.Logging.slf4j)
                implementation(Ktor.Mock.jvm)
                implementation(Ktor.Serialization.jvm)
                implementation(Serialization.core)
                implementation(SqlDelight.android)
            }
        }

        val androidAndroidTestRelease by getting
        val androidTest by getting {
            dependsOn(androidAndroidTestRelease)
            dependencies {
                implementation(kotlin("test-junit"))
                implementation("junit:junit:4.13.2")
            }
        }
        val iosX64Main by getting
        val iosArm64Main by getting
        //val iosSimulatorArm64Main by getting
        val ios by creating {
            dependsOn(commonMain)
            iosX64Main.dependsOn(this)
            iosArm64Main.dependsOn(this)
            //iosSimulatorArm64Main.dependsOn(this)
            dependencies {
                implementation(SqlDelight.native)
            }
        }
    }
}

android {
    compileSdk = 31
    sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
    defaultConfig {
        minSdk = 21
        targetSdk = 31
        versionCode = 1
        versionName = "1.0"
    }
}
sqldelight {
    database("PetsDatabase") {
        packageName = "com.example.kmp_app.db"
        sourceFolders = listOf("sqldelight")
    }
}

和我的项目 build.gradle:

buildscript {
    repositories {
        google()
        mavenCentral()
        jcenter()
    }
    dependencies {
        classpath("com.android.tools.build:gradle:4.2.0")
        classpath(kotlin("gradle-plugin", version = Versions.kotlin))
        classpath(kotlin("serialization", version = Versions.kotlin))
        classpath("com.squareup.sqldelight:gradle-plugin:${Versions.sqldelight}")
    }
}

allprojects {
    repositories {
        google()
        mavenCentral()
        jcenter()
    }
}

plugins{
    //kotlin("android") version "${Versions.kotlin}" apply false
}

我希望你能提供帮助,如果像这样,请提前致谢!

I was develoing an KMM App, where I try to implement a regular localDatasource and remoteDatasource, using SQLDelight and Ktor respectively.

My problems comes when I try to shared the native code from AndroidApp and iosMain, into commonModule. I start to get the following error into my commonModule expect class:

Expected function 'cache' has no actual declaration in module KMM-APP.shared for JVM
Expected function 'cache' has no actual declaration in module KMM-APP.shared.iosArm64Main for Native
Expected function 'cache' has no actual declaration in module KMM-APP.shared.iosX64Main for Native

It's a bit confuse, in order I don't make use of jvm module in my proyect, although I do for IOS module.

Here it's my cacheAndroid.kt of AndroidApp module:

import android.content.Context
import com.example.kmp_app.db.PetsDatabase
import com.squareup.sqldelight.android.AndroidSqliteDriver

lateinit var appContext: Context

internal actual fun cache(): PetsDatabase {
  val driver = AndroidSqliteDriver(PetsDatabase.Schema, appContext, "petsDB.db")
  return PetsDatabase(driver)
}

Here is the classes of my IOS module:

import com.example.kmp_app.db.PetsDatabase
import com.squareup.sqldelight.drivers.native.NativeSqliteDriver

internal actual fun cache(): PetsDatabase {
    val driver = NativeSqliteDriver(PetsDatabase.Schema, "petsDB.db")
    return PetsDatabase(driver)
}

And the use into commonModule:

internal expect fun cache(): PetsDatabase

I in this last line of code where I reciving the error above, but I also get the error into the actual classes of Android and IOS modules, into their expect class variant.

Finally regarding my build.gradle(common)

plugins {
    kotlin("multiplatform")
    kotlin("native.cocoapods")
    id("com.android.library")
    id("kotlinx-serialization")
    id("com.squareup.sqldelight")
}

version = "1.0"

kotlin {
    targets{
        ios {
            binaries {
                framework {
                    baseName = "shared"
                }
            }
        }
        // Block from https://github.com/cashapp/sqldelight/issues/2044#issuecomment-721299517.
        val onPhone = System.getenv("SDK_NAME")?.startsWith("iphoneos") ?: false
        if (onPhone) {
            iosArm64("ios")
        } else {
            iosX64("ios")
        }

        android()
        //iosSimulatorArm64() sure all ios dependencies support this target
    }

    cocoapods {
        summary = "Some description for the Shared Module"
        homepage = "Link to the Shared Module homepage"
        ios.deploymentTarget = "14.1"
        podfile = project.file("../iosApp/Podfile")
    }
    
    sourceSets {
        all {
            languageSettings.apply {
                useExperimentalAnnotation("kotlinx.coroutines.ExperimentalCoroutinesApi")
            }
        }

        val commonMain by getting{
            dependencies {
                implementation(kotlin("stdlib-common"))
                implementation(Coroutines.Core.core)
                implementation(Ktor.Core.common)
                implementation(Ktor.Json.common)
                implementation(Ktor.Logging.common)
                implementation(Ktor.Serialization.common)
                implementation(SqlDelight.runtime)

            }
        }
        val commonTest by getting {
            dependencies {
                implementation(kotlin("test-common"))
                implementation(kotlin("test-annotations-common"))
                implementation(Ktor.Mock.common)
            }
        }
        val androidMain by getting{
            dependencies {
                implementation(kotlin("stdlib"))
                implementation(Coroutines.Core.core)
                implementation(Ktor.android)
                implementation(Ktor.Core.jvm)
                implementation(Ktor.Json.jvm)
                implementation(Ktor.Logging.jvm)
                implementation(Ktor.Logging.slf4j)
                implementation(Ktor.Mock.jvm)
                implementation(Ktor.Serialization.jvm)
                implementation(Serialization.core)
                implementation(SqlDelight.android)
            }
        }

        val androidAndroidTestRelease by getting
        val androidTest by getting {
            dependsOn(androidAndroidTestRelease)
            dependencies {
                implementation(kotlin("test-junit"))
                implementation("junit:junit:4.13.2")
            }
        }
        val iosX64Main by getting
        val iosArm64Main by getting
        //val iosSimulatorArm64Main by getting
        val ios by creating {
            dependsOn(commonMain)
            iosX64Main.dependsOn(this)
            iosArm64Main.dependsOn(this)
            //iosSimulatorArm64Main.dependsOn(this)
            dependencies {
                implementation(SqlDelight.native)
            }
        }
    }
}

android {
    compileSdk = 31
    sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
    defaultConfig {
        minSdk = 21
        targetSdk = 31
        versionCode = 1
        versionName = "1.0"
    }
}
sqldelight {
    database("PetsDatabase") {
        packageName = "com.example.kmp_app.db"
        sourceFolders = listOf("sqldelight")
    }
}

And my proyect build.gradle:

buildscript {
    repositories {
        google()
        mavenCentral()
        jcenter()
    }
    dependencies {
        classpath("com.android.tools.build:gradle:4.2.0")
        classpath(kotlin("gradle-plugin", version = Versions.kotlin))
        classpath(kotlin("serialization", version = Versions.kotlin))
        classpath("com.squareup.sqldelight:gradle-plugin:${Versions.sqldelight}")
    }
}

allprojects {
    repositories {
        google()
        mavenCentral()
        jcenter()
    }
}

plugins{
    //kotlin("android") version "${Versions.kotlin}" apply false
}

I hope you can help and if like this, take thanks in advance !

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

吖咩 2025-01-16 12:25:38

我认为它与 Gradle 中的 packageName 有关:

 packageName = "com.example.kmp_app.db"
  1. 尝试传递缓存函数的路由而不是 "com.example.kmp_app.db"
    就像如果我的缓存函数存在于 dataSource.cacheSource 上,我们将传递 "com.example.kmp_app.db.dataSource.cacheSource"

  2. 确保您的缓存实际 / Expect 函数具有相同的包名称,如 "com.example.kmp_app.db.dataSource.cacheSource"

Shared gradle

sqldelight {
    database("RecipeDatabase") {
        packageName = "com.example.food1fork.Food1ForkKmm.DataSource.cacheSource"
        sourceFolders = listOf("SqlDelight")
    }
}

iOS module

package com.example.food1fork.Food1ForkKmm.DataSource.cacheSource

actual class DriverFactory {
    actual fun createDriver(): SqlDriver {
        return NativeSqliteDriver(RecipeDatabase.Schema, "recipes.db")
    }
}

Android module

package com.example.food1fork.Food1ForkKmm.DataSource.cacheSource

actual class DriverFactory(private val context: Context) {
    actual fun createDriver(): SqlDriver {
        return AndroidSqliteDriver(RecipeDatabase.Schema, context, "recipes.db")
    }
}

Shared module

package com.example.food1fork.Food1ForkKmm.DataSource.cacheSource

expect class DriverFactory {
    fun createDriver(): SqlDriver
}

I think it related with packageName in your Gradle:

 packageName = "com.example.kmp_app.db"
  1. Try to pass route of your cache function instead of "com.example.kmp_app.db"
    like if my cache function exists on dataSource.cacheSource, we will pass "com.example.kmp_app.db.dataSource.cacheSource"

  2. Be sure your Cache actual / expect function have the same package name like this "com.example.kmp_app.db.dataSource.cacheSource"

Shared gradle

sqldelight {
    database("RecipeDatabase") {
        packageName = "com.example.food1fork.Food1ForkKmm.DataSource.cacheSource"
        sourceFolders = listOf("SqlDelight")
    }
}

iOS module

package com.example.food1fork.Food1ForkKmm.DataSource.cacheSource

actual class DriverFactory {
    actual fun createDriver(): SqlDriver {
        return NativeSqliteDriver(RecipeDatabase.Schema, "recipes.db")
    }
}

Android module

package com.example.food1fork.Food1ForkKmm.DataSource.cacheSource

actual class DriverFactory(private val context: Context) {
    actual fun createDriver(): SqlDriver {
        return AndroidSqliteDriver(RecipeDatabase.Schema, context, "recipes.db")
    }
}

Shared module

package com.example.food1fork.Food1ForkKmm.DataSource.cacheSource

expect class DriverFactory {
    fun createDriver(): SqlDriver
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文