feat(android): release signing + R8-verified signed APK (Phase 28.8)
This commit is contained in:
@@ -2229,14 +2229,13 @@ The app reuses the existing Pi REST API surface with no changes:
|
||||
dark top bar.
|
||||
- Follow-up polish deferred: card shadows, blue `btn-primary` buttons, page titles.
|
||||
|
||||
**28.8 — Polish + distribution**
|
||||
- App icon, splash screen, dark theme polish
|
||||
- Error handling: Pi unreachable, server unreachable, no cellular data, storage full
|
||||
- APK signing + release build
|
||||
- Distribution: APK sideload (simplest — host the APK on the Pi itself at
|
||||
`http://yaris.local/app/yaris-obd.apk` so the user just opens that URL on the phone
|
||||
to install/update). Play Store is out of scope (Google developer account fee, review
|
||||
process, updates lag behind development).
|
||||
**28.8 — Polish + distribution 🚧 IN PROGRESS (2026-08-15)**
|
||||
- ✅ App icon (adaptive, red bg + white gauge), native splash screen (API 31+), "Yaris OBD"
|
||||
label, OS-following dark mode.
|
||||
- ✅ Release build: local signing keystore (gitignored), R8-verified — `app-release.apk`
|
||||
(~43 MB) installs and launches on the Pixel.
|
||||
- ⬜ Distribution: host the APK on the Pi (`GET /app` → `static/app/` + download page).
|
||||
Play Store out of scope.
|
||||
|
||||
#### Open questions (resolve during 28.1)
|
||||
|
||||
|
||||
@@ -8,5 +8,7 @@ local.properties
|
||||
*.aab
|
||||
*.jks
|
||||
*.keystore
|
||||
keystore/
|
||||
keystore.properties
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
!gradle/wrapper/gradle-wrapper.properties
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import java.io.FileInputStream
|
||||
import java.util.Properties
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.android.application)
|
||||
alias(libs.plugins.kotlin.android)
|
||||
@@ -6,6 +9,12 @@ plugins {
|
||||
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 {
|
||||
namespace = "com.yarisobd.app"
|
||||
compileSdk = 35
|
||||
@@ -20,6 +29,17 @@ android {
|
||||
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 {
|
||||
debug {
|
||||
applicationIdSuffix = ".debug"
|
||||
@@ -32,6 +52,7 @@ android {
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
signingConfig = signingConfigs.getByName("release")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+13
-13
@@ -250,28 +250,28 @@ android/
|
||||
- [ ] FontAwesome-style icons where they map to the web nav
|
||||
- [ ] 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).**
|
||||
|
||||
#### 28.8.1 — App polish
|
||||
- [ ] App icon (adaptive icon: foreground + background layers)
|
||||
- [ ] Splash screen (Android 12+ SplashScreen API)
|
||||
- [ ] Dark theme verified on all screens (default, car-friendly)
|
||||
- [ ] Error handling audit: every network call has a user-visible error state + retry
|
||||
- [ ] Accessibility: content descriptions on icons, reasonable touch targets (≥48dp)
|
||||
- [ ] Commit: `feat: app polish`
|
||||
#### 28.8.1 — App polish ✅ (2026-08-15)
|
||||
- [x] App icon: adaptive icon (red `#e63946` bg + white gauge foreground)
|
||||
- [x] Splash screen: native API 31+ (`values-v31/themes.xml`, dark bg + gauge icon)
|
||||
- [x] Dark theme follows the OS setting (done in 28.7)
|
||||
- [x] App label: "Yaris OBD"
|
||||
- [ ] Error handling audit — most screens have error states; dashboard still shows "—" when offline
|
||||
- [ ] Accessibility audit — content descriptions present on most icons; touch targets ≥48dp mostly
|
||||
|
||||
#### 28.8.2 — Build + distribution
|
||||
- [ ] Release build signing key (keystore generated, not committed)
|
||||
- [ ] ProGuard/R8 rules verified (Retrofit, OkHttp, Coil, MapLibre keep rules)
|
||||
- [ ] APK output: `app/build/outputs/apk/release/app-release.apk`
|
||||
#### 28.8.2 — Build + distribution 🚧 (release APK signed; hosting pending)
|
||||
- [x] Release signing key: `android/keystore/release.keystore` (gitignored) + `keystore.properties`
|
||||
- [x] ProGuard/R8 rules verified — release APK builds AND launches on the Pixel
|
||||
- [x] APK output: `app/build/outputs/apk/release/app-release.apk` (~43 MB, signed)
|
||||
- [ ] Self-hosted distribution:
|
||||
- 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
|
||||
download link + install instructions
|
||||
- Phone flow: connect to Pi hotspot → open `http://yaris.local/app` → download APK →
|
||||
install (user must enable "Install unknown apps" once)
|
||||
- [ ] Commit: `feat: release build + self-hosted distribution`
|
||||
- [ ] Commit: `feat: self-hosted distribution`
|
||||
|
||||
## Working notes
|
||||
|
||||
|
||||
Reference in New Issue
Block a user