Mobile App Development with KMP × Unity UaaL ── Multi-Repo Setup and Automation
Hi! We’re the AnotherBall Mobile Engineering Team.
Our app “Avvy” has a somewhat complex architecture: we use KMP (Kotlin Multiplatform) to share business logic across iOS and Android, and Unity as a Library (UaaL) to embed Unity’s 2D avatar rendering into our native apps.
In this article, we’ll share how we coordinate five repositories and how much we’ve automated with GitHub Actions.
Repository Structure
To avoid build complexity and inter-team dependencies, we split our codebase by function into separate repositories.
| Repository | Role | Artifacts |
|---|---|---|
shared-kmm |
Business logic | AAR / XCFramework (KMP library) |
unity-module |
2D avatar rendering | UaaL libraries for Android / iOS |
android-app |
Android app | APK / AAB |
ios-app |
iOS app | IPA |
unity-spm |
SPM distribution for Unity XCFramework | Swift Package |
Each repository communicates through pre-built libraries—AAR for Android and XCFramework for iOS. This allows each team to work independently.
What the Unity Module Does
The Unity module handles avatar display and real-time control.
- Avatar display: Renders avatars with 2D animation
- Face tracking: Detects facial movements via camera and reflects them on the avatar
- Customization: Outfit and accessory changes
Communication with native apps requires special handling. Face tracking sends data 60 times per second, so standard bridges would cause latency. On iOS, we use direct pointer access; on Android, we use memory-mapped files for fast data exchange.
How We Automated It
We use GitHub Actions to automate most of the cross-repository coordination. About 1,200 PRs are processed automatically each month (December 2025 figures).
Server API Changes
When the server’s API definition file (OpenAPI) is updated, an update PR is automatically created in the KMP repository.
KMP Library Updates
From KMP library release to update PR creation in each app repository—everything is automated.
The flow is simple: Publish → Trigger → Update.
- When a release is triggered in
shared-kmm, it publishes to GitHub Packages - On success,
gh workflow runtriggers the update workflow in each app repository - Each app gets an auto-generated PR with the version update
1 | # On KMP release (excerpt) |
1 | # Android app update workflow (excerpt) |
Unity Library Distribution
To use Unity modules in the iOS app, we distribute them via SPM (Swift Package Manager).
- Build the Unity XCFramework and upload it to GitHub Releases
- Calculate a hash value for the file
- Auto-generate Package.swift (embedding the download URL and hash)
- Create a PR in the distribution repository (unity-spm)
While we could distribute directly from the unity-module repository, Xcode downloads the entire repository when resolving SPM packages. By creating a separate unity-spm repository that contains only Package.swift, we significantly speed up the download process.
The hash value lets the iOS app verify the file wasn’t corrupted during download.
Auto-Generated Release Branch PRs
When changes are pushed to a release/* branch, multiple merge PRs are automatically created:
release/2.10.0→main(for production release)release/2.10.0→release/2.11.0(to propagate bug fixes to the next version)
Version numbers are compared to determine the appropriate merge targets, preventing missed merges.
Package.resolved Conflict Resolution (iOS)
When multiple KMM/UaaL update PRs exist simultaneously, Package.resolved file conflicts occur. In the iOS repository, we have a workflow that automatically resolves these conflicts.
Trigger: Push to release/* branch
How it works:
- Fetch open PRs targeting the release branch via GitHub API
- Filter PRs with titles starting with
chore: update KMMorchore: update UaaL - Check if each PR can be merged, and identify those with conflicts
- Resolve conflicts for each PR
1 | # Attempt to merge base branch |
The key is make resolve-package-dependencies (which runs xcodebuild -resolvePackageDependencies internally), re-resolving dependencies including target branch changes. When multiple PRs have conflicts, they’re processed in parallel.
Remaining Challenges
- CI/CD execution time: Gradle/Xcodebuild can take 40+ minutes; we’re looking into better caching strategies
- Workflow duplication: Similar logic exists in multiple workflow files; we want to extract it into reusable components
- Auto-merging update PRs: Currently we only auto-create PRs; we’d like to auto-merge when tests pass
Conclusion
Even with a complex setup combining KMP and Unity UaaL, separating repositories and communicating through artifacts lets each team work independently. We’ve learned that automation isn’t a one-time setup—it requires ongoing improvement.
We’re Hiring
AnotherBall is looking for mobile engineers interested in app development using Kotlin/Swift/Unity/AI!
We’re seeking teammates to grow our product together while adopting new technologies like KMP. If you’re interested, we’d love to hear from you!