0

I'm trying to create my first KMM project ( using Ktor to get a simple query ). I've managed to run it in Android, but each time I try in iOS i got an exception when i use Ktor.

This is my gradle "Shared"

plugins {
    kotlin("multiplatform")
    kotlin("plugin.serialization")
    id("com.android.library")
    id("com.squareup.sqldelight")

}

kotlin {
    android()
    
    listOf(
        iosX64(),
        iosArm64(),
        iosSimulatorArm64()
    ).forEach {
        it.binaries.framework {
            baseName = "shared"
        }
    }

    sourceSets {
        val commonMain by getting {
            dependencies {
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.1")
                implementation("io.ktor:ktor-client-core:1.6.6")
                implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.3.2")
                implementation("io.ktor:ktor-client-serialization:1.6.5")
                implementation("com.squareup.sqldelight:runtime:1.5.3")
            }
        }
        val commonTest by getting {
            dependencies {
                implementation(kotlin("test"))
            }
        }
        val androidMain by getting {
            dependencies {
                implementation("io.ktor:ktor-client-android:1.6.5")
                implementation("com.squareup.sqldelight:android-driver:1.5.3")
            }
        }
        val androidTest by getting
        val iosX64Main by getting
        val iosArm64Main by getting
        val iosSimulatorArm64Main by getting
        val iosMain by creating {
            dependsOn(commonMain)
            iosX64Main.dependsOn(this)
            iosArm64Main.dependsOn(this)
            iosSimulatorArm64Main.dependsOn(this)
            dependencies {
                implementation("io.ktor:ktor-client-ios:1.6.5")
                implementation("com.squareup.sqldelight:native-driver:1.5.3")
            }
        }
        val iosX64Test by getting
        val iosArm64Test by getting
        val iosSimulatorArm64Test by getting
        val iosTest by creating {
            dependsOn(commonTest)
            iosX64Test.dependsOn(this)
            iosArm64Test.dependsOn(this)
            iosSimulatorArm64Test.dependsOn(this)
        }
    }
}

android {
    compileSdk = 32
    sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
    defaultConfig {
        minSdk = 21
        targetSdk = 32
    }
}

sqldelight {
    database("AppDatabase") {
        packageName = "com.example.basekmm_003"
    }
}

This is the base gradle

buildscript {
    repositories {
        gradlePluginPortal()
        google()
        mavenCentral()
    }
    dependencies {
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21")
        classpath("com.android.tools.build:gradle:7.2.0")
        classpath("com.squareup.sqldelight:gradle-plugin:1.5.3")
        classpath("org.jetbrains.kotlin:kotlin-serialization:1.6.21")
    }
}

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

tasks.register("clean", Delete::class) {
    delete(rootProject.buildDir)
}

The Android Studio version I'm using is: Chipmunk / 2021.2.1

The code for my api is:


class JsonApi() {
    suspend fun getLatestMovies(): List<JsonMessage>? =
        KtorClient.httpClient.get {
            
url("https://gitcdn.link/cdn/KaterinaPetrova/greeting/7d47a42fc8d28820387ac7f4aaf36d69e434adc1/greetings.json")
        }
}

@Serializable
data class JsonMessage(val string: String?, val lang: String?)

object KtorClient {
    private val json = Json {
        encodeDefaults = true
        ignoreUnknownKeys = true
    }
    val httpClient = HttpClient {
        install(JsonFeature) { serializer = KotlinxSerializer(json) }
        install(HttpTimeout) {
            socketTimeoutMillis = 30_000
            requestTimeoutMillis = 30_000
            connectTimeoutMillis = 30_000
        }
        defaultRequest {
            contentType(ContentType.Application.Json)
            accept(ContentType.Application.Json)
        }
    }
}

And the iOS Code is

@main
struct iOSApp: App {
    let sdk = MovieSDK(databaseDriverFactory: DatabaseDriverFactory())
        var body: some Scene {
            WindowGroup {
                ContentView(viewModel: .init(sdk: sdk))
            }
        }
}

struct RocketLaunchRow: View {
    var jsonMessage: JsonMessage

    var body: some View {
        HStack() {
            VStack(alignment: .leading, spacing: 10.0) {
                Text("Launch name: \(jsonMessage)")
            }
            Spacer()
        }
    }
}

struct ContentView: View {
  @ObservedObject private(set) var viewModel: ViewModel
    enum LoadableLaunches {
            case loading
            case result([JsonMessage])
            case error(String)
        }
    
    var body: some View {
        NavigationView {
            listView()
            .navigationBarTitle("SpaceX Launches")
            .navigationBarItems(trailing:
                Button("Reload") {
                    self.viewModel.loadLaunches()
            }
            )
        }
    }

    private func listView() -> AnyView {
        switch viewModel.launches {
        case .loading:
            return AnyView(Text("Loading...").multilineTextAlignment(.center))

        case .result(_):
            return AnyView(
                Text("Succes")
            )

        case .error(let description):
            return AnyView(Text(description).multilineTextAlignment(.center))
        }
    }
    
    
    class ViewModel: ObservableObject {
        let sdk: MovieSDK
        @Published var launches = LoadableLaunches.loading

        init(sdk: MovieSDK) {
            self.sdk = sdk
            self.loadLaunches()
        }

        func loadLaunches() {
            self.launches = .loading
            sdk.getLatestMovies(completionHandler: { launches, error in
                if let launches = launches {
                    self.launches = .result(launches)
                } else {
                    self.launches = .error(error?.localizedDescription ?? "error")
                }
            }
        )
        }
    }
}

The exception I'm getting is: enter image description here

What I'm doing wrong?, I've tried several approaches with the same result ( event with different urls )

Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220
Nicote Ool
  • 121
  • 8
  • Check if solution from [this answer](https://stackoverflow.com/a/66931899/3585796) helps. If it doesn't - add full stacktrace with exception error instead of error image - it should be printed into console and `MovieSDK` source code. – Phil Dukhov May 18 '22 at 17:18
  • 1
    You're welcome. If this solved your question, please upvote it. Voting is the most appropriate way to thank someone on SO, see [Why is voting important?]. – Phil Dukhov May 19 '22 at 18:03

0 Answers0