Android Studio refused to sync the project after the lightning-kmp-app bump in 4e939c4:
Using multiple versions of the Android Gradle Plugin [9.1.1, 9.4.0] across Gradle builds is
not allowed.
Affected builds: [:, :lightning-kmp-app:lightning-kmp:bitcoin-kmp:secp256k1-kmp]
A composite build has to settle on a single AGP version across every build that applies the
plugin. Four builds in this tree do:
: 9.1.1 version catalog
:lightning-kmp-app 9.1.1 version catalog
:secp256k1-frost-kmp 9.1.1 version catalog
:lightning-kmp-app:lightning-kmp:bitcoin-kmp:secp256k1-kmp 9.4.0 hardcoded
lightning-kmp and bitcoin-kmp apply no android plugin at all, which is why the message names
only the two ends of the chain rather than everything between them.
secp256k1-kmp pins 9.4.0 twice -- a buildscript classpath entry, and a pluginManagement
resolutionStrategy that rewrites every requested com.android plugin to that version -- so it
cannot be talked out of it from here. The three catalogs move up to meet it. Pinning it down to
9.1.1 instead would mean editing a build four submodules deep and then committing in bitcoin-kmp
and lightning-kmp purely to carry the pointer, for no gain. Moving up is also the direction the
chain already set: bbba08b's f22c30a moved every build in it onto Gradle 9.7.1 for the same
reason, and 4e939c4 followed.
Submodule commits carried here:
lightning-kmp-app bbba08b -> ce1ed01 build: move to AGP 9.4.0, matching the version the
submodule chain pins
secp256k1-frost-kmp d3b294d -> 80a55b7 build: move to AGP 9.4.0 to match the rest of
mantra-kmp's composite
Both sit on branches (build/agp-9.4.0 and build/gate-ios-targets-on-macos) rather than their
masters, and neither is pushed yet, so a fresh clone cannot resolve these two pointers until
they are.
9.4.0 is a minor bump inside the AGP 9.x line, so the DSL is unchanged and every android.* flag
in gradle.properties -- newDsl, builtInKotlin, the r8 settings -- keeps its meaning.
`:composeApp:compileDebugKotlinAndroid` passes clean.
Note that this is only what the IDE needs to sync, not everything worth knowing about the
chain. bitcoin-kmp's settings.gradle.kts substitutes secp256k1-kmp, -jni-jvm and the three
-jni-jvm-{linux,darwin,mingw} coordinates, but not -jni-android. So the android app still
resolves secp256k1-kmp-jni-android from maven central at stock 0.24.0, without the
FROST/prefractal native modules the threshold branch exists to provide, and a call into those
from android would fail with UnsatisfiedLinkError. Fixing that needs a substitution rule in
bitcoin-kmp. Untouched here because it is a runtime concern, not a sync one.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
lightning-kmp-app moves 6745d88 -> bbba08b, four commits:
57353cf Minor updates
9f3cd72 Build lightning-kmp from the experimental submodule via a composite build
f22c30a Follow the submodule chain onto Gradle 9.7.1
bbba08b Declare the ios targets only on a mac, so the IDE can import the project
9f3cd72 is the substantive one. lightning-kmp no longer comes from maven central: the
submodule now carries its own experimental/lightning-kmp submodule on branch `threshold`
-- the branch with the FROST/prefractal signers -- and substitutes
fr.acinq.lightning:lightning-kmp-core for that build's project. That build includes
bitcoin-kmp, which includes secp256k1-kmp, which compiles the C library from a secp256k1-zkp
fork. So this repo's build tree is now four levels deep and compiles native code.
Cloning therefore needs `git submodule update --init --recursive`, and because each included
build resolves the android SDK from its own local.properties rather than inheriting the
root's, the three new nested builds each need a (gitignored) local.properties with sdk.dir.
57353cf changed two signatures that MantraApplication implements -- LightningApplication
gained getApplicationContext(), and BusinessManager.initialize now takes the application
rather than a Context. Neither needed a source change: MantraApplication extends
android.app.Application, which already supplies getApplicationContext(), and it was already
passing `this`, which satisfies the narrowed parameter type.
The rest of this commit is what the update forces on the outer build.
gradle-wrapper.properties, 9.3.1 -> 9.7.1: f22c30a moved every build in the chain onto
9.7.1. An included build does not use its own wrapper -- the root build's gradle version runs
the whole tree -- so this repo has to follow for the chain to build at all.
gradle.properties, configuration cache off: secp256k1-kmp's `:jni:generateHeaders` and
`:native:buildSecp256k1<target>` both hold gradle script object references and cannot be
serialized. The configuration cache covers a whole build tree and has no per-build opt-out,
so an included build's incompatibility is this build's problem. The comment records how to
undo this once those tasks are fixed upstream.
composeApp/build.gradle.kts, ios targets gated on the host: secp256k1-kmp declares a
libsecp256k1 cinterop, which makes gradle switch off klib cross compilation for apple
targets. On linux nothing in the tree then offers an ios variant of
fr.acinq.phoenix:lightning-kmp-app, and the ios compilations failed with "No matching variant
of project ':lightning-kmp-app:library'" -- not a warning, a build failure. The gate covers
the target declarations, the iosMain dependencies (the source set only exists when the
targets do) and the kspIos* configurations (likewise). This mirrors bbba08b, which applied
the same gate inside the submodule for the same reason.
secp256k1-frost-kmp d3b294d applies that gate there too. Substitution rules apply across a
whole build tree, so that project's own lightning-kmp-core coordinate started resolving to
the source project without it asking, and every apple source set stopped resolving. The
android build masked it -- ios compilations are not in its task graph -- but
kmpPartiallyResolvedDependenciesChecker reported it and compileAppleMainKotlinMetadata failed
outright, which would have broken IDE import.
Note that `:composeApp:compileCommonMainKotlinMetadata` no longer exists on a linux host.
With ios gated off, androidTarget is the only declared target (jvm() is still commented out),
and KMP does not generate a commonMain metadata compilation for a single-target project.
`:composeApp:compileDebugKotlinAndroid` is the check now; it passes clean, with none of the
resolution errors above.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Add both libraries as git submodules and resolve them through Gradle
composite builds instead of remote publications, so local changes to
either library are picked up by the app build directly.
Submodules:
* secp256k1-frost-kmp (github.com/ac-cord-ac/secp256k1-frost-kmp) at
2478403 -- BIP-327 FROTH/FROST signing over secp256k1, KMP.
* lightning-kmp-app (github.com/kngako/lightning-kmp-app) at 6745d88 --
phoenix business logic on top of lightning-kmp-core. Both submodules
carry a local commit aligning them with this build's AGP 9.1.1 /
Kotlin 2.4.10 (AGP version must match across a composite build or the
android variants fail attribute matching).
settings.gradle.kts:
* includeBuild() both submodule checkouts.
* lightning-kmp-app's project stays named ':library' (compose-resources
derives its Res package from the project name), so an explicit
dependencySubstitution maps the coordinate the app declares,
fr.acinq.phoenix:lightning-kmp-app, onto that project.
* Drop the jitpack.io repository: it only served com.github.kngako,
which is no longer consumed as a binary.
composeApp/build.gradle.kts:
* commonMain gains ac.cord.auxiliary:library:1.0.0 (secp256k1-frost-kmp,
substituted by the composite build).
* commonMain replaces com.github.kngako.lightning-kmp-app:library (via
JitPack) with fr.acinq.phoenix:lightning-kmp-app:1.0.0 (substituted by
the composite build). lightning-kmp-core still comes from Maven
Central.
* Remove the RestoreJitPackClassifier component-metadata rule and the
javax.inject import: it only existed to repair the artifact
classifiers JitPack drops from the apple metadata variants, which no
longer applies.
gradle/libs.versions.toml:
* Remove the now-unused lightningKmpApp version and the
com.github.kngako lightning-kmp-app catalog entry.
Verified:
./gradlew :composeApp:compileCommonMainKotlinMetadata :composeApp:compileDebugKotlinAndroid
The shared lightning/phoenix logic now lives in kngako/lightning-kmp-app,
which publishes a single `:library` module. JitPack serves a repository's
submodules under <GROUP>.<ARTIFACT>, hence the
com.github.kngako.lightning-kmp-app:library coordinate. The repository is
content-filtered to com.github.kngako so it is not consulted for anything
else -- an unfiltered jitpack.io entry gets asked about every dependency
that misses in mavenCentral, and each miss is a remote round trip.
The version is a commit rather than master-SNAPSHOT. For a -SNAPSHOT
version JitPack advertises a unique-snapshot maven-metadata.xml
(timestamp=<sha>, buildNumber=1) while serving the files under their
literal -SNAPSHOT names, so gradle derives library-<target>-master-<sha>-1
and gets a 404 on every artifact. Pinning a commit sidesteps the snapshot
machinery entirely and is reproducible; it needs bumping when the fork
moves.
That leaves the classifier. JitPack rewrites the version inside a
published .module file and drops the classifier while doing so, so both
the sources and the host-specific metadata variants of each apple target
come back naming library-<target>-<ver>.jar -- a file that does not
exist, next to the -sources.jar and -metadata.jar that do. The klib and
the aar are named without a classifier and so survive the rewrite, which
is why the android compilation resolves this dependency perfectly well
and only the metadata compilations fail. Every shared ios source set
resolves through those, so a component metadata rule puts the -metadata
classifier back. It is scoped to the two apple modules and to their
metadata variant by name, so it cannot disturb the klib artifacts.
Verified: :composeApp:compileCommonMainKotlinMetadata and
:composeApp:compileDebugKotlinAndroid both pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>