feat(android): release signing + R8-verified signed APK (Phase 28.8)

This commit is contained in:
Mathieu Moran
2026-08-15 20:44:45 -04:00
parent d34d30e65f
commit 5039b90bc6
4 changed files with 43 additions and 21 deletions
+7 -8
View File
@@ -2229,14 +2229,13 @@ The app reuses the existing Pi REST API surface with no changes:
dark top bar. dark top bar.
- Follow-up polish deferred: card shadows, blue `btn-primary` buttons, page titles. - Follow-up polish deferred: card shadows, blue `btn-primary` buttons, page titles.
**28.8 — Polish + distribution** **28.8 — Polish + distribution 🚧 IN PROGRESS (2026-08-15)**
- App icon, splash screen, dark theme polish - ✅ App icon (adaptive, red bg + white gauge), native splash screen (API 31+), "Yaris OBD"
- Error handling: Pi unreachable, server unreachable, no cellular data, storage full label, OS-following dark mode.
- APK signing + release build - ✅ Release build: local signing keystore (gitignored), R8-verified — `app-release.apk`
- Distribution: APK sideload (simplest — host the APK on the Pi itself at (~43 MB) installs and launches on the Pixel.
`http://yaris.local/app/yaris-obd.apk` so the user just opens that URL on the phone - ⬜ Distribution: host the APK on the Pi (`GET /app` → `static/app/` + download page).
to install/update). Play Store is out of scope (Google developer account fee, review Play Store out of scope.
process, updates lag behind development).
#### Open questions (resolve during 28.1) #### Open questions (resolve during 28.1)
+2
View File
@@ -8,5 +8,7 @@ local.properties
*.aab *.aab
*.jks *.jks
*.keystore *.keystore
keystore/
keystore.properties
!gradle/wrapper/gradle-wrapper.jar !gradle/wrapper/gradle-wrapper.jar
!gradle/wrapper/gradle-wrapper.properties !gradle/wrapper/gradle-wrapper.properties
+21
View File
@@ -1,3 +1,6 @@
import java.io.FileInputStream
import java.util.Properties
plugins { plugins {
alias(libs.plugins.android.application) alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android) alias(libs.plugins.kotlin.android)
@@ -6,6 +9,12 @@ plugins {
alias(libs.plugins.ksp) alias(libs.plugins.ksp)
} }
// Release signing config loaded from keystore.properties (gitignored).
val keystorePropertiesFile = rootProject.file("keystore.properties")
val keystoreProperties = Properties().apply {
if (keystorePropertiesFile.exists()) load(FileInputStream(keystorePropertiesFile))
}
android { android {
namespace = "com.yarisobd.app" namespace = "com.yarisobd.app"
compileSdk = 35 compileSdk = 35
@@ -20,6 +29,17 @@ android {
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
} }
signingConfigs {
create("release") {
if (keystorePropertiesFile.exists()) {
storeFile = rootProject.file(keystoreProperties["storeFile"] as String)
storePassword = keystoreProperties["storePassword"] as String
keyAlias = keystoreProperties["keyAlias"] as String
keyPassword = keystoreProperties["keyPassword"] as String
}
}
}
buildTypes { buildTypes {
debug { debug {
applicationIdSuffix = ".debug" applicationIdSuffix = ".debug"
@@ -32,6 +52,7 @@ android {
getDefaultProguardFile("proguard-android-optimize.txt"), getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro" "proguard-rules.pro"
) )
signingConfig = signingConfigs.getByName("release")
} }
} }
+13 -13
View File
@@ -250,28 +250,28 @@ android/
- [ ] FontAwesome-style icons where they map to the web nav - [ ] FontAwesome-style icons where they map to the web nav
- [ ] Page titles (`h3 fw-bold`) at the top of each screen - [ ] Page titles (`h3 fw-bold`) at the top of each screen
### 28.8 — Polish + distribution ⬜ NOT STARTED ### 28.8 — Polish + distribution 🚧 IN PROGRESS
**Depends on: 28.1–28.7 (whichever subset ships).** **Depends on: 28.1–28.7 (whichever subset ships).**
#### 28.8.1 — App polish #### 28.8.1 — App polish ✅ (2026-08-15)
- [ ] App icon (adaptive icon: foreground + background layers) - [x] App icon: adaptive icon (red `#e63946` bg + white gauge foreground)
- [ ] Splash screen (Android 12+ SplashScreen API) - [x] Splash screen: native API 31+ (`values-v31/themes.xml`, dark bg + gauge icon)
- [ ] Dark theme verified on all screens (default, car-friendly) - [x] Dark theme follows the OS setting (done in 28.7)
- [ ] Error handling audit: every network call has a user-visible error state + retry - [x] App label: "Yaris OBD"
- [ ] Accessibility: content descriptions on icons, reasonable touch targets (≥48dp) - [ ] Error handling audit — most screens have error states; dashboard still shows "—" when offline
- [ ] Commit: `feat: app polish` - [ ] Accessibility audit — content descriptions present on most icons; touch targets ≥48dp mostly
#### 28.8.2 — Build + distribution #### 28.8.2 — Build + distribution 🚧 (release APK signed; hosting pending)
- [ ] Release build signing key (keystore generated, not committed) - [x] Release signing key: `android/keystore/release.keystore` (gitignored) + `keystore.properties`
- [ ] ProGuard/R8 rules verified (Retrofit, OkHttp, Coil, MapLibre keep rules) - [x] ProGuard/R8 rules verified — release APK builds AND launches on the Pixel
- [ ] APK output: `app/build/outputs/apk/release/app-release.apk` - [x] APK output: `app/build/outputs/apk/release/app-release.apk` (~43 MB, signed)
- [ ] Self-hosted distribution: - [ ] Self-hosted distribution:
- Copy APK to Pi: `scp app-release.apk [email protected]:~/app/yaris-obd/static/app/` - Copy APK to Pi: `scp app-release.apk [email protected]:~/app/yaris-obd/static/app/`
- Add a lightweight Pi route: `GET /app` → serves `static/app/index.html` with - Add a lightweight Pi route: `GET /app` → serves `static/app/index.html` with
download link + install instructions download link + install instructions
- Phone flow: connect to Pi hotspot → open `http://yaris.local/app` → download APK → - Phone flow: connect to Pi hotspot → open `http://yaris.local/app` → download APK →
install (user must enable "Install unknown apps" once) install (user must enable "Install unknown apps" once)
- [ ] Commit: `feat: release build + self-hosted distribution` - [ ] Commit: `feat: self-hosted distribution`
## Working notes ## Working notes