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

Cristián Arenas

11/20/2019, 12:57 PM
Hello everybody! I'm new here. How can I generate a
.framework
that works in both an iOS device and the simulator? Right now I'm changing 2 lines in my
build.gradle
every time I want to switch between targeting iosX64 (simulator) and iosArm64 (actual device).
These are the 2 lines I change, just in case it's relevant:
Copy code
-    iosX64("ios") {
+    iosArm64("ios") {
Copy code
-                implementation "io.ktor:ktor-client-serialization-iosx64:${versions.ktor}"
+                implementation "io.ktor:ktor-client-serialization-iosarm64:${versions.ktor}"
v

vanniktech

11/20/2019, 1:10 PM
Copy code
//select iOS target platform depending on the Xcode environment variables
  val iOSTarget: (String, KotlinNativeTarget.() -> Unit) -> KotlinNativeTarget = if (System.getenv("SDK_NAME")?.startsWith("iphoneos") == true) ::iosArm64 else ::iosX64

  iOSTarget("ios") {

  }
c

Cristián Arenas

11/20/2019, 1:15 PM
OK, if I understand that correctly, that’ll help me automate this change, to generate the correct framework. But that does not generate a
.framework
that works on both platforms, I need to distribute the framework so it should include appropriate binaries for both architectures. Do you know how to achieve this?
v

vanniktech

11/20/2019, 1:16 PM
Nope. Just started with multiplatform this Sunday
c

Cristián Arenas

11/20/2019, 1:17 PM
Oh OK, don’t worry then 🙂
I may end up using that if I can’t figure it out 😅 It’s better than doing it manually
a

Artyom Degtyarev [JB]

11/20/2019, 1:34 PM
Are you talking about something like described here(https://kotlinlang.org/docs/reference/building-mpp-with-gradle.html#building-final-native-binaries) in the Building universal frameworks section*?*
c

Cristián Arenas

11/20/2019, 1:35 PM
Oh, I think that’s exactly what I want! I didn’t know they were called “universal frameworks”. Thanks! ❤️
t

tylerwilson

11/20/2019, 2:15 PM
If you are already using Cocoapods in your project, I would suggest going that route: use the cocoapods plugin that generates a podspec which you link to from your Xcode project. Then when you build your project, it will rebuild the framework (if needed) using the correct current architecture. (https://kotlinlang.org/docs/reference/native/cocoapods.html)
k

Konstantin Petrukhnov

11/21/2019, 4:27 AM
@Cristián Arenas One way to build universal framework: https://github.com/Ekahau/khtf-iosapp-fw/ You may also need to have bitcode enabled and making your framework dynamic.
m

mkojadinovic

11/22/2019, 8:31 AM
I do something like this:
Copy code
iosArm64 {
        binaries {
            framework('Logger')
        }
    }

    iosX64 {
        binaries {
            framework('Logger')
        }
    }
// Create a task building a fat framework.
    task fatFramework(type: FatFrameworkTask) {
        def buildType = project.findProperty('kotlin.build.type') ?: 'DEBUG'
        baseName = "Logger"

        final File frameworkDir = new File(buildDir, "xcode-frameworks")
        destinationDir = frameworkDir

        from(
                targets.iosArm64.binaries.getFramework('Logger', buildType),
                targets.iosX64.binaries.getFramework('Logger', buildType)
        )
    }
Also, you have to add next:
Copy code
iosMain {
            dependencies {
                implementation deps.coroutineNative
                implementation deps.kotlinxSerRuntimeNative

                implementation deps.ktoriOS
                implementation deps.ktorSerializationNative

                // SQL Delight
                implementation deps.sqlDelightiOS
            }
        }
        iosX64Main {
            dependsOn iosMain
            kotlin.srcDirs += project.file("src/iosMain/kotlin")
        }

        iosArm64Main {
            dependsOn iosMain
            kotlin.srcDirs += project.file("src/iosMain/kotlin")
        }
k

Konstantin Petrukhnov

11/25/2019, 6:06 AM
@mkojadinovic could you please share full example of build.gradle?
m

mkojadinovic

11/25/2019, 7:21 AM
Copy code
import org.jetbrains.kotlin.gradle.tasks.FatFrameworkTask

apply plugin: "kotlin-multiplatform"
apply plugin: 'com.android.library'
apply plugin: 'kotlinx-serialization'
apply plugin: "com.squareup.sqldelight"
apply plugin: 'kotlin-kapt'

android {
    defaultConfig {
        minSdkVersion minSdk
        compileSdkVersion compileSdk
    }
    packagingOptions {
        exclude "META-INF/*"
    }

    testOptions {
        unitTests.returnDefaultValues = true
    }
}

kotlin {
    iosArm64 {
        binaries {
            framework('Logger')
        }
    }

    iosX64 {
        binaries {
            framework('Logger')
        }
    }


    // Create a task building a fat framework.
    task fatFramework(type: FatFrameworkTask) {
        def buildType = project.findProperty('kotlin.build.type') ?: 'DEBUG'
        baseName = "Logger"

        final File frameworkDir = new File(buildDir, "xcode-frameworks")
        destinationDir = frameworkDir

        from(
                targets.iosArm64.binaries.getFramework('Logger', buildType),
                targets.iosX64.binaries.getFramework('Logger', buildType)
        )
    }

    android()

    sourceSets {
        all {
            languageSettings {
                useExperimentalAnnotation('kotlin.Experimental')
            }
        }
        commonMain {
            dependencies {
                implementation deps.kotlinCommon
                implementation deps.coroutineCommon
                implementation deps.kotlinxSerRuntimeCommon

                implementation deps.ktorCore
                implementation deps.ktorSerialization

                // SQL Delight
                implementation deps.sqlDelightJVM

                implementation deps.kodeinErased
            }
        }
        commonTest {
            dependencies {
                implementation deps.kotlinReflect
                implementation deps.test.mockkCommon

                implementation deps.test.kotlinTestCommon
                implementation deps.test.kotlinAnnotCommon

                api deps.sqlDelightJVM
                api deps.test.ktorMock
            }
        }
        androidMain {
            dependencies {
                implementation deps.kotlin
                implementation deps.coroutineAndroid
                implementation deps.kotlinxSerRuntime

                implementation deps.ktorAndroid
                implementation deps.ktorSerializationJvm

                //Crashlytics
                implementation deps.crashlytics

                implementation deps.network.gson
                implementation deps.network.retrofit
                implementation deps.network.okhttp

                // SQL Delight
                implementation deps.sqlDelightAndroid

                implementation deps.kodeinErased
            }
        }
        androidTest {
            dependencies {
                implementation deps.test.kotlinTest
                implementation deps.test.kotlinTestJunit

                api deps.sqlDelightJVM

                implementation deps.test.ktorMockJvm
                implementation deps.test.kotlinTestJunit
                implementation deps.test.kotlinTest
                implementation deps.test.mockk
            }
        }
        iosMain {
            dependencies {
                implementation deps.coroutineNative
                implementation deps.kotlinxSerRuntimeNative

                implementation deps.ktoriOS
                implementation deps.ktorSerializationNative

                // SQL Delight
                implementation deps.sqlDelightiOS
            }
        }
        iosTest {
            dependencies {
                api deps.sqlDelightiOS

                api deps.test.ktorMockNative
            }
        }
        iosX64Main {
            dependsOn iosMain
            kotlin.srcDirs += project.file("src/iosMain/kotlin")
        }

        iosArm64Main {
            dependsOn iosMain
            kotlin.srcDirs += project.file("src/iosMain/kotlin")
        }
    }
}

sqldelight {
    LoggerDatabase {
        packageName = "com.example.logger"
    }
}

configurations {
    compileClasspath
}

tasks.build.dependsOn fatFramework


kapt {
    correctErrorTypes = true
    mapDiagnosticLocations = true
}

tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8

    kotlinOptions {
        jvmTarget = '1.8'
    }
}
3 Views