SplitForge is a local-first split planner for hybrid race training. Build run + station templates, plan solo or doubles strategies, and see live time estimates. Pro unlock adds auto-split suggestions, export/share, and what-if deltas.
- Kotlin Multiplatform + Compose Multiplatform
- MVVM + StateFlow
- Persistence: Multiplatform Settings (single AppState JSON)
- Serialization: kotlinx.serialization
- IAP: RevenueCat purchases-kmp-core (one-time Pro entitlement)
- Kotlin: 2.2.10
- Compose Multiplatform: 1.10.0
- Android Gradle Plugin: 9.0.0
- Gradle distribution: 8.11.1
- Coroutines: 1.10.1
- Serialization: 1.8.0
- Multiplatform Settings: 1.3.0
- RevenueCat purchases-kmp-core: 2.2.3+17.11.0
Reasoning: these versions are stable, widely compatible, and align with AGP 9 + Kotlin 2.2 + Compose MPP 1.10.
- JDK 17
- Android Studio (for Android)
- Xcode 15+ (for iOS)
- macOS for iOS builds
curlorwgetandunzip(the local Gradle wrapper script downloads Gradle)
./scripts/bootstrap.shFrom repo root:
./gradlew test
./gradlew :androidApp:assembleDebug
./gradlew :androidApp:lint- Open
iosApp/iosApp.xcodeprojin Xcode - Select scheme
iosApp - Build for any iPhone simulator
From repo root:
xcodebuild -project iosApp/iosApp.xcodeproj -scheme iosApp -configuration Debug -sdk iphonesimulator -destination 'generic/platform=iOS Simulator' buildThe app runs without keys using a no-op billing implementation.
Add this to local.properties (not committed):
REVENUECAT_API_KEY=your_android_public_api_key
Set the key in:
iosApp/Configs/Debug.xcconfigiosApp/Configs/Release.xcconfig
REVENUECAT_API_KEY = your_ios_public_api_key
Entitlement id: pro
Offering id: default
./gradlew ktlintCheck
./gradlew ktlintFormat- Update
CHANGELOG.md - Verify localization EN/FR
- Set RevenueCat keys in CI/Release builds
- Run Android release build and lint
- Build iOS release in Xcode
- Validate Pro purchase + restore
- Export/share summary image on both platforms
See:
docs/PRIVACY_POLICY_EN.mddocs/PRIVACY_POLICY_FR.md
- No accounts, analytics, or ads.
- Brand safety: no trademarked event names used.