The fat APK's second half was 31 MB that cannot execute on any Android device. modernc.org/libc's Xlstat64 issues a raw lstat syscall on linux/amd64, and Android's seccomp policy forbids it because bionic never issues it, so the process takes SIGSYS the first time anything touches the database -- which for this app is startup. That is every x86_64 Android, x86 Chromebooks included, not merely the emulator. arm64 is structurally unaffected: the architecture has no lstat syscall at all, so modernc routes through fstatat. 27,059,130 bytes to 15,898,465, and one lib/ entry. Three places had to agree, and the third is what would have made this a silent no-op: abiFilters (what Gradle packages), android:package rather than package:fat (what Go *compiles* -- otherwise the library is still built and then discarded), and the native-code assertion in CI. That assertion is anchored, `native-code: 'arm64-v8a'$`, because without the anchor it also matches the fat APK's line and would pass on exactly the thing it exists to catch. Checked against a real artifact. Adding the ABI back, if modernc ever fixes Xlstat64, is those same three edits.
118 lines
4.5 KiB
Groovy
118 lines
4.5 KiB
Groovy
plugins {
|
|
id 'com.android.application'
|
|
}
|
|
|
|
android {
|
|
namespace 'com.wails.app'
|
|
compileSdk 35
|
|
|
|
buildFeatures {
|
|
buildConfig = true
|
|
}
|
|
|
|
defaultConfig {
|
|
// The app's identity on the device. `namespace` above stays
|
|
// com.wails.app -- that is the *Java package* the scaffold's
|
|
// MainActivity/WailsBridge live in, and renaming it would mean
|
|
// renaming their source. The two being different is normal and is
|
|
// why every `am start` needs the fully-qualified activity name
|
|
// (app.yellowjacket/com.wails.app.MainActivity), not `.MainActivity`.
|
|
//
|
|
// Matches build/config.yml's productIdentifier.
|
|
applicationId "app.yellowjacket"
|
|
minSdk 21
|
|
targetSdk 35
|
|
|
|
// **Android orders releases by this integer, not by the version
|
|
// string, and refuses to install anything not greater than what is
|
|
// already there.** A hardcoded 1 means the first install is the
|
|
// last: every later build is rejected as a downgrade and the only
|
|
// way out is an uninstall, which takes the user's library with it.
|
|
// CI derives it from the tag (1.3.1 -> 10301), monotonic as long as
|
|
// minor and patch stay under 100. The defaults keep a local build
|
|
// working with no environment at all.
|
|
//
|
|
// `Integer.parseInt`, not `(...) as Integer`: Groovy binds the call
|
|
// parentheses to `versionCode` before the cast, so the latter reads
|
|
// as `versionCode("1") as Integer` -- it sets a String, then casts
|
|
// the setter's null return, and Gradle fails the entire project
|
|
// with "Value is null" pointing at this line.
|
|
versionCode Integer.parseInt(System.getenv("YJ_VERSION_CODE") ?: "1")
|
|
versionName System.getenv("YJ_VERSION") ?: "0.0.0"
|
|
|
|
// **arm64 only, and x86_64 is not a gap.** `modernc.org/libc`'s
|
|
// Xlstat64 issues a raw lstat syscall on linux/amd64, which
|
|
// Android's seccomp policy forbids (bionic never issues it), so
|
|
// the process takes SIGSYS the first time anything touches the
|
|
// database -- which for this app is startup. That is every
|
|
// x86_64 Android, emulators and x86 Chromebooks alike, not just
|
|
// some. arm64 is structurally unaffected: the architecture has
|
|
// no lstat syscall at all, so modernc routes through fstatat.
|
|
//
|
|
// So the second ABI was ~31 MB of an artifact that could not run
|
|
// anywhere. If modernc fixes it, adding 'x86_64' back here and
|
|
// to the native-code assertion in android-apk.yml is the whole
|
|
// change.
|
|
ndk {
|
|
abiFilters 'arm64-v8a'
|
|
}
|
|
}
|
|
|
|
def keystoreFile = System.getenv("ANDROID_KEYSTORE_FILE")
|
|
def hasKeystore = keystoreFile != null && !keystoreFile.trim().isEmpty()
|
|
|
|
signingConfigs {
|
|
// A real keystore can be provided via environment variables; without
|
|
// one, release builds are signed with the debug keystore so they can
|
|
// be installed for testing (not suitable for Play Store uploads).
|
|
release {
|
|
if (hasKeystore) {
|
|
storeFile file(keystoreFile)
|
|
storePassword System.getenv("ANDROID_KEYSTORE_PASSWORD")
|
|
keyAlias System.getenv("ANDROID_KEY_ALIAS")
|
|
keyPassword System.getenv("ANDROID_KEY_PASSWORD")
|
|
}
|
|
}
|
|
}
|
|
|
|
buildTypes {
|
|
release {
|
|
minifyEnabled false
|
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
|
signingConfig hasKeystore ? signingConfigs.release : signingConfigs.debug
|
|
}
|
|
debug {
|
|
debuggable true
|
|
}
|
|
}
|
|
|
|
compileOptions {
|
|
sourceCompatibility JavaVersion.VERSION_11
|
|
targetCompatibility JavaVersion.VERSION_11
|
|
}
|
|
|
|
// Source sets configuration
|
|
sourceSets {
|
|
main {
|
|
// JNI libraries are in jniLibs folder
|
|
jniLibs.srcDirs = ['src/main/jniLibs']
|
|
// Assets for the WebView
|
|
assets.srcDirs = ['src/main/assets']
|
|
}
|
|
}
|
|
|
|
// Packaging options
|
|
packagingOptions {
|
|
// Don't strip Go symbols in debug builds
|
|
doNotStrip '*/arm64-v8a/libwails.so'
|
|
}
|
|
}
|
|
|
|
dependencies {
|
|
implementation 'androidx.appcompat:appcompat:1.6.1'
|
|
implementation 'androidx.webkit:webkit:1.9.0'
|
|
implementation 'com.google.android.material:material:1.11.0'
|
|
implementation 'androidx.biometric:biometric:1.1.0'
|
|
implementation 'androidx.security:security-crypto:1.1.0-alpha06'
|
|
}
|