When using Kotlin Multiplatform, the Kotlin/Native compiler produces a framework for iOS/macOS corresponding to the shared code module (am assuming single module for purposes of this discussion). A number of different approaches are used then to ensure that the XCode project is wired up to use that framework and that it is regenerated whenever an XCode build takes place after the shared code has been updated. These are typically based on use of CocoaPods plugin or custom gradle packForXCode() type task that’s executed from an XCode run script. What’s common in these approaches is that a say iOS developer needs to have access to the shared Kotlin code and a setup to allow building the framework. Generally this is seen as being the preferred way of working (allowing all developers to update and build the shared code as needed). However there are cases where it does make sense for the shared code to be consumed in XCode as a prebuilt binary and one option for that is to publish/consume the code as a Swift Package. In this article I’m going to outline how this was done for PeopleInSpace project using the Multiplatform Swift Package Gradle plugin (note: see update at end of article:)

Update 21st Oct 2022: The really nice KMMBridge tool was recently released by Touchlab and would recommend using that now for generating/publishing Swift Packages as alternative to approach described in this article.

Swift Packages

Swift Packages are a relatively new concept that are described in official documentation as

…reusable components of Swift, Objective-C, Objective-C++, C, or C++ code that developers can use in their projects. They bundle source files, binaries, and resources in a way that’s easy to use in your app’s project.

The above mentioned plugin makes use of the ability provided to distribute binary frameworks as Swift Packages (in particular, what are known as XCFrameworks).

Project setup

To make use of the plugin we added following to build.gradle.kts in the common module

1
id("com.chromaticnoise.multiplatform-swiftpackage") version "2.0.3"

and then added following to set various configuration parameters needed (the plugin README has full list of options available)

1
2
3
4
5
6
7
multiplatformSwiftPackage {
    packageName("PeopleInSpace")
    swiftToolsVersion("5.3")
    targetPlatforms {
        iOS { v("13") }
    }
}

With those updates we can now run ./gradlew createSwiftPackage which will write generated files to common/swiftpackage directory (this can be customised if needed).

Publishing Swift Package to Github

GitHub Packages supports the publication/hosting of Swift Packages. For the purposes of this evaluation we created a separate PeopleInSpacePackage repository to which the artifacts generated by the plugin were pushed. An example of how to do that is shown here. Note also that git tags are used as mechanism to version the published package.

PeopleInSpacePackage Screenshot1

Consume Swift Package in XCode

This article outlines how to add Swift Package dependencies to your XCode project. As we’ve published our package to Github you’ll need to setup associated account in XCode settings. Now when you select “Swift Packages/Add Package Dependency…” from File menu you’ll see likes of following allowing you to select/add PeopleInSpacePackage package.

XCode package Screenshot1

XCode package Screenshot2

We can now import the associated module in our Swift code and start making use of our Kotlin Multiplatform shared code!

Update Jan 24th 2020: Also created Swift Package for Bike Share

Note: if you’re having problems with package name to use in import in Swift code then you might be running in to this issue


Featured in Kotlin Weekly Issue #234 and Android Weekly Issue #450


Update September 17th 2022: The Multiplatform Swift Package library mentioned above is no longer being maintained and in particular is missing M1 support. However a fork has been created which adds this support and also is publishing artefacts that include those updates. More info here.