December 12, 2022

Improving KMM CI Build Times

Improving KMM CI Build Times

Modern application development is shifting to be faster, more efficient, and increasingly geared towards mobile cross-platform app development. Cross-platform frameworks use a single codebase and logic that can be replicated for multiple mobile operating systems. This versatility might previously have sacrificed platform-specific features and functionality, but Kotlin Multiplatform Mobile (KMM) provides all the combined advantages of cross-platform and native app development.

KMM, an SDK from JetBrains, offers native and cross-platform ways to create mobile apps for iOS and Android. Similar to a cross-platform framework, KMM supports the development of native apps while allowing for codebase reuse. It also addresses the difficulty of sustaining flexibility while maintaining separate codebases.

Because it is a relatively new technology, though, KMM still has a few pain points that you may run across. In this article, you’ll learn more about some of these challenges and the solutions you can use to reduce errors with your KMM-based continuous integration (CI) builds.

Why Do You Need KMM?

Approximately 83 percent of the world’s population uses smartphones. With such a large userbase, there is naturally intense demand for more efficient and cost-effective app development methods. As a result, development frameworks are racing to produce cross-platform apps that are accessible to both Android and iOS consumers. The Kotlin Multiplatform Mobile SDK allows users to share code, access multiplatform libraries, and streamline the development process.

Kotlin is already used by major mobile development teams and organizations all over the world. Using KMM, Unflow’s product team delivered an exceptionally high-quality product by removing redundancy in code, reducing time and effort, and maintaining performance and native capabilities. There are many other KMM case studies, including Cash App, Philips, and Netflix. This success has been attributed to the multiple benefits that KMM offers, such as:

  • Simplified development and release cycles, enabling faster time to market. KMM speeds up the development process by simultaneously building the shared module, iOSApp module, and androidApp module for cross-platform use.
  • Improved platform-independent business logic app sharing. Each target platform’s user interface can be separated, allowing the program to integrate seamlessly into any ecosystem.
  • Easy integration into existing or new projects. The fundamental logic of an existing monolithic Android application can be easily decoupled and migrated to iOS platforms. As a result, even small teams can use KMM to build and maintain reliable and multiplatform applications across a variety of operating systems.

Challenges of KMM

Kotlin Multiplatform Mobile is currently in alpha testing. The newness of this framework means developers may run into some challenges, including those detailed below.

Support Is Limited

KMM currently provides limited community support for component, plugin, and library development, as well as debugging discussion forums. Some of the new KMM plugins are still in alpha or beta testing stages, making them unstable or subject to change in the future. Additionally, there are only a few KMM experts available for hire, compared to those available for more established frameworks.

Teams Must Be Multifunctional

Despite being a cross-platform framework, KMM does not have a solution for every cross-platform issue, especially when shared code is involved. Only the application’s business logic, as previously mentioned, is shared code; all subsequent user interface code must be written specifically for each platform. If the development team only knows Kotlin, you will need to hire extra iOS developers to accomplish cross-functional multiplatform development.

Build Times Are Longer

For years, Gradle's lengthy build process resulted in Android applications experiencing performance difficulties. KMM also suffers from long build times since it continues to compile, build, and test multiplatform applications using the Gradle build tool.

Different platforms supported by Kotlin Multiplatform call for various host operating systems during compilation. Therefore, to complete project unit test cases for both Android and iOS, a typical CI pipeline includes running two distinct pipelines for the shared code module. This requires making independent binaries for iOS and Android. KMM generates an aar and an XCFramework for Android and iOS, respectively, after the CI tests succeed and the new changes are approved. The CD pipeline then distributes them to their relevant artifact repositories.

Typical CI/CD pipeline

Every minor cross-platform code change necessitates the regeneration of the XCFramework binary, which usually causes lengthy build times for iOS developers. The iOS ecosystem’s regular compiles and builds can be exorbitantly expensive as well. The high cost of Apple’s hardware (watchOS, tvOS, iOS, macOS) makes using it pricey. GitHub reports that the cost of running an action on macOS is ten times more than it is on Linux. As a result, you can soon exhaust your allotment, especially if you’re utilizing the free cloud plan.

How Can You Improve KMM CI Build Times?

As seen in the above diagram, setting up a Kotlin Multiplatform CI pipeline can let you build cross-platform applications to Android and iOS. However, the build times are slow and expensive, especially on macOS platforms. Fortunately, you can use a workaround by moving some shared module jobs to cheaper Linux machines. This creates parallelization and modularization, which reduce CI build times.

The following steps demonstrate how to enhance your KMM project’s CI build time. You can check your work against this GitHub repo.

Step 1: Set Up Your KMM Project

First, configure your Kotlin/Multiplatform libraries and project to be published on Maven Central. The sample shared module Gradle build looks like this:

This is a basic multiplatform project set up to work on several OS platforms, including Linux, Android, iOS, watchOS, and JVM. The host platforms are still a concern when it comes to the build time of the CI pipeline, even though the common KMM module may be compiled and published to a central Maven repository. Since there are Apple hardware targets in the Gradle build, every application update automatically causes a build on macOS.

Step 2: Split CI Pipeline Build Hosts

The simplest way to build up a CI/CD pipeline for a KMM project requires two jobs for a single workflow to support each platform. These jobs are executed in succession commands as long as the platform environment is predetermined. You will want to accelerate the CI build process, especially for jobs that run via the macOS target. To achieve this, you must configure Gradle so that the majority of the shared module code executes on Linux, since Android is more tolerant and permits the selection of any SDK into the preset Linux OS environment.

To set up two separate CI build workflows, you can use a specific argument named build target. It accepts the host target type, since its value is supplied as a pipeline parameter from the command line. This allows you to prioritize Linux OS for build publishing and compilation:

The above code works as follows:

  • object SetEnvParams defines the environment parameters to split the host targets.
  • fun KotlinTarget.getHostType(): HostTarget? configures the various Kotlin platforms (androidJvm, JVM, JS, native Android, iOS, watchOS, macOS) before mapping them to the appropriate targets. This ensures that only iOS-specific code is executed by macOS, allowing it to leverage Linux builds.
  • enum class HostTarget sets Linux and macOS as the two primary host platforms.
  • fun KotlinTarget.isCompilationAllowed(): Boolean filters through CI builds to ensure that Kotlin Multiplatform only runs on the predefined operating systems. As a result, the CI build pipeline rules are followed, resulting in a faster build time.

Step 3: Update the Gradle Build

To build this KMM project, update the Gradle build to call the disableCompilationsIfNeeded function so that only the specified target is compiled as defined in the argument:

You have now successfully optimized your CI/CD build pipeline. Your jobs will run concurrently while also prioritizing Linux hardware over the more expensive macOS.

So far, you’ve only learned how to optimize KMM CI builds in compilation mode. The same concept can be applied when publishing the project as well. Other recommendations from Kotlin for optimizing Gradle compilations and CI builds include increasing the Gradle heap size, building only the binaries you need, enabling the Gradle daemon, and using Gradle build caches both locally and remotely.

Modularizing App Changes via CI Configurations

Another way to reduce the time it takes for KMM CI builds is to modularize app changes. To accomplish this, tell the CI pipeline to ignore CI builds for the unaffected platform. As a result, only updates to the shared module will necessitate running CI on both platforms. For this, you can have two distinct, independently running GitHub Actions for iOS and Android.

For instance, the configuration below will run CI changes on iOS track and dismiss Android SDK:

Below is a similar example configuration to ignore IOS CI builds:

Conclusion

Kotlin Multiplatform Mobile offers many strengths to developers, such as multiplatform capability, cost efficiency, and quicker app creation for both native iOS and Android applications. As a relatively recent tool, though, it does also come with some drawbacks.

One of the key challenges of working with KMM is the lengthy build times you may experience when updating changes on the iOS platform. As demonstrated above, the solution is to optimize the CI builds by modularizing the KMM application project.

Despite the complexity and infancy of the KMM framework, companies like Unflow are fully utilizing its advantages. Without writing a single line of code, you can build and distribute native content in the form of screens, flows, and features using the Unflow platform. It enables you to ship your complete schedule without worrying about the engineering of the app store. To get started, register for Unflow and sign up for a demo.

Faith Kilonzi

Faith is a full-stack software engineer with a passion for problem-solving using technology. She is also a technical writer, tech consultant, and DevOps enthusiast. She is currently pursuing a master's degree in big data technologies at the University of East London. She has worked in the ed-tech, healthcare, fintech, research, technology, and consultancy industries in Kenya, Ghana, South Africa, and the United States.

What are you waiting for?

Make apps smarter,
with Unflow

Thanks for your interest!
Something's gone wrong while submitting the form