Search code examples
androidandroid-studiogradlektorkmm

Adding Ktor To Kotlin Multiplatform Mobile results in Unresolved reference: HttpClient


I can't get Ktor to work in a KMM project, I just get a Unresolved reference: HttpClient error when trying to reference any Ktor classes. If I try to manually add the ktor import it says Unresolved reference io. Other dependencies like Kermit resolve fine, it seems to just be Ktor with the issue. Here's my simple steps to reproduce:

enter image description here

  1. In Android Studio (I have tried both 4.1.3 and 4.2 Beta 6), I go File -> New -> KMM Application.

  2. In the shared module build.gradle.kts I add the dependencies for the ktor client:

val commonMain by getting {
        dependencies {
            implementation("io.ktor:ktor-client-core:1.5.2")
        }
     }
  1. In the Greeting class in commonMain I try creating an HttpClient like it says in the Ktor documents https://kotlinlang.org/docs/mobile/use-ktor-for-networking.html#select-an-engine:
class Greeting {
    val httpClient: HttpClient = HttpClient()

    fun greeting(): String {
        return "Hello, ${Platform().platform}!"
    }
}

I get the Unresolved reference: HttpClient. The ktor imports don't work.

Things I have tried:

  1. Adding the Android and iOS client dependencies as well.
  2. Adding enableFeaturePreview("GRADLE_METADATA") to settings.gradle.kts as suggested here: How to fix 'Unresolved reference: HttpClient' with ktor-client-core targeting linuxX64
  3. Cleaning, syncing with gradle, invalidate cashes and restart, closing AS and re-opening, building the project.

I really have no idea why this doesn't work, it seems like it the simplest possible setup. Here's my build.gradle files and settings file (which were auto generated from new KMM project wizard)

shared module build.gradle.kts

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

plugins {
    kotlin("multiplatform")
    id("com.android.library")
}

kotlin {
    android()
    ios {
        binaries {
            framework {
                baseName = "shared"
            }
        }
    }
    sourceSets {
        val commonMain by getting {
            dependencies {
                implementation("io.ktor:ktor-client-core:1.5.2")
            }
        }
        val commonTest by getting {
            dependencies {
                implementation(kotlin("test-common"))
                implementation(kotlin("test-annotations-common"))
            }
        }
        val androidMain by getting {
            dependencies {
                implementation("com.google.android.material:material:1.2.1")
            }
        }
        val androidTest by getting {
            dependencies {
                implementation(kotlin("test-junit"))
                implementation("junit:junit:4.13")
            }
        }
        val iosMain by getting
        val iosTest by getting
    }
}

android {
    compileSdkVersion(29)
    sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
    defaultConfig {
        minSdkVersion(24)
        targetSdkVersion(29)
    }
}

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)

Project build.gradle.kts

buildscript {
    repositories {
        gradlePluginPortal()
        jcenter()
        google()
        mavenCentral()
    }
    dependencies {
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.10")
        classpath("com.android.tools.build:gradle:4.0.1")
    }
}

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

settings.gradle.kts

pluginManagement {
    repositories {
        google()
        jcenter()
        gradlePluginPortal()
        mavenCentral()
    }
    
}
rootProject.name = "core"


include(":androidApp")
include(":shared")



Solution

  • I answered this question here: https://stackoverflow.com/a/66913665/5222156

    Basically updating org.jetbrains.kotlin:kotlin-gradle-plugin from 1.4.10 to 1.4.31 in root build.gradle.kts fixed the issue for me.

    This is how my build.gradle.kts file looks like:

    buildscript {
        repositories {
            gradlePluginPortal()
            jcenter()
            google()
            mavenCentral()
        }
        dependencies {
            classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.31")
            classpath("com.android.tools.build:gradle:4.2.0-beta06")
            classpath("com.squareup.sqldelight:gradle-plugin:1.4.4")
        }
    }
    
    allprojects {
        repositories {
            google()
            jcenter()
            mavenCentral()
        }
    }