I have a kotlin multiplatform project to make a shared library targeting iOS and Android. I have a handful of multiplatform external libraries : sqldelight, kodein-di, ktor, klock, kotlinx-coroutines and kotlinx-serialization.
It takes around 5 minutes to build the shared lib as an apple framework using command line ./gradlew :SharedCode:build
Is it possible to reduce this build time ?
My SharedCode multiplatform lib build.gradle
apply plugin: 'kotlinx-serialization'
apply plugin: 'com.android.library'
apply plugin: 'org.jetbrains.kotlin.multiplatform'
apply plugin: "com.squareup.sqldelight"
apply plugin: "org.jetbrains.dokka"
group = 'com.example.multiplatform'
version = '1.0'
android {
compileSdkVersion 28
defaultConfig {
minSdkVersion 15
}
buildTypes {
release {
minifyEnabled false
}
}
compileOptions {
sourceCompatibility = '1.8'
targetCompatibility = '1.8'
}
}
sqldelight {
MyDB {
packageName = "com.example.multiplatform"
}
}
dokka {
outputFormat = "markdown"
impliedPlatforms = ["common"] // This will force platform tags for all non-common sources e.g. "JVM"
kotlinTasks {
// dokka fails to retrieve sources from MPP-tasks so they must be set empty to avoid exception
// use sourceRoot instead (see below)
[]
}
sourceRoot {
// assuming there is only a single source dir...
path = kotlin.sourceSets.commonMain.kotlin.srcDirs[0]
platforms = ["common"]
}
}
dependencies {
// Specify Kotlin/JVM stdlib dependency.
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
testImplementation 'junit:junit:4.12'
testImplementation 'org.jetbrains.kotlin:kotlin-test'
testImplementation 'org.jetbrains.kotlin:kotlin-test-junit'
androidTestImplementation 'junit:junit:4.12'
androidTestImplementation 'org.jetbrains.kotlin:kotlin-test'
androidTestImplementation 'org.jetbrains.kotlin:kotlin-test-junit'
androidTestImplementation "io.ktor:ktor-client-serialization-jvm:$ktor_version"
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
kotlin {
targets {
final def iOSTarget = System.getenv('SDK_NAME')?.startsWith("iphoneos") \
? presets.iosArm64 : presets.iosX64
fromPreset(iOSTarget, 'ios') {
binaries {
framework('SharedCode')
}
}
fromPreset(presets.android, 'android')
}
sourceSets {
all {
dependencies {
implementation "org.kodein.di:kodein-di-core:$kodein_version"
implementation "org.kodein.di:kodein-di-erased:$kodein_version"
}
}
commonMain {
dependencies {
//HTTP
implementation "io.ktor:ktor-client-json:$ktor_json_version"
implementation "io.ktor:ktor-client-serialization:$ktor_version"
//Coroutines
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core-common:$kotlinx_coroutines_version"
//Kotlinx serialization
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:$serialization_version"
//kclock
implementation "com.soywiz.korlibs.klock:klock:$klock_version"
}
}
commonTest {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-test-common'
implementation 'org.jetbrains.kotlin:kotlin-test-annotations-common'
implementation "io.ktor:ktor-client-mock:$ktor_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core-common:$kotlinx_coroutines_version"
implementation "org.kodein.di:kodein-di-core:$kodein_version"
implementation "org.kodein.di:kodein-di-erased:$kodein_version"
}
}
androidMain {
dependencies {
//HTTP
implementation "io.ktor:ktor-client-json-jvm:$ktor_json_version"
implementation "io.ktor:ktor-client-serialization-jvm:$ktor_version"
//Coroutines
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinx_coroutines_version"
//Kotlinx serialization
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:$serialization_version"
//sqldelight
implementation "com.squareup.sqldelight:android-driver:$sqldelight_version"
}
}
androidTest {
dependencies {
implementation 'junit:junit:4.12'
implementation 'org.jetbrains.kotlin:kotlin-test'
implementation 'org.jetbrains.kotlin:kotlin-test-junit'
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:$serialization_version"
implementation "io.ktor:ktor-client-mock-jvm:$ktor_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinx_coroutines_version"
}
}
iosMain {
dependencies {
//HTTP
implementation "io.ktor:ktor-client-ios:$ktor_version"
implementation "io.ktor:ktor-client-json-native:$ktor_json_version"
implementation "io.ktor:ktor-client-serialization-native:$ktor_version"
//Coroutines
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core-native:$kotlinx_coroutines_version"
//kotlinx serialization
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-native:$serialization_version"
//sqldelight
implementation "com.squareup.sqldelight:ios-driver:$sqldelight_version"
}
}
iosTest {
dependencies {
implementation "io.ktor:ktor-client-mock-native:$ktor_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core-native:$kotlinx_coroutines_version"
}
}
}
}
task iosTest {
def device = project.findProperty("iosDevice")?.toString() ?: "iPhone X"
def isDevice = System.getenv('SDK_NAME')?.startsWith("iphoneos")
dependsOn 'linkTestDebugExecutableIos'
group = JavaBasePlugin.VERIFICATION_GROUP
description = "Runs tests for target 'ios' on an iOS simulator"
doLast {
if (!isDevice) {
def binary = kotlin.targets.ios.binaries.getExecutable('test', 'DEBUG').outputFile
exec {
commandLine 'xcrun', 'simctl', 'spawn', device, binary.absolutePath
}
}
}
}
tasks.check.dependsOn iosTest
tasks.withType(Test) {
testLogging {
exceptionFormat "full"
events "passed", "failed"
showStandardStreams true
}
}
task packForXCode(type: Sync) {
final File frameworkDir = new File(buildDir, "xcode-frameworks")
final String mode = project.findProperty("XCODE_CONFIGURATION")?.toUpperCase() ?: 'DEBUG'
final def framework = kotlin.targets.ios.binaries.getFramework("SharedCode", mode)
inputs.property "mode", mode
dependsOn framework.linkTask
from { framework.outputFile.parentFile }
into frameworkDir
doLast {
new File(frameworkDir, 'gradlew').with {
text = "#!/bin/bash\nexport 'JAVA_HOME=${System.getProperty("java.home")}'\ncd '${rootProject.rootDir}'\n./gradlew \$@\n"
setExecutable(true)
}
}
}
tasks.build.dependsOn packForXCode
When I'm actively coding and testing, I just build the framework target rather than building the whole project with build
. Calling build
generally makes the debug and release frameworks, as well as test frameworks of both.
So, in my case, I run linkMainDebugFrameworkIos
instead of the full build
. That takes significantly less time. 1m 35s vs at least 5m, if not longer, for a full build.
That task name will probably change with 1.3.40+, and sqldelight and other libs should be on 1.3.40 soon-ish. Just FYI.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With