This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
# Build entire project
./gradlew build
# Build specific module
./gradlew :library:getbackcompose-core:build
./gradlew :examples:simple-app:sample:app:assembleDebug
# Run tests (foundation module has commonTest)
./gradlew :library:getbackcompose-foundation:allTests
./gradlew :library:getbackcompose-foundation:jvmTest # JVM only
# Run desktop apps
./gradlew :examples:simple-app:sample:desktop:run
./gradlew :examples:metro-app:sample:desktop:run
# Run wasmJs apps (opens browser)
./gradlew :examples:simple-app:sample:wasmJs:wasmJsBrowserDevelopmentRun
./gradlew :examples:metro-app:sample:wasmJs:wasmJsBrowserDevelopmentRun
# Build iOS frameworks (used by Xcode build phase)
./gradlew :examples:simple-app:sample:ios:embedAndSignAppleFrameworkForXcode
./gradlew :examples:metro-app:sample:ios:embedAndSignAppleFrameworkForXcode
# Compile check for a specific target
./gradlew :examples:metro-app:sample:ios:compileKotlinIosSimulatorArm64iOS apps are built via Xcode projects at examples/*/sample/iosApp/iosApp.xcodeproj.
GetBack Compose is a KMP navigation library built on a four-layer scope model instead of AndroidX Navigation's lifecycle-based approach:
- Render Scope — Compose's
remember{}recomposition (not managed by this library) - View Scope —
CoroutineScopeinonViewAppear(), cancels when view is hidden (pushed over), restarts when visible again - ViewProvider Scope — Lives as long as the navigation entry exists, survives being hidden
- ManagedCoroutineScope — Ref-counted hierarchical scopes, cancels when all consumers release
Key difference from AndroidX: scopes cancel on visibility change, not Android lifecycle transitions.
ViewProvider— Factory that creates aViewwhen it becomes visible. Receives a freshCoroutineScopeper appearance.View— Stable wrapper around@Composablecontent with a scope reference.VisibilityScopedView— Manages aCoroutineScopetied to view visibility. The cross-platform entry point for hosting compose content.NavigationStack<V>— Push/pop navigation. Routes carry full typed objects (not serialized IDs).ViewSwitcher<K>— Tab-like switching.RetainingScopeViewSwitcherretains state per tab;SingleScopeViewSwitchershares one scope.ManagedCoroutineScope— Hierarchical scope withcreate("childName")for named children and automatic ref-count cleanup.Screen— CombinesViewProvider+ViewPresentation(fullscreen or modal).
| Module | Purpose |
|---|---|
getbackcompose-foundation |
Coroutine utilities, ManagedCoroutineScope, CoroutineScopeFactory |
getbackcompose-core |
ViewProvider, View, VisibilityScopedView, ViewContext |
getbackcompose-compose |
ViewModel base class, StateProvider, state observation, modal surface |
getbackcompose-navigation-stack |
NavigationStack, NavigationStackHost, route factories |
getbackcompose-navigation-switcher |
ViewSwitcher, ViewSwitcherHost, tab retention |
getbackcompose-navigation-multidisplay |
Multi-slot navigation (top bar / content / bottom bar) |
getbackcompose-lifecycle |
AndroidX Lifecycle integration (Android-only, optional) |
getbackcompose-activity |
ViewModelComponentActivity, Android Activity integration |
getbackcompose-foundation-test |
TestScopeRule, TestFlow, FlowMock (JVM-only) |
All library modules target: Android, Desktop (JVM), iOS (x64/arm64/simulator), JS (IR), WasmJs.
Exceptions: getbackcompose-lifecycle and getbackcompose-activity are Android-only.
Three apps demonstrate different DI strategies with identical feature sets:
| App | DI Approach | Platforms |
|---|---|---|
| simple-app | Manual constructor injection | Android, Desktop, iOS, WasmJs |
| metro-app | Metro (KMP DI by Zac Sweers) | Android, Desktop, iOS, WasmJs |
| dagger-app | Dagger 2 | Android only |
Shared business logic lives in examples/shared/sample/core/{auth,data} — used by both simple-app and metro-app. Platform-specific Ktor engines use expect/actual in PlatformEngine.kt (Android, Darwin, Java, Js, WasmJs).
- Android:
ViewModelComponentActivitysubclass inappmodule - Desktop:
main()withapplication { Window { VisibilityScopedView(...) } } - iOS:
MainViewController()returningComposeUIViewController { VisibilityScopedView(...) } - WasmJs:
main()withComposeViewport(document.body!!) { VisibilityScopedView(...) }
Non-Android platforms use ViewContext.EMPTY (always-foreground context).
- Kotlin 2.3.10, Compose Multiplatform 1.10.2
- Ktor 3.4.1 (HTTP clients per platform)
- Metro 0.11.2 (KMP DI, metro-app only)
- Dagger 2.59.2 (dagger-app only)
- Atomicfu (multiplatform synchronization primitives)
- Coil 3.4.0 (KMP image loading in shared modules)
- Kermit (multiplatform logging)
Published to Maven Central via the vanniktech gradle-maven-publish-plugin.
# Publish to local Maven (~/.m2) for testing
./gradlew publishToMavenLocal
# Publish to Maven Central (requires credentials)
./gradlew publishAndReleaseToMavenCentralGroup: com.getbackcompose, version configured in root gradle.properties.
POM metadata (license, SCM, developer) also in root gradle.properties.
Per-module artifact IDs and descriptions in each module's gradle.properties.
Signing is disabled by default (RELEASE_SIGNING_ENABLED=false in root gradle.properties). Override for release builds.
Required in ~/.gradle/gradle.properties for Maven Central publishing:
mavenCentralUsername=<sonatype-username>
mavenCentralPassword=<sonatype-password>
signing.keyId=<gpg-key-id>
signing.password=<gpg-passphrase>
signing.secretKeyRingFile=<path-to-secring.gpg>- Library modules have zero AndroidX dependencies in core (Android-specific modules are opt-in)
- Navigation routes are sealed types/enums implementing
ViewKey— no string-based routing - Factories pass full objects, not serialized primitives or IDs
@Volatilein commonMain uses@kotlin.concurrent.Volatile(notjava.lang.Volatile)- Thread safety uses atomicfu
SynchronizedObject+synchronized(this)(not JVMsynchronized) - Project-wide opt-ins configured in root
build.gradle.kts:ExperimentalUuidApi,ExperimentalAtomicApi - Gradle version catalog (
libs.versions.toml) with typesafe project accessors