The android app had no android secp256k1 natives at all, and had not had any for
as long as lightning-kmp-core has been a dependency. `dependencyInsight` on
debugRuntimeClasspath resolved every secp256k1 coordinate to
`:secp256k1-kmp:jni:jvm:{darwin,linux,mingw}` -- desktop .so/.dylib/.dll files,
loaded by extracting them from a jar, which cannot work on a device.
The cause is a chain of individually reasonable decisions. lightning-kmp-core
publishes no android variant, so an android consumer resolves it to the jvm one;
the jvm variant asks for `secp256k1-kmp-jni-jvm`; and nothing anywhere asks for
`secp256k1-kmp-jni-android`. lightning-kmp-app names it only in androidDeviceTest,
so consumers of the published library do not get it. It has to be named here.
Naming it alone would not have been enough. bitcoin-kmp's settings.gradle.kts
substituted five of secp256k1-kmp's coordinates to the fork's projects but not
-jni-android, so it would have resolved from Maven Central to stock 0.24.0 --
built from upstream libsecp256k1, with no ChillDKG module. Because the kotlin API
comes from the substituted root project, that combination type-checks and links
and then fails with UnsatisfiedLinkError at the first native call. The rule is
added in the submodule commits this carries.
Submodule commits carried here:
lightning-kmp-app ce1ed01 -> 6434282 build: carry the jni-android substitution
down from bitcoin-kmp
experimental/lightning-kmp 77be7b78 -> 5103b79e
experimental/bitcoin-kmp 196a479 -> 65c4aab build: substitute
secp256k1-kmp-jni-android to the
included build too
Verified through the artifact rather than the graph: composeApp-debug.apk now
carries lib/{arm64-v8a,armeabi-v7a,x86,x86_64}/libsecp256k1-jni.so, and `nm -D` on
the arm64 one exports all twelve Java_..._chilldkg_... JNI entry points --
hostpubkey_gen, params_hash, participant_step1/step2/finalize,
coordinator_step1/finalize, and the recover and investigate calls.
The three builds in the chain sit on `build/substitute-jni-android` branches
(lightning-kmp-app on `build/agp-9.4.0`, which now carries two commits) and none
are pushed, so a fresh clone cannot resolve these pointers yet.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
234 lines
8.3 KiB
Kotlin
234 lines
8.3 KiB
Kotlin
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
|
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
|
|
|
plugins {
|
|
alias(libs.plugins.androidApplication)
|
|
// alias(libs.plugins.androidx.room)
|
|
alias(libs.plugins.androidx.room3)
|
|
alias(libs.plugins.kotlinMultiplatform)
|
|
alias(libs.plugins.composeMultiplatform)
|
|
alias(libs.plugins.composeCompiler)
|
|
alias(libs.plugins.composeHotReload)
|
|
alias(libs.plugins.kotlinPluginSerialization)
|
|
alias(libs.plugins.ksp)
|
|
alias(libs.plugins.sqldelight)
|
|
}
|
|
|
|
kotlin {
|
|
compilerOptions {
|
|
freeCompilerArgs.add("-Xexpect-actual-classes")
|
|
}
|
|
|
|
androidTarget {
|
|
compilerOptions {
|
|
jvmTarget.set(JvmTarget.JVM_21)
|
|
}
|
|
}
|
|
|
|
// Declared only on a mac, mirroring the gate lightning-kmp-app's :library applies to its own ios
|
|
// targets. Down the composite chain secp256k1-kmp declares a libsecp256k1 cinterop, which makes
|
|
// gradle switch off klib cross compilation for apple targets, so on a linux/windows host nothing
|
|
// in the build tree offers an ios variant of fr.acinq.phoenix:lightning-kmp-app. Declaring these
|
|
// targets anyway leaves every ios compilation unable to resolve it and fails the build outright.
|
|
// Building an ios binary needs a mac regardless.
|
|
if (org.gradle.internal.os.OperatingSystem.current().isMacOsX) {
|
|
listOf(
|
|
iosArm64(),
|
|
iosSimulatorArm64()
|
|
).forEach { iosTarget ->
|
|
iosTarget.binaries.framework {
|
|
baseName = "ComposeApp"
|
|
isStatic = true
|
|
}
|
|
}
|
|
}
|
|
|
|
// jvm()
|
|
|
|
sourceSets {
|
|
androidMain.dependencies {
|
|
// The android secp256k1 natives. Nothing pulls these in transitively: lightning-kmp-core
|
|
// publishes no android variant, so the android target resolves it to the jvm one, which
|
|
// asks for secp256k1-kmp-jni-jvm and gets desktop .so/.dylib/.dll files that cannot load
|
|
// on a device. The app has to name the android artifact itself.
|
|
//
|
|
// Resolved from source via the composite build, not from Maven Central -- bitcoin-kmp's
|
|
// settings.gradle.kts substitutes this coordinate for secp256k1-kmp's :jni:android. That
|
|
// matters: the stock artifact has no ChillDKG module, so ChillDKG would compile and then
|
|
// fail with UnsatisfiedLinkError. The version is never resolved; substitution matches on
|
|
// group:name.
|
|
implementation("fr.acinq.secp256k1:secp256k1-kmp-jni-android:0.24.0")
|
|
|
|
implementation(libs.androidx.activity.compose)
|
|
implementation(libs.androidx.work.runtime.ktx)
|
|
// implementation(libs.androidx.room.sqlite.wrapper)
|
|
implementation(libs.compose.uiToolingPreview)
|
|
implementation(libs.okhttp.coroutines)
|
|
|
|
implementation(libs.sqldelight.android.driver)
|
|
}
|
|
commonMain.dependencies {
|
|
implementation(libs.androidx.datastore)
|
|
implementation(libs.androidx.datastore.preferences)
|
|
|
|
implementation(libs.androidx.lifecycle.viewmodelCompose)
|
|
implementation(libs.androidx.lifecycle.runtimeCompose)
|
|
|
|
implementation(libs.androidx.paging.common)
|
|
implementation(libs.androidx.paging.compose)
|
|
|
|
// implementation(libs.androidx.room.runtime)
|
|
implementation(libs.androidx.room3.runtime)
|
|
implementation(libs.androidx.sqlite.bundled)
|
|
|
|
implementation(libs.coil.compose)
|
|
implementation(libs.coil.network.ktor3)
|
|
|
|
implementation(libs.compose.runtime)
|
|
implementation(libs.compose.foundation)
|
|
implementation(libs.compose.material3)
|
|
implementation (libs.compose.material.icons.core)
|
|
implementation (libs.compose.material.icons.extended)
|
|
implementation(libs.compose.ui)
|
|
implementation(libs.compose.components.resources)
|
|
implementation(libs.compose.uiToolingPreview)
|
|
|
|
|
|
implementation(libs.kermit)
|
|
|
|
implementation(libs.kotlinx.datetime)
|
|
implementation(libs.kotlinx.serialization.json)
|
|
implementation(libs.kotlinx.serialization.cbor)
|
|
|
|
|
|
implementation(libs.ktor.client.core)
|
|
implementation(libs.ktor.client.cio)
|
|
implementation(libs.ktor.client.websockets)
|
|
implementation(libs.ktor.serialization.kotlinx.json)
|
|
|
|
|
|
|
|
// implementation(libs.lightning.kmp.core)
|
|
|
|
// resolved via the lightning-kmp-app composite build (see settings.gradle.kts)
|
|
implementation("fr.acinq.phoenix:lightning-kmp-app:1.0.0")
|
|
|
|
implementation(libs.navigation.compose)
|
|
|
|
implementation(libs.okio)
|
|
|
|
implementation(libs.qrose)
|
|
|
|
implementation(libs.sqldelight.runtime)
|
|
implementation(libs.sqldelight.coroutines.extensions)
|
|
|
|
implementation(libs.vitorpamplona.quartz)
|
|
|
|
implementation("com.ionspin.kotlin:bignum:0.3.10")
|
|
|
|
// resolved via the secp256k1-frost-kmp composite build (see settings.gradle.kts)
|
|
implementation("ac.cord.auxiliary:library:1.0.0")
|
|
|
|
implementation("no.synth:kmp-zip:0.8.0")
|
|
implementation("no.synth:kmp-zip-okio:0.8.0")
|
|
}
|
|
commonTest.dependencies {
|
|
implementation(libs.kotlin.test)
|
|
}
|
|
jvmMain.dependencies {
|
|
implementation(compose.desktop.currentOs)
|
|
implementation(libs.kotlinx.coroutinesSwing)
|
|
}
|
|
// Only exists when the ios targets above were declared; the default hierarchy template
|
|
// creates this source set from them.
|
|
if (org.gradle.internal.os.OperatingSystem.current().isMacOsX) {
|
|
iosMain.dependencies {
|
|
implementation(libs.sqldelight.native.driver)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
android {
|
|
namespace = "press.mantra.android"
|
|
compileSdk = libs.versions.android.compileSdk.get().toInt()
|
|
|
|
buildFeatures {
|
|
buildConfig = true
|
|
}
|
|
defaultConfig {
|
|
applicationId = "press.mantra.android"
|
|
minSdk = libs.versions.android.minSdk.get().toInt()
|
|
targetSdk = libs.versions.android.targetSdk.get().toInt()
|
|
versionCode = 1
|
|
versionName = "0.1.0"
|
|
}
|
|
packaging {
|
|
resources {
|
|
excludes += "/META-INF/{AL2.0,LGPL2.1}"
|
|
excludes += "META-INF/versions/9/OSGI-INF/MANIFEST.MF"
|
|
}
|
|
}
|
|
buildTypes {
|
|
getByName("release") {
|
|
isMinifyEnabled = false
|
|
}
|
|
getByName("debug") {
|
|
applicationIdSuffix = ".debug"
|
|
versionNameSuffix = "-DEBUG"
|
|
}
|
|
}
|
|
compileOptions {
|
|
sourceCompatibility = JavaVersion.VERSION_21
|
|
targetCompatibility = JavaVersion.VERSION_21
|
|
}
|
|
}
|
|
|
|
dependencies {
|
|
debugImplementation(libs.compose.uiTooling)
|
|
// ksp(libs.androidx.room3.compiler)
|
|
add("kspAndroid", libs.androidx.room3.compiler)
|
|
// These configurations only exist when the ios targets are declared, which the kotlin block
|
|
// above does only on a mac.
|
|
if (org.gradle.internal.os.OperatingSystem.current().isMacOsX) {
|
|
add("kspIosSimulatorArm64", libs.androidx.room3.compiler)
|
|
// add("kspIosX64", libs.androidx.room.compiler)
|
|
add("kspIosArm64", libs.androidx.room3.compiler)
|
|
}
|
|
// add("kspJvm", libs.androidx.room3.compiler)
|
|
// Add any other platform target you use in your project, for example kspDesktop
|
|
}
|
|
|
|
room3 {
|
|
schemaDirectory("$projectDir/schemas")
|
|
}
|
|
|
|
sqldelight {
|
|
databases {
|
|
create("ChannelsDatabase") {
|
|
packageName.set("fr.acinq.phoenix.db.sqldelight")
|
|
srcDirs.from("src/commonMain/sqldelight/channelsdb")
|
|
}
|
|
create("PaymentsDatabase") {
|
|
packageName.set("fr.acinq.phoenix.db.sqldelight")
|
|
srcDirs.from("src/commonMain/sqldelight/paymentsdb")
|
|
}
|
|
create("AppDatabase") {
|
|
packageName.set("fr.acinq.phoenix.db.sqldelight")
|
|
srcDirs.from("src/commonMain/sqldelight/appdb")
|
|
}
|
|
}
|
|
}
|
|
|
|
compose.desktop {
|
|
application {
|
|
mainClass = "press.mantra.desktop.MainKt"
|
|
|
|
nativeDistributions {
|
|
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
|
|
packageName = "press.mantra.desktop"
|
|
packageVersion = "1.0.0"
|
|
}
|
|
}
|
|
}
|