KMMBridge CocoaPods Quick Start
While KMMBridge does support CocoaPods, we generally recommend using SPM whenever possible with KMMBridge. With CocoaPods there’s more complexity, more room for failure and less support as the world is moving towards SPM. While CocoaPods is still supported, we rarely use it for our client projects at this point. Some docs may be out of date, so please reach out if you find anything that seems off.
Configuring KMMBridge from scratch is complex. That is because configuring XCFramework publications is complex. There are many points of access and resource configuration necessary.
If you are using GitHub, however, we have built a template project to make this process simple.
We have another “CocoaPods Quick Start” from the KMMBridge 0.5.x releases. If you are currently using KMMBridge from the 0.5.x era, please note several features have been simplified and/or removed. When upgrading, please carefully review your workflow script changes.
Publishing to CocoaPods requires a few steps, this is because CocoaPods keeps it’s dependency info in a separate git repo. That means you will need to:
- Create (or have access to) a GitHub repo dedicated to storing CocoaPods version information.
- Configure CI with an SSH key info to be able to push to that repo.
- Configure your clients to be able to access that repo (if not public).
CocoaPods publishes Podspec config info to a separate repo. This repo only holds config information. It does not host your binaries. The XCFramework binary files are pushed to the GitHub Releases of your KMP library repo.
Create a KMP Repo
Open up our GitHub template repo
From the GitHub page, click “Use this template”, and create a repo in your org.
“Use this template” screenshot
This repo can be public or private. Private repos will allow you to control access through GitHub.
Change the GROUP value
Open gradle.progperties
and change the value of GROUP to something that doesn’t start with co.touchlab
.
GROUP=com.yourorg.yourrepo
Why GROUP needs to be changed
This only matters for GitHub Packages, which has historically had issues with conflicting maven “coordinates”, even though they are in separate GitHub Package repos. It’s not super important to have your domain, but our workflow checks and fails the build if it starts with co.touchlab
.
Set your build version
Your builds publish with a version. That is controlled by LIBRARY_VERSION
in gradle.properties
. Whenever you publish, be sure to update that value first.
The value currently in the template should work, but I’d suggest changing it to:
LIBRARY_VERSION=0.1.0
Make sure to commit and push that change.
Create a Podspec Repo
CocoaPods keeps it’s config info, called “Podspecs”, in a separate git repo. In our case, this means you’ll want to create a new empty repo on GitHub.
Create a repo in your org. We’ll call ours “Podspecs”. It can be public or private.
Important! Add at least one commit to this repo. The easiest option is to create a README. The CocoaPods process won’t push without an existing commit.
Next, you’ll need to enable access between these repos and our CI build workflow.
Pointing Your KMP Library to the Podspec Repo
In order to correctly have KMMBridge export the Podspecs for your library, you need to update the allshared/build.gradle.kts
file to point to the new repo.
kmmbridge {
// Must be the SSH url
cocoapods("git@github.com:YOUR_ORG/YOUR_PODSPEC_REPO.git")
}
Make sure to use the SSH form of git remote URL rather than the https form.
Adding Deploy Keys
In order grant CI access to your repos you’ll need to add deploy keys. This can be done manually via the command line and GitHub, however for convenience we’ve added a gradle task called setupDeployKeys
to help automate the process. For more details about setupDeployKeys
see the docs.
./gradlew setupDeployKeys --no-configuration-cache \
-PgithubDeploySourceRepo=YOUR_ORG/YOUR_KMP_REPO \
-PgithubDeployTargetRepo=YOUR_ORG/YOUR_PODSPEC_REPO
If you get the error
Task 'setupDeployKeys' not found in root project 'YOUR_PROJECT' and its subprojects.
this means that these properties were not set up correctly.
If you want you can double-check that this task succeeded by checking your two repos:
- In your KMP repo click on the “Settings” tab, then go to “Secrets and Variables” -> “Actions”. You should see
KMMBRIDGE_SSH_KEY
. - In your podspec repo click on the “Settings” tab, then go to “Deploy Keys”. You should see
KMMBridge Key
.
Publish your iOS Binaries
If you have a free GitHub account…
Then you will need to set one additional setting in GitHub. By default paid accounts have actions set up to read/write, but for some reason free accounts default to read-only. You’ll need to update your repos settings.
Go to your KMP library repo and click the “Settings” tab. Then select actions -> general. Under workflow permissions select “Read and Write permissions”.
Make sure you’ve committed your changes, then open your new KMP repo (not the Podspec repo) in GitHub, then open the “Actions” tab. Find “KMMBridge iOS Publish” in the list of Workflows.
“Actions” tab screenshot
Look for “Run workflow”. Leave the branch default (main), and click the green “Run workflow” button.
“Run workflow” screenshot
⏳ Wait (~15 minutes)…
The workflow will build 3 release binaries for iOS. This can take a fair bit of time. Usually around 15 minutes.
Some Highlights (while we’re waiting)
While your build is running, let’s take a few minutes to highlight important parts of the source and configuration for your new repo.
If you want to skip ahead go to Check Your Build
Android Publication
You can also publish Android AAR dependencies from the KMP repo.
Assuming you ran the iOS publication step above, you’ll need to bump the version in gradle.properties
:
LIBRARY_VERSION=0.1.1
Look for “KMMBridge Android and iOS Publish” in the GitHub Actions workflow list and run that instead of “KMMBridge iOS Publish” that we used earlier. That will publish iOS binaries, but also Android binaries.
The Android dependencies will publish to GitHub Packages. That is a maven repo, so you can add them from Gradle in your Android project.
Code Modules
The code in the sample is essentially the code in our KaMP Kit KMP sample app, but split out into an external “SDK” format. For your own code, you should replace the sample modules and packaging with whatever your project needs. The sample intends to show several libraries and a few basic features fully implemented.
analytics
This is a “typed” analytics library. The idea is that analytics is critical to many apps, but most analytics libraries are just “maps of strings” that marketing people put in a spreadsheet. Implementing and maintaining these values correctly across platforms is critical, but very difficult to verify. There’s also no “joy” for the developers. They never get to see the outcome. It’s just a tedious coding chore that nobody enjoys.
Having an analytics library with typed and named function calls is a method some teams use to improve analytics maintenance.
Because these functions are intended to be called directly from Swift, this whole module is exported to the Xcode framework. See allshared/build.gradle.kts
:
cocoapods {
...
framework {
export(project(":analytics")) // <-- This line
isStatic = true
}
}
breeds
This module provides the “data” of the app. It calls the Dog CEO REST API to get a list of dog breeds and images for those breeds. The module uses Ktor for network calls, SQLDelight for local storage, and various other architectural structures to manage everything.
This module is not exported for a few reasons. The majority of the code is not called directly from Swift. The entry points are provided in allshared
. Also, SQLDelight generates Kotlin code, which includes references to parts of the SQLDelight library that Swift definitely doesn’t need. There’s no way to make that generated code “internal”, so “hiding” it inside another module is a common approach to API surface hygiene.
allshared
This is the Xcode framework “umbrella” module. There is no Android code here. The build.gradle.kts
file configures the Xcode framework structure, and the Kotlin code provides structured SDK initialization specific to iOS.
This is the module that KMMBridge is configured to publish from.
testapps
These are not intended to be “sample apps” for this tutorial. A helpful option for separate KMP repos is to have local test apps that you can run and build the KMP code directly with. It is not required to do this, but depending on your setup, you may find them useful. Both apps are configured to build the code locally.
To build and run the KMP code locally with your iOS app code, see CocoaPods Local Dev
✋ Check your build
Go back to the GitHub Actions page to check on your build. If done, continue to the next steps. If the build failed, here are some possible causes:
The GROUP value wasn’t changed, or the change wasn’t pushed. The build will fail at “Touchlab Sample Sanity Check”
“Sanity check error” screenshot
The build was run more than once If the release exists, the build will fail.
For other issues, reach out or file an issue in the quick start template repo.
👍 Next Steps
If the build succeeded, you should see a new release on your repo GitHub page.
Xcode Integration
Now that the build is complete you can try integrating it.
Go to touchlab/KMMBridgeCocoaPodsQuickStart-iOS and create another repo using that template (or just clone it, if you don’t plan on starting with it).
GitHub Access
GitHub requires you to authenticate to download binary files from private repos. If your podspec and shared repos are set to be private you will need access from your computer (Public repos do not need special access). Adding this authentication is not complex, but if any of the steps are incorrect, Xcode and CocoaPods aren’t very helpful explaining what went wrong. Make sure you double-check everything.
For access to private repos, go to GitHub and create a Personal Access Token. Go to your user settings -> “Developer settings” -> “Personal access tokens” -> “Fine-grained tokens” and click “Generate new token”. Under repository access select whether you want access to all your projects or choose “only selected repositories”. Either way be sure that both your podspec repo and your source shared repo have access.
Under the Permissions select “Repository permissions” -> “Contents” and add “read-only” access.
GitHub screenshot
After the token is created, make sure to get and keep a copy of the token string. We’ll need to add it in a few places.
You could also use a classic token to access the repo if you prefer. For the classic token you want to select the “repo” scope.
Artifact Authentication
To use your newly generated token on your computer, create or open the file ~/.netrc
. This provides “curl” and other tools with authentication information.
touch ~/.netrc
open ~/.netrc
Add the following to the file:
machine api.github.com
login <GitHub User>
password <PAT>
The login is your GitHub username, and the password is the same PAT we created earlier. Save the file and exit.
Adding the library
To add the library using CocoaPods first open the Podfile
, and update the source with your Podspec repo.
platform :ios, '16'
source 'https://github.com/YOUR_ORG/YOUR_PODSPEC_REPO.git' # <- this line
target 'ios' do
...
end
Then after that run pod install
from CI and wait until the operation succeeds. If there is a failure check your source url and that your artifact authentication is correctly setup.
You may notice in the Podfile
that there’s a check for LOCAL_KOTLIN_PATH
, this is for local development support. You can find out more in the documentation
Starting the project
Open ios.xcworkspace
, either directly with Xcode or by opening it from a terminal.
To open from the terminal, cd to the directory you just cloned and run:
open ios.xcworkspace
In Xcode, make sure you have an iPhone simulator selected, then click the “Run” button.
Android Publication
You can publish both iOS and Android binaries by running the “KMMBridge Android and iOS Publish” action in the GitHub Actions panel. With our template as it is currently configured, the Xcode XCFramework binaries are attached to the GitHub release that is created, while the Android dependencies are published to GitHub packages.
Very Important: First open gradle.properties
and change LIBRARY_VERSION
to 0.1.1
. Add/commit/push in git.
Now go back to the “Actions” tab on the GitHub repo page, and run “KMMBridge Android and iOS Publish”.
This will also take around 15 minutes, or possibly more with the additional publications.
Clone the Android Sample
Open our Android sample repo. You can either use it as a template, or clone it directly.
While this repo references “SPM”, it should work for both SPM and CocoaPods.
Add the maven repo
In the Android sample project, open settings.gradle.kts
. Find dependencyResolutionManagement
at line 9. Change the uri to point to your KMP library repo:
dependencyResolutionManagement {
val GITHUB_PACKAGES_USERNAME: String by settings
val GITHUB_PACKAGES_PASSWORD: String by settings
@Suppress("UnstableApiUsage")
repositories {
google()
mavenCentral()
maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/touchlab/KMMBridgeCocoaPodsQuickStart") // <-- Change this
credentials {
username = GITHUB_PACKAGES_USERNAME
password = GITHUB_PACKAGES_PASSWORD
}
}
}
}
You’ll also need to supply GitHub auth info, similar to the way we did for Xcode. This is also true for public repos, for the same reasons.
Each user will need their own credentials. To do that, we reference Gradle properties in the build file. For each user, those values are set in the global Gradle properties file. Open or create ~/.gradle/gradle.properties
. Your GitHub username is your actual username. The “password” is the PAT we created earlier:
GITHUB_PACKAGES_USERNAME=[GitHub username]
GITHUB_PACKAGES_PASSWORD=[Your PAT]
Add the new dependencies
Open gradle/libs.versions.toml
. Find sharedlib-analytics
on line 66. Change sharedlib-analytics
and sharedlib-breeds
to match the GROUP value from your KMP library.
sharedlib-analytics = { module = "[your GROUP]:analytics-android-debug", version.ref = "sharedlib" }
sharedlib-breeds = { module = "[your GROUP]:breeds-android-debug", version.ref = "sharedlib" }
Find sharedlib =
on line 24. This is the version of your KMP library. Right now, that should be set to 0.1.1
, but when you make future builds, this is what you’ll update.
sharedlib = "0.1.1"
If all is configured correctly, reload Gradle, and run the app!
Next Steps
The template is meant as a starting point. Rip out our sample code and add some of your own.
If you use a different CI, or need to publish to other locations, you can still use KMMBridge. It is meant to be easily extended. Be prepared, though, that any production build config can be complex, and Xcode builds are no exception. We’ve also found that the people setting up the KMP builds are usually familiar with Android and Gradle. Less so with Xcode and CocoaPods. We would highly encourage you to recruit help from your iOS team.
- Create a KMP Repo
- Change the GROUP value
- Set your build version
- Create a Podspec Repo
- Pointing Your KMP Library to the Podspec Repo
- Adding Deploy Keys
- Publish your iOS Binaries
- ⏳ Wait (~15 minutes)…
- Faster CI Builds
- Some Highlights (while we’re waiting)
- Android Publication
- Code Modules
- Only expose what you need
- ✋ Check your build
- 👍 Next Steps
- Xcode Integration
- GitHub Access
- Artifact Authentication
- Adding the library
- Starting the project
- Android Publication
- Clone the Android Sample
- Add the maven repo
- Add the new dependencies
- Next Steps