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