When wiring androidTarget() in a KMP module, what AGP setup and source-set/configuration details matter for producing a usable AAR (compileSdk, namespace, publishLibraryVariants, dependency configurations, manifest)?
answer
- androidTarget() needs com.android.library + android {} block
- namespace + compileSdk + minSdk required
- androidMain holds Android actuals; commonMain shared
- publishLibraryVariants(...) picks published AAR variants
- androidUnitTest / androidInstrumentedTest test source sets
basics
~20 sYou apply the Android library Gradle plugin, set compileSdk/minSdk and a namespace in the android {} block, and put Android-only code in androidMain. androidTarget() then builds an AAR that an Android app can depend on. You can pick which build variants get published.
solid answer
~40 sandroidTarget() requires the Android Gradle Plugin with com.android.library applied and an android { } block carrying namespace, compileSdk, and defaultConfig.minSdk. Shared code lives in commonMain; Android-specific actuals and Android-API usage go in androidMain. KMP dependency configurations map to Android ones via the source set (androidMain.dependencies { implementation(...) }). To publish, androidTarget { publishLibraryVariants("release", "debug") } controls which variants the AAR exposes. The Android library still needs a manifest (src/androidMain/AndroidManifest.xml), though manifest merging means a minimal one suffices and the package attribute is now replaced by namespace. The produced AAR bundles compiled classes plus resources/manifest and is consumed like any Gradle library. Modern KMP test source sets are androidUnitTest and androidInstrumentedTest.
code
kotlin · 21 linesplugins {
kotlin("multiplatform")
id("com.android.library")
}
kotlin {
androidTarget {
publishLibraryVariants("release", "debug")
}
sourceSets {
androidMain.dependencies {
implementation("androidx.core:core-ktx:1.13.0")
}
}
}
android {
namespace = "com.example.shared"
compileSdk = 35
defaultConfig { minSdk = 24 }
}go deeper
Knows androidMain holds Android code and the module produces an AAR.
Sets up the android {} block (namespace/compileSdk/minSdk) and per-source-set dependencies.
Explains publishLibraryVariants, manifest/namespace handling, test source-set names, and how KMP configs map to AGP.
Standardizes the AAR publishing/variant strategy across modules and reasons about consumer compatibility and minSdk policy.
## Plugin and android {} block `androidTarget()` only works if the **Android Gradle Plugin** is applied. For a shared library you use the **library** plugin: ```kotlin plugins { kotlin("multiplatform") id("com.android.library") } kotlin { androidTarget { publishLibraryVariants("release") // which variants the AAR publishes } iosArm64(); iosSimulatorArm64() } android { namespace = "com.example.shared" // required since AGP 8 compileSdk = 35 defaultConfig { minSdk = 24 } } ``` - **namespace** - required by modern AGP; defines the R class / package. - **compileSdk** - the Android SDK API level you compile against. - **minSdk** - lowest device API level supported. ## Source sets - `commonMain` - shared, platform-agnostic code; `expect` declarations. - `androidMain` - Android-specific `actual` implementations and any code touching the Android SDK (e.g., `android.content.Context`). - Test source sets: `androidUnitTest` (local JVM unit tests) and `androidInstrumentedTest` (on-device/instrumented). These names supersede older `androidTest`/`androidAndroidTest` confusion fixed in newer KMP. Dependencies are declared per source set and map onto Android configurations: ```kotlin sourceSets { androidMain.dependencies { implementation("androidx.core:core-ktx:1.13.0") } } ``` ## Manifest An Android library AAR carries a manifest. Provide `src/androidMain/AndroidManifest.xml`; with AGP 8+ the `package` attribute is replaced by `namespace`, so the manifest can be minimal (`<manifest />`). It merges into consumers via manifest merging. ## Publishing variants - `publishLibraryVariants("release", "debug")` - choose which build variants the published AAR includes; without it, defaults may publish only release or fail to disambiguate. - `publishLibraryVariantsGroupedByFlavor = true` - group multi-flavor outputs. - The resulting **AAR** (Android Archive) packages compiled bytecode + resources + manifest and is consumed by an app module as a normal `implementation(project(":shared"))` or from a Maven repo. ## Why this matters Getting `namespace`/`compileSdk` wrong stops the AAR from building; wrong source-set names silently drop your Android `actual`s; missing `publishLibraryVariants` causes ambiguous-variant publish errors. The Android side is 'just' a Kotlin/JVM target wrapped by AGP, but the AGP wiring is the part teams get wrong.
- What goes in androidMain versus commonMain?commonMain holds shared, platform-agnostic code and expect declarations; androidMain holds the Android actual implementations and any code that touches the Android SDK (Context, etc.).
- What does publishLibraryVariants control?Which Android build variants (release/debug/flavors) the published AAR exposes, preventing ambiguous-variant publish errors.
saying these in an interview costs you the question
- Forgets the Android Gradle Plugin must be applied for androidTarget()
- Omits namespace/compileSdk and assumes it builds
- Puts Android-SDK code in commonMain
- Doesn't know how dependencies map to Android source-set configurations