Android Studio:KMM 项目的“共享”模块目录始终未标记为源根目录

Mar*_*rat 5 android android-studio kotlin-multiplatform

我使用 KMM 向导在 Android Studio 中创建了一个新项目。我正在关注动手教程,我注意到我无法选择在某些目录中创建包。具体来说,在“共享”模块内部,只有 androidMain 文件夹的 kotlin 目录始终标记为“源根”。

我手动将其他文件夹(commonMain、iosMain)中的 kotlin 目录标记为“sources root”。我还将 commonMain 内的 sqldelight 目录标记为“源根”。

但 Android Studio 会定期恢复该状态。我不知道是什么导致了这个问题。它还显示 androidMain 文件夹的 kotlin 目录被设置为“sources root”,但也不是。奇怪的是,目录不能同时设置和取消设置为“源根目录”。

这是 Android Studio、KMM 插件的错误还是首选项中的某种设置?

Android Studio版本:4.1.1

KMM插件版本:0.1.3-release-54-Studio4.1

在此输入图像描述

在此输入图像描述

编辑:

共享模块的build.gradle.kts :

import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget

plugins {
    kotlin("multiplatform")
    kotlin("plugin.serialization")
    id("com.android.library")
    id("kotlin-android-extensions")
    id("com.squareup.sqldelight")
}
group = "com.example.kmmapplication"
version = "1.0-SNAPSHOT"

repositories {
    gradlePluginPortal()
    google()
    jcenter()
    mavenCentral()
}
kotlin {
    android()
    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")
    }

    val coroutinesVersion = "1.3.9-native-mt"
    val serializationVersion = "1.0.1"
    val ktorVersion = "1.4.2"
    val sqlDelightVersion: String by project

    sourceSets {
        val commonMain by getting {
            dependencies {
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
                implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$serializationVersion")
                implementation("io.ktor:ktor-client-core:$ktorVersion")
                implementation("io.ktor:ktor-client-serialization:$ktorVersion")
                implementation("com.squareup.sqldelight:runtime:$sqlDelightVersion")
            }
        }
        val commonTest by getting {
            dependencies {
                implementation(kotlin("test-common"))
                implementation(kotlin("test-annotations-common"))
            }
        }
        val androidMain by getting {
            dependencies {
                implementation("io.ktor:ktor-client-android:$ktorVersion")
                implementation("com.squareup.sqldelight:android-driver:$sqlDelightVersion")
            }
        }
        val androidTest by getting {
            dependencies {
                implementation(kotlin("test-junit"))
                implementation("junit:junit:4.13.1")
            }
        }
        val iosMain by getting {
            dependencies {
                implementation("io.ktor:ktor-client-ios:$ktorVersion")
                implementation("com.squareup.sqldelight:native-driver:$sqlDelightVersion")
            }
        }
        val iosTest by getting
    }
}
android {
    compileSdkVersion(29)
    sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
    defaultConfig {
        minSdkVersion(24)
        targetSdkVersion(29)
        versionCode = 1
        versionName = "1.0"
    }
    buildTypes {
        getByName("release") {
            isMinifyEnabled = false
        }
    }
}

sqldelight {
    database("AppDatabase") {
        packageName = "com.example.kmmapplication.shared.cache"
    }
}

val packForXcode by tasks.creating(Sync::class) {
    group = "build"
    val mode = System.getenv("CONFIGURATION") ?: "DEBUG"
    val sdkName = System.getenv("SDK_NAME") ?: "iphonesimulator"
    val targetName = "ios" + if (sdkName.startsWith("iphoneos")) "Arm64" else "X64"
    val framework =
        kotlin.targets.getByName<KotlinNativeTarget>(targetName).binaries.getFramework(mode)
    inputs.property("mode", mode)
    dependsOn(framework.linkTask)
    val targetDir = File(buildDir, "xcode-frameworks")
    from({ framework.outputDirectory })
    into(targetDir)
}
tasks.getByName("build").dependsOn(packForXcode)
Run Code Online (Sandbox Code Playgroud)

设置.gradle.kts

pluginManagement {
    repositories {
        gradlePluginPortal()
        google()
        jcenter()
        mavenCentral()
    }
    resolutionStrategy {
        eachPlugin {
            if (requested.id.namespace == "com.android" || requested.id.name == "kotlin-android-extensions") {
                useModule("com.android.tools.build:gradle:4.0.1")
            }
        }
    }
}
rootProject.name = "KMMApplication"


include(":androidApp")
include(":shared")
Run Code Online (Sandbox Code Playgroud)

gradle-wrapper.properties

distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
Run Code Online (Sandbox Code Playgroud)

Kev*_*gan 3

这些 ios 目标定义冲突:

    ios { //Target 1
        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") //Target 2
    } else {
        iosX64("ios") //Target 3
    }
Run Code Online (Sandbox Code Playgroud)

你有ios,它是 arm 和 x64 的组合目标,然后是单独的目标iosArm64和 iosX64`。我不知道这是否是导致 IDE 问题的原因,但这确实令人困惑。

第二个没有定义框架,因为它们是从使用 cocoapods 的上下文中获取的。如果您查看 sqldelight 问题评论,它来自我,最终来自 KaMPKit: https: //github.com/touchlab/KaMPKit/blob/master/shared/build.gradle.kts#L28

为了让 IDE 正常工作,我建议删除第一个ios目标。但是,再次强调,sqldelight 问题中的示例假设您已配置 cocoapods。您需要添加 cocoapods 或更新目标配置和packForXcode.

目标如下所示。

val onPhone = System.getenv("SDK_NAME")?.startsWith("iphoneos") ?: false
    if (onPhone) {
        iosArm64("ios") {
          binaries {
              framework {
                  baseName = "shared"
              }
          }
      }
    } else {
        iosX64("ios") {
          binaries {
             framework {
                 baseName = "shared"
             }
          }
       }
    }
Run Code Online (Sandbox Code Playgroud)

作为替代方案,我建议仅使用 KaMPKit 作为项目的基础,直到您更熟悉 KMM 插件示例和配置选项。它们还不能完全开箱即用。