Skip to content

Generate protos into commonMain for multiplatform projects with an Android target - #3698

Draft
oldergod wants to merge 1 commit into
masterfrom
bquenaudon/kmp-android-source-roots
Draft

Generate protos into commonMain for multiplatform projects with an Android target#3698
oldergod wants to merge 1 commit into
masterfrom
bquenaudon/kmp-android-source-roots

Conversation

@oldergod

Copy link
Copy Markdown
Member

Fixes #3688.

Problem

Since 6.0.0-alpha02, a Kotlin multiplatform project with an Android target gets no generateCommonMainProtos task. Wire generates into the Android variants only (generateDebugProtos, generateReleaseProtos). commonMain and every non-Android target see no generated code. In 5.5.0, Wire generated once into commonMain and every target consumed it.

The trigger is the Android target: com.android.library plus androidTarget(). A multiplatform project without an Android plugin is not affected. The issue's wire block alone does not reproduce; the Android target does.

Root cause, two parts

  1. Refactor to Factory pattern and use modern Android Variant API #3503 (6.0.0-alpha02) flipped the detection order in SourceRoots.kt. forEachWireSource checks hasAndroid before the Kotlin multiplatform arm. Any project with an Android plugin is treated as an Android-only project.
  2. The same rewrite also removed the afterEvaluate deferral that 5.5.0 used for Android projects. applyWirePlugin() now runs at android-plugin-apply time, before the build script evaluates the wire {} block. The Android path tolerates this because onVariants defers its callbacks. The multiplatform path reads extension.outputs eagerly, so reordering the arms alone wires nothing into the compilations.

Fix

  • SourceRoots.kt: the Kotlin multiplatform arm now precedes the hasAndroid arm. This restores the 5.5.0 semantics: generate once into commonMain, the Android target consumes commonMain like every other target.
  • WirePlugin.kt: when the KotlinMultiplatformExtension is present at android-plugin-apply time, the android handler defers applyWirePlugin() to afterEvaluate. This path does not use the Android variant API, so the deferral is safe, and the wire {} block is evaluated by then. Pure Android projects keep the synchronous call that onVariants requires.

Known limit: if the build script declares com.squareup.wire and the Android plugin before kotlin("multiplatform"), the extension is not visible yet when the android handler runs, and Wire still takes the Android path. Declaring the Kotlin plugin first, the common convention, works.

Test coverage

CI never caught this because the only multiplatform fixture has no Android target. This PR adds the kotlin-multiplatform-android fixture (KMP, com.android.library, androidTarget(), jvm) and a kotlinMultiplatformWithAndroidTarget test. The test asserts generateCommonMainProtos exists, no per-variant generate task exists, and assemble compiles the generated code.

Verification

  • The new test fails on master without the fix (assertion: :generateCommonMainProtos is null) and passes with it.
  • Full :wire-gradle-plugin:test suite green locally, test task forced fresh (--rerun --no-build-cache): 104 tests, 0 failures, 5 pre-existing ignores.
  • End to end: the reproducer from the issue (two sourcePath blocks, google-common-protos srcJar, protovalidate protoPath, jvm + js + androidTarget) against a locally published plugin. generateCommonMainProtos is back, 12 files generate into the commonMain output, and compileKotlinJvm, compileKotlinJs, compileDebugKotlinAndroid, and compileReleaseKotlinAndroid all compile them.

…droid target

Since 6.0.0-alpha02, a Kotlin multiplatform project with an Android
target gets no generateCommonMainProtos task. Wire generates into the
Android variants only, and commonMain plus every non-Android target
see no generated code.

Two causes, both from the #3503 rewrite. First, forEachWireSource
checks hasAndroid before the Kotlin multiplatform arm, so any project
with an Android plugin takes the Android path. Second, the rewrite
removed the afterEvaluate deferral for Android projects. The setup now
runs at android-plugin-apply time, before the build script evaluates
the wire {} block. The Android path tolerates this because onVariants
defers its callbacks. The multiplatform path reads extension.outputs
eagerly, so it would wire nothing into the compilations.

Fix both: the multiplatform arm now precedes the hasAndroid arm, and
the android handler defers applyWirePlugin to afterEvaluate when the
KotlinMultiplatformExtension is present. That path does not use the
Android variant API, so the deferral is safe. Pure Android projects
keep the synchronous call that onVariants requires.

Add the kotlin-multiplatform-android fixture. The only multiplatform
fixture had no Android target, which is why CI never caught this.

Fixes #3688

Co-authored-by: Benoît Quenaudon <benoit@quenaudon.com>
Signed-off-by: Benoît Quenaudon <benoit@quenaudon.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Canmnot generate commonMain sources with Wire 6.4.5 (KMP)

1 participant