feat(android)!: replace the Capacitor wrapper with a native Kotlin/Compose app

Fresh Kotlin 2.2 + Jetpack Compose app at feature parity with web/
(game logic, settings contract, voice semantics ported one-to-one with
twinned tests; 104 unit + 9 instrumentation tests). Fully offline:
VIBRATE is the only permission; Media3's ACCESS_NETWORK_STATE is
stripped. Voice clips mount from web/static/audio at build time.

Same applicationId, signing env contract, and Play alpha track;
versionCode 7 / 0.2.0. CI Android job is Gradle-only (lint, test,
debug + R8 release APK) and the release workflow fails fast on an
unbumped versionCode.

BREAKING CHANGE: WebView localStorage (settings, in-progress round)
is not migrated; wrapper users start clean.
This commit is contained in:
tiennm99 committed 2026-08-31 13:28:48 +07:00
1 parent 8f9b03ca05
commit e314ae01c8
126 files changed
+6390 -2275

No files matched your search

+8 -14
View File
@@ -3,9 +3,11 @@
# The web app is built twice and only twice — once per base path — and every
# consumer downloads an artifact instead of rebuilding:
#
# build (root, base "") -> deploy-firebase, preview-firebase, android-debug
# build (root, base "") -> deploy-firebase, preview-firebase
# build (gh, base /loto) -> deploy-pages
#
# The Android app is native Kotlin/Compose and builds independently of the
# web bundle (it mounts web/static/audio straight from the checkout).
# Tags are handled by android-release.yml, which builds standalone.
name: ci
@@ -154,28 +156,20 @@ jobs:
entryPoint: web
android-debug:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- uses: actions/download-artifact@v7
with:
name: web-build
# capacitor.config.json declares `webDir: "../web/build"`.
path: web/build
- uses: ./.github/actions/setup-android
# `npm run build` would rebuild web/; the bundle is already here.
- name: Sync web bundle into the native project
run: npm run sync
# assembleRelease runs R8 with no secrets needed (unsigned without
# LOTO_KEYSTORE_PATH) so a missing keep rule fails CI, not the tag.
- name: Lint, test and assemble debug + release APKs
run: ./gradlew :app:lint :app:test :app:assembleDebug :app:assembleRelease
working-directory: android
- name: Assemble debug APK
run: ./gradlew :app:assembleDebug
working-directory: android/android
- uses: actions/upload-artifact@v7
with:
name: app-debug.apk
path: android/android/app/build/outputs/apk/debug/*.apk
path: android/app/build/outputs/apk/debug/*.apk
archive: false
retention-days: 7