Kotlin/Multiplatform Fat Framework for iOS

When building a Kotlin/Multiplatform library for iOS, the documentation and most examples show how to build for either x86 or ARM64. However, what if you’d actually want to use your library both on iPhone devices as well as the iOS Simulator. Here’s how to build a fat framework with plain Gradle.

In this article, we’ll look at a real-world example; Log4K, a lightweight logging library for Kotlin/Multiplatform that supports Android, iOS, JavaScript and plain JVM environments. We’ll start of by declaring the supported iOS architectures and the final framework name, e.g. Log4K.framework:

kotlin {
    iosArm64 { binaries.framework("Log4K") }
    iosX64 { binaries.framework("Log4K") }

    // ...

Each architecture has to be backed by a Gradle module source set. In other words, you’d have to create the sources for each architecture in it’s own directory. Fortunately, the Kotlin/Multiplatform Gradle module allows to depend on other source sets to reduce duplication. Thus, move your sources into a new iosMain folder that we’ll use to share code across target platforms.

Don’t forget to declare this source set with Gradle and let the iosArm64 and iosX64 source sets depend on it:

kotlin {
    // ...
    sourceSets {
        val iosMain by creating {
            dependencies { }
        }
        val iosTest by creating {
            dependencies {
                implementation(kotlin("test"))
            }
        }
        getByName("iosArm64Main") { dependsOn(iosMain) }
        getByName("iosArm64Test") { dependsOn(iosTest) }
        getByName("iosX64Main") { dependsOn(iosMain) }
        getByName("iosX64Test") { dependsOn(iosTest) }

        // Other source sets for Android, JavaScript, ...
    }

Now that that the source code is arranged properly, we need a Gradle task to produce the Framework. We’ll register a new task universalFrameworkDebug to build the debug version. Please note we’ll have to use the framework name we configured earlier:

kotlin {
   // ... 
   tasks {
        register("universalFrameworkDebug", org.jetbrains.kotlin.gradle.tasks.FatFrameworkTask::class) {
            baseName = "Log4K"
            from(
                iosArm64().binaries.getFramework("Log4K", "Debug"),
                iosX64().binaries.getFramework("Log4K", "Debug")
            )
            destinationDir = buildDir.resolve("bin/universal/debug")
            group = "Universal framework"
            description = "Builds a universal (fat) debug framework"
            dependsOn("linkLog4KDebugFrameworkIosArm64")
            dependsOn("linkLog4KDebugFrameworkIosX64")
        }

The task for a release build looks almost the same:

        register("universalFrameworkRelease", org.jetbrains.kotlin.gradle.tasks.FatFrameworkTask::class) {
            baseName = "Log4K"
            from(
                iosArm64().binaries.getFramework("Log4K", "Release"),
                iosX64().binaries.getFramework("Log4K", "Release")
            )
            destinationDir = buildDir.resolve("bin/universal/release")
            group = "Universal framework"
            description = "Builds a universal (fat) release framework"
            dependsOn("linkLog4KReleaseFrameworkIosArm64")
            dependsOn("linkLog4KReleaseFrameworkIosX64")
        }

Lastly, you might want to be able to build both debug and release at the same time:

        register("universalFramework") {
            dependsOn("universalFrameworkDebug")
            dependsOn("universalFrameworkRelease")
        } 

You are now able to build your library for iOS x64 and ARM64:

./gradlew universalFramework

That’s it. You can find the entire Grade sources on Github. The library is published on Bintray.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.