feat(client): signed Android APK build with runtime API URL (#187) #207
No reviewers
Labels
No labels
area:auth
area:ci
area:db
area:infra
area:native
area:pwa
area:service
epic
feature
foundation
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
james/carol!207
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "187-android-build"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Closes #187. Three commits land the signed Android APK pipeline with a runtime API URL:
feat(client): runtime API URL settings + secure storage— first-launch server-URL screen, expo-secure-store persistence, request middleware that splices the runtime URL into every native API call, "Change server" entry in the Account screen. Web is unaffected (same-origin).feat(client): android build wiring (prebuild + signing config)— Expo config plugin that injects a release signingConfig into the generatedandroid/app/build.gradle,pnpm -F @carol/client build:androidwrapper script,.gitignoreentries for the generated tree and keystores, full notes inapps/client/README.md.feat(ci): forgejo workflow for signed android release—.forgejo/workflows/release-android.ymltriggers on the samev*.*.*tag as the API release. Installs JDK 21 + the Android SDK, runsexpo prebuild+gradlew assembleRelease bundleRelease, attaches APK + AAB to the same Forgejo release.No baked-in URL — the Android APK ships with nothing and prompts on first launch (per the ticket). Validation is
http(s)://<host>; the reachability test is the next login attempt.Secrets reviewers should provision before the next tag release
Set these on
forge.wynning.tech(Settings → Actions → Secrets) before pushing a tag — without them the release-android workflow falls through to a debug-signed build and skips the asset upload, so the existing API release pipeline still succeeds:ANDROID_KEYSTORE_BASE64—base64 -w0 carol-release.jksANDROID_KEYSTORE_PASSWORDANDROID_KEY_ALIASANDROID_KEY_PASSWORDKeystore generation + the warning about backing it up live in
apps/client/README.md"Android release build" anddocs/ci.md"Release pipeline".CI workflow summary
Client (web export smoke)job covers the universal client.v*.*.*): the existing release.yml workflow runs unchanged. The new release-android.yml runs in parallel, waits for release.yml to create the release page (polled every 10s for ~5 min), then uploadscarol-vX.Y.Z.apkandcarol-vX.Y.Z.aabas assets.Test plan
Verified locally:
pnpm install --frozen-lockfileclean.pnpm -F @carol/api typecheck/lint/test(574 passed, 107 skipped — sqlite leg only locally; postgres leg runs in CI).pnpm -F @carol/api-client typecheck/lint/test/check.pnpm -F @carol/client typecheck/lint/test(25 tests).pnpm -F @carol/client export:web— web bundle unchanged;/server-setuproute exports.pnpm -F @carol/client prebuild:android— generatesandroid/, plugin splicessigningConfigs.releaseand rewires the release buildType to use the env-var-conditional config.actionlint .forgejo/workflows/*.ymlclean.Waits on first CI execution:
Surprises
expo prebuildrewritesapps/client/package.json(e.g. swaps"android": "expo start --android"for"expo run:android"). I revert the swap in the build script; the regression isn't fatal but worth flagging if a future contributor sees the script diff move.signingConfigs { debug { … } }already, so the plugin extends that block rather than creating one — the original "splice a new block before buildTypes" approach silently no-op'd. Caught by re-running prebuild + inspecting the gradle.signingConfig signingConfigs.debugliteral appears in both the debug and release buildTypes; a global string replace would target the wrong one. The plugin scans for the release block by name and edits only inside it.Follow-ups worth filing
Generated with Claude Code
📊 Test coverage
Patch coverage: no testable lines changed.
Overall (
app/,lib/,db/, excluding UI per ADR-0019):Soft thresholds per ADR-0019. Coverage is informational and does not block merge.
Trivy (container image)
Threshold:
high· Total findings: 121 · At/above threshold: 16.27.0, 7.28.0, 8.5.0