https://kotlinlang.org logo
#multiplatform
Title
# multiplatform
t

Tom Wayne

05/20/2021, 9:44 AM
Hey all, I am have an KMP project which contains iOS app, Android app and shared KMP module. When I try to build the iOS app from the Android Studio (in order to be able to debug it) the build succeed. 🙂 The problem is that the build always (when you change a code) take around 12 minutes. Which is way to long when you are debugging and often testing if given code works. The 90% percent of time spent on build is used to run these tasks:
Task :kmpcorelib:linkDebugFrameworkIosArm64
> Task :kmpcorelib:linkDebugFrameworkIosX64
> Task :kmpcorelib:linkKMPCoreDebugFrameworkIosArm64
> Task :kmpcorelib:linkKMPCoreDebugFrameworkIosX64
> Task :kmpcorelib:linkKMPCoreReleaseFrameworkIosArm64
> Task :kmpcorelib:linkKMPCoreReleaseFrameworkIosX64
> Task :kmpcorelib:linkReleaseFrameworkIosArm64
> Task :kmpcorelib:linkReleaseFrameworkIosX64
My question is: Is there a way how to run the app on iOS simulator without running all these task? I dont know why the studio needs to link the RELEASE version of the framework. Also I dont understand why it has to run the iOSArm64 variants when its running the on the X64 simulator. Also whats the difference between running
linkDebugFrameworkIosArm64
and
linkKMPCoreDebugFrameworkIosArm64
isnt it duplication? PS: I run the iOS buld via clicking the default configuration in Android studio. Not some custom gradle script
🧵 5
This is how the KMP build.gradle looks like:
Copy code
plugins {
    id("com.android.library")
    kotlin("multiplatform")
    kotlin("native.cocoapods")
    kotlin("plugin.serialization") version "1.5.0"
    id("com.prof18.kmp.fatframework.cocoa") version "0.0.1"
    id("io.gitlab.arturbosch.detekt")
    id("maven-publish")
}

version = "1.3.11"
group = "com.betsys.kmpcorelib"
val podName = "KMPCore"

detekt {
    autoCorrect = true
    config = files("$rootDir/config/detekt.yml")
    baseline = file("$rootDir/config/baseline.xml")
    input = files("src/commonMain/kotlin")
    reports {
        html.enabled = true
        xml.enabled = true
        txt.enabled = true
    }
}

// If you want to build iOS app from Android Studio - you have to put this config to comment - it somehow breaks the iOS build
fatFrameworkCocoaConfig {
    fatFrameworkName = podName
    outputPath = "$rootDir/../cocoapods"
    versionName = "1.16.1"
}

val ktorVersion = "1.5.4"
val napierVersion = "1.4.1"
val koinVersion = "3.0.1"
val kotlinxVersion = "1.4.1"
val kotlinxDatetime = "0.1.1"

kotlin {
    // We cant use simple ios() target now, since it doesnt support Arm32 architecture
    // For that reason we have specify each target explicitly
    // Same for folders with iOS code. We havet to use duplicit iosX64Main etc. instead of one iosMain folder

    ios("ios") {
        binaries.framework(podName)
    }
    android {
        publishLibraryVariants("debug")
        publishLibraryVariantsGroupedByFlavor = true
    }


    sourceSets {
        val commonMain by getting {
            dependencies {
                implementation("io.ktor:ktor-client-core:$ktorVersion")
                implementation("io.ktor:ktor-client-logging:$ktorVersion")
                implementation("io.ktor:ktor-client-mock:$ktorVersion")
                implementation("io.ktor:ktor-client-serialization:$ktorVersion")
                implementation("io.ktor:ktor-client-websockets:$ktorVersion")
                api("io.insert-koin:koin-core:$koinVersion")
                api("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinxVersion-native-mt")
                api("org.jetbrains.kotlinx:kotlinx-datetime:$kotlinxDatetime")
                api("com.ionspin.kotlin:bignum:0.3.1-SNAPSHOT")
                implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.0")
            }
        }

        val commonTest by getting {
            dependencies {
                implementation(kotlin("test-common"))
                implementation(kotlin("test-annotations-common"))
                implementation( "io.mockk:mockk-common:1.11.0")
                implementation("com.ionspin.kotlin:bignum:0.3.1-SNAPSHOT")
            }
        }

        val androidMain by getting {
            dependencies {
                implementation("io.ktor:ktor-client-android:$ktorVersion")
                implementation("com.google.android.material:material:1.3.0")
                implementation("io.ktor:ktor-client-okhttp:$ktorVersion")
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinxVersion")
                implementation("com.jakewharton.timber:timber:4.7.1")
            }
        }

        val androidTest by getting {
            dependencies {
                implementation(kotlin("test-junit"))
                implementation("junit:junit:4.13.2")
                implementation("io.mockk:mockk:1.11.0")
            }
        }

        val iosMain by getting {
            dependencies {
                implementation("io.ktor:ktor-client-ios:$ktorVersion")
            }
        }

        val iosTest by getting

    }
}

android {
    compileSdkVersion(30)
    sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")

    defaultConfig {
        minSdkVersion(19)
        targetSdkVersion(30)
        versionCode = 1
        versionName = "1.0"
        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        getByName("release") {
            isMinifyEnabled = false
        }
    }

    packagingOptions {
        excludes.add("META-INF/*.kotlin_module")
    }

    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }

    tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().all {
        kotlinOptions {
            jvmTarget = "1.8"
        }
    }
}

val packForXcode by tasks.creating(Sync::class) {
    val targetDir = File(buildDir, "xcode-frameworks")

    /// selecting the right configuration for the iOS
    /// framework depending on the environment
    /// variables set by Xcode build
    val mode = System.getenv("CONFIGURATION") ?: "DEBUG"
    val sdkName: String? = System.getenv("SDK_NAME")
    val isiOSDevice = sdkName.orEmpty().startsWith("iphoneos")

    val framework = kotlin.targets
        .getByName<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget>(
            if (isiOSDevice) {
                "iosArm64"
            } else {
                "iosX64"
            }
        )
        .binaries.getFramework(mode)

    inputs.property("mode", mode)
    dependsOn(framework.linkTask)

    from({ framework.outputDirectory })
    into(targetDir)

    println("Build Folder => $targetDir")

    /// generate a helpful ./gradlew wrapper with embedded Java path
    doLast {
        val gradlew = File(targetDir, "gradlew")
        gradlew.writeText(
            "#!/bin/bash\n"
                    + "export 'JAVA_HOME=${System.getProperty("java.home")}'\n"
                    + "cd '${rootProject.rootDir}'\n"
                    + "./gradlew \$@\n"
        )
        gradlew.setExecutable(true)
    }
}

tasks.build.dependsOn("packForXCode")
2 Views