Using Swift Package Manager
Swift Package Manager is a newer dependency manager directly from Apple. In some ways it's more integrated into Xcode, but is also less flexible than CocoaPods. Much of that seems by design, as it's very difficult to introduce side effects into the Package.swift
build scripts. While that is likely to result in more reliable builds for the average Xcode project, for Kotlin builds, that means some more manual processes at present.
Out of the box, the official Kotlin tools are far less integrated into SPM. We have some basic support for SPM development, but this is a work in progress. Feedback welcome.
Kotlin Project Configuration
After setting up KMMBridge in your Kotlin project, you should configure SPM for library publishing. Generally speaking, SPM wants to have the Package.swift
file in the root of the repo. Xcode and SPM use Git repos as an organizational and discovery unit. The Package.swift
file goes in the root, and Xcode clones from GitHub (or others) to read info about the library and source code.
If you don't have a Package.swift
file, or don't know how to set one up, that's OK. KMMBridge currently generates these files for you.
In the kmmbridge
block, add spm()
. If you call it without parameters, KMMBridge assumes you want the Package.swift
file at the root of your repo (we also assume you're using Git. We're not sure you could use SPM to deploy without Git).
kmmbridge {
spm()
// Other config...
}
In the example above, the Kotlin module is one folder down. The spm()
setup detects that with git automatically.
SPM uses Git for versioning. Your publication process will need to add tags to your repo as builds are published so that SPM can find those builds. Our Default GitHub Flow handles versioning automatically.
If you are configuring KMMBridge on your own, be aware that you need to set the Gradle version
property correctly, or provide a different way for KMMBridge's SPM support to get a version for publishing (see Configuration Overview - VersionManager)
Specifying swift tools version
You can use the swiftToolsVersion
parameter to set the swift tools version that will be written to the Package.swift header. If no value is provided, version 5.3 will be used by default:
kmmbridge {
...
spm(swiftToolVersion = "5.8")
}
Specifying target platforms and versions
You can use the targetPlatforms
lambda to add a targets and versions. Currently, only iOS target is supported:
kmmbridge {
...
spm {
iOS { v("14") }
macOS { v("12") }
}
}
Using a custom package file
By default, KMMBridge fully manages your Package.swift file. This might not be what you want, if your published library needs to include more than just your Kotlin framework. If you need to customize your package file, pass the useCustomPackageFile
flag when configuring SPM in KMMBridge:
kmmbridge {
...
spm(useCustomPackageFile = true)
}
When this flag is set, rather than regenerating your entire package file during publication, KMMBridge will only update the variables it sets at the top of the package file. You are now responsible for using them correctly when making changes.
This works by replacing a block of code that begins with the comment // BEGIN KMMBRIDGE VARIABLES BLOCK (do not edit)
and ends with the comment // END KMMBRIDGE BLOCK
.
The custom package file mode is new and experimental. The local dev flow using the spmDevBuild
gradle task is disabled when useCustomPackageFile
is true.
Exporting multiple frameworks
By default, KMMBridge manages the Package.swift file considering that you have only Kotlin Module being exposed as a Swift Framework. If that's not your case, and you have more modules compiling Frameworks, you can use the perModuleVariablesBlock
flag together with the useCustomPackageFile
.
kmmbridge {
...
spm(useCustomPackageFile = true, perModuleVariablesBlock = true)
}
When set, it will modify the configuration block from KMMBridge to include the Framework name, so it can support multiple frameworks:
///// Before
// BEGIN KMMBRIDGE VARIABLES BLOCK (do not edit)
let remoteKotlinUrl = "https://www.example.com/"
let remoteKotlinChecksum = "01234567890abcdef"
let packageName = "TestPackage"
// END KMMBRIDGE BLOCK
///// After
// BEGIN KMMBRIDGE VARIABLES BLOCK FOR 'TestPackage' (do not edit)
let remoteTestPackageUrl = "https://www.example.com/"
let remoteTestPackageChecksum = "fedcba9876543210"
let testPackagePackageName = "TestPackage"
// END KMMBRIDGE BLOCK FOR 'TestPackage'
// BEGIN KMMBRIDGE VARIABLES BLOCK FOR 'TestPackage2' (do not edit)
let remoteTest2PackageUrl = "https://www.example.com/"
let remoteTestPackage2Checksum = "01234567890abcdeg"
let testPackage2PackageName = "TestPackage2"
// END KMMBRIDGE BLOCK FOR 'TestPackage2'
Artifact Authentication
For artifacts that are kept in private storage, you may need to add authentication information so your ~/.netrc
file or your Mac's Keychain Access. See the section here for a description of how to set up private file access.
When publishing to GitHub Packages, be aware of a few issues. First, GitHub Packages requires authentication for accessing files in all repos, public or private. You need to add ~/.netrc
or Mac Keychain Access authentication info for any user accessing these repos. Also, if your repo is private, you'll need to authenticate to GitHub in Xcode to add it (see below), but you still also need to set up ~/.netrc
or Mac Keychain Access for SPM to grab the binary.
Xcode Configuration
Open or create an Xcode project. To add an SPM package, go to File > Add Packages
in the Xcode menu. Add your source control account (presumably GitHub). You can usually browse for the package at that point, but depending on how many repos you have, it may be easier to copy/paste the repo URL in the top/right search bar. After finding the package, you should generally add the pacakge by version ("Up to Next Major Version" suggested).
The Xcode configuration can be confusing here. You need to authenticate to GitHub through the Xcode UI if you have a private GitHub repo. You will still need to set up authentication for SPM to access the actual packages with ~/.netrc
. This has been the primary source of issues when people set up KMMBridge!!!
Once added, you should be able to import the Kotlin module into Swift/Objc files and build!
Updating Builds
Run the KMMBridge build again. It should automatically create another build version and publish that to the GitHub repo. In Xcode, you can update your imported version by right-clicking on the module and selecting "Update Package":
Local Kotlin Dev
If you are going to locally build and test Kotlin with SPM, see IOS_LOCAL_DEV_SPM.