Files
web-terminal/android/settings.gradle.kts
Yaojia Wang c1612d0145 build(android): make release buildable and instrumented testing possible
Four gaps that made "ship it" and "test it on hardware" impossible.

RELEASE SIGNING. assembleRelease was silently producing
app-release-unsigned.apk because there was no signingConfigs block at all —
the failure mode where you only notice at install time. Credentials now
resolve from keystore.properties, then local.properties, then
WEBTERM_RELEASE_* env; nothing is created or committed, and
keystore.properties.example is the template.

The degradation is ENFORCED, not documented. The signingConfig is only
created when credentials actually resolve — an empty config is precisely what
makes AGP emit an unsigned artifact quietly — and a guard on packageRelease
throws with an actionable message, distinguishing "not configured" from
"credentials found but the keystore file is missing: <path>". It hooks the
PACKAGE task on purpose: R8 has already run and reported by then, so a
developer without a keystore still gets the full shrink result rather than an
early abort. Verified: minifyReleaseWithR8 completes, packageRelease fails
loudly, and no unsigned APK is written.

VERSIONING. Was still the scaffold 1 / "0.1.0". Now 1 / "0.1.0-alpha01",
where the suffix is a factual claim about device verification rather than
decoration: alpha means device QA is essentially unstarted, beta means the
A34/A35 checklist blocks pass on hardware, and plain 0.1.0 means the whole
checklist is ticked. versionCode stays 1 because no artifact has ever left
the build machine.

MINIFICATION. release had isMinifyEnabled = false and an empty rules file —
so nothing had ever exercised R8 on this app, and the first release build
would have been the experiment. Now minify + resource shrinking, with a
deliberately short rules file: the actual artifacts were checked, and
kotlinx.serialization, Tink, Hilt, FCM, OkHttp, Compose and CameraX all ship
their own consumer rules, so none are re-declared. The termux packages are
kept whole because the JitPack artifacts ship no rules and :terminal-view
binds to non-API internals — it writes the public TerminalView.mEmulator
field and calls TerminalRenderer.getFontWidth()/getFontLineSpacing(). Getting
that wrong yields a build that crashes only in production.
lintVitalRelease also passes now, the two pre-existing lint ERRORS having
been fixed earlier this session.

ANDROID TEST ENABLEMENT. :app had no androidTest source set and no
instrumentation runner, which is the mechanical reason A34/A35 have no code
at all. The runner (Hilt-aware) and dependencies are wired, and a
:macrobenchmark module exists. The tests themselves are a separate change.

Verified: ./gradlew test :app:assembleDebug :app:assembleDebugAndroidTest
:app:assembleBenchmark :macrobenchmark:assembleBenchmark
:app:lintVitalRelease koverVerify -> BUILD SUCCESSFUL; 901 JVM tests, 0
failures on a forced re-execution with test-results deleted and
--no-build-cache.
2026-07-30 12:14:53 +02:00

61 lines
3.1 KiB
Plaintext

pluginManagement {
repositories {
google()
gradlePluginPortal()
mavenCentral()
// google() (above) serves AGP for the Android-framework modules.
// It requires the Android Gradle Plugin / SDK, absent in this env.
}
}
@Suppress("UnstableApiUsage")
dependencyResolutionManagement {
// Modules must not declare their own repositories.
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
// JitPack — builds the Apache-2.0 Termux terminal-emulator + terminal-view
// submodules on demand for :terminal-view (A16, plan §9 R2). Scoped to those
// two libs only; never termux-shared/app (GPLv3).
maven { url = uri("https://jitpack.io") }
}
// The version catalog at gradle/libs.versions.toml is auto-registered as `libs`.
}
rootProject.name = "webterm-android"
// ── Pure Kotlin/JVM modules (JVM-unit-testable; the 80% Kover targets) ──────────
// These build with the JVM toolchain only — NO Android SDK required.
include(":wire-protocol")
include(":session-core")
include(":api-client")
include(":client-tls")
include(":test-support")
// :transport-okhttp (A7) — OkHttp is a plain JVM lib, so this pure-JVM module
// builds and tests here (MockWebServer) with NO Android SDK.
include(":transport-okhttp")
// ── Android-framework modules ───────────────────────────────────────────────────
// The Android SDK IS now installed (see android/README.md → "Android SDK setup"),
// and AGP 9.2.1 is proven to build against SDK 35 with Gradle 9.6.1. Enable each as
// its real module is implemented (plan AW2+).
// Recipe: apply `alias(libs.plugins.android.library)` ONLY (AGP 9 has built-in
// Kotlin — do NOT add kotlin.android); android { namespace; compileSdk = 36;
// defaultConfig { minSdk = 29 } }.
//
// :app (A13) — the Android application: Compose Material 3 (+ Adaptive) design
// system, Hilt DI skeleton, launcher MainActivity. This module establishes the
// Android UI-stack version matrix for every later Android task.
include(":app") // A13 — libs.plugins.android.application + compose + ksp + hilt
include(":terminal-view") // A16 — android-library + Termux terminal-emulator/-view (JitPack, Apache-2.0)
include(":host-registry") // A12 — android-library + DataStore (Host list / last-session)
include(":client-tls-android") // A11 — android-library + AndroidKeyStore import + Tink AEAD
// ── Instrumented-only module (no production code, never on :app's classpath) ─────
// :macrobenchmark (A35) — a `com.android.test` module that drives :app's `benchmark`
// variant OUT of process via UiAutomator. Separate APK by construction, so it cannot
// violate the "dependencies only flow down" rule: nothing depends on it, and it depends
// on :app only through `targetProjectPath`, not a project() dependency.
include(":macrobenchmark") // A35 — libs.plugins.android.test + benchmark-macro-junit4