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

Posted

技术标签:

【中文标题】Android Studio:KMM 项目的“共享”模块目录一直未被标记为源根目录【英文标题】:Android Studio: "shared" module directories of KMM project keep getting unmarked as sources root 【发布时间】:2021-03-03 18:11:16 【问题描述】:

我使用 KMM 向导在 android Studio 中创建了一个新项目。我正在关注handson tutorial,我注意到我没有在某些目录中创建包的选项。具体来说,在“shared”模块中,只有 androidMain 文件夹的 kotlin 目录总是被标记为“sources root”。

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

但 Android Studio 会定期恢复该状态。我不知道是什么导致了这个问题。它还表明androidMain文件夹的kotlin目录设置为“sources root”,也不是。奇怪的是,目录不能同时设置和取消设置为“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)

settings.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")

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

【问题讨论】:

这可能是 Gradle 配置问题。请发布settings.gradlebuild.gradle 用于共享和 Gradle 版本(来自gradle/wrapper/gradle-wrapper.properties)。 @KevinGalligan 感谢您的评论。我从这 3 个文件中发布了代码 同样的问题。每个 gradle 同步都使其“未标记为 root”,这令人沮丧。 【参考方案1】:

这些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
    

您有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"
             
          
       
    

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

【讨论】:

感谢您的回答。我是 KMM 的初学者,也没有很好的 Gradle 技能。我同意这三个目标冲突。我还不知道如何将 cocoapods 添加到我的项目中。但我最终会这样做。我尝试删除第二个和第三个目标并尝试使用 IDE。我还下载了 KaMPKit 应用程序的 ZIP 并尝试编译它。在所有情况下,项目结构的错误仍然存​​在。此外,IDE 似乎不时删除一些依赖项,即序列化,我得到很多 Lint 错误。只有“使缓存无效并重新启动”有帮助。 您认为这是 Kotlin Multiplatform 插件或 Android Studio 中的错误吗? 哪一块有错误,不知道。您应该能够解决 KaMP Kit,所以我不确定发生了什么。这是使用 Android Studio 4.1 和 Intellij 2020.2.3 测试的(我相信)。

以上是关于Android Studio:KMM 项目的“共享”模块目录一直未被标记为源根目录的主要内容,如果未能解决你的问题,请参考以下文章

无法将 io.ktor 导入 Android Studio 中 KMM 的通用模块

KMM:如何将共享模块引用到现有的 iOS 项目中

Koin在KMM与Android Jetpack Compose中的应用

如何在 KMM(kotlin 本机)共享模块中读取 Swift 框架库中生成的对象数组

空 KMM 项目卡在 gradle 同步中

如何在android studio项目中包含共享库?