The device tier could only take a screenshot and read what Go chose to log, and a screenshot cannot tell a dropped CSS declaration from a missing asset. This adds the third thing: the page's own answer, from the engine that is really rendering it. `make android-screenshot` grabs the screen, `make android-inspect` forwards the WebView's devtools socket, and `make android-eval EXPR=...` evaluates in the real page. Four details are load-bearing. Only a `debuggable` build opens that socket, so the debug build type takes `applicationIdSuffix ".dev"` and installs *beside* the release app -- the two carry different signing certificates, and Android's only remedy for a changed certificate is an uninstall, which takes the user's library with it. Playwright cannot drive a WebView (`connectOverCDP` calls `Browser.setDownloadBehavior`, which it answers "Browser context management is not supported"), so the eval is raw CDP over Node's built-in WebSocket. The socket name carries the pid, so it is resolved per launch rather than written down. And `exec-out`, not `shell`, for the screenshot: a pty translates LF and corrupts the PNG. What it immediately established is why it was worth having. The phone renders in Chrome 113 at 424x439 CSS px -- two years behind every browser the other tiers use, with no Popover API and no relaxed CSS nesting -- so a spec passing at that viewport says nothing about the device, and two conclusions drawn from version numbers alone were wrong. Both are corrected in NOTES.md and the plan.
128 lines
5.2 KiB
Groovy
128 lines
5.2 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
|
|
// Its own application id, so it installs *beside* the release
|
|
// app rather than needing an uninstall to replace it. The two
|
|
// are signed by different certificates (the release one comes
|
|
// from a keystore CI holds), and Android's remedy for a
|
|
// certificate change is an uninstall -- which takes the
|
|
// user's library with it. This is also what makes the WebView
|
|
// inspectable on a real phone: `debuggable` is what turns on
|
|
// `setWebContentsDebuggingEnabled`, and `make android-inspect`
|
|
// drives it.
|
|
applicationIdSuffix ".dev"
|
|
}
|
|
}
|
|
|
|
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'
|
|
}
|