|
|
|
@@ -0,0 +1,143 @@
|
|
|
|
|
# DEX Optimization (Play Console metrics) Implementation Plan
|
|
|
|
|
|
|
|
|
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
|
|
|
|
|
|
|
|
**Goal:** Raise Play Console DEX metrics (shrink/obfuscation/optimization currently 40-42%, level Medium) by removing redundant blanket ProGuard keep rules, then verify the app still works end-to-end on a physical device.
|
|
|
|
|
|
|
|
|
|
**Architecture:** Flutter Android app whose DEX (1.1MB, 1165 classes) is ~40% pinned by legacy `io.flutter.** { *; }` blanket keep rules. Flutter's built-in `flutter_proguard_rules.pro` (auto-applied from the Flutter SDK gradle package) already keeps `FlutterPlugin` implementations with `allowobfuscation`, plus manifest keeps and `@Keep` annotations cover the rest. Strip the redundant rules, add standard R8 hardening flags, rebuild, verify DEX size reduction, smoke-test on a physical device (Redmi A5 over adb/usbipd), then commit.
|
|
|
|
|
|
|
|
|
|
**Tech Stack:** Flutter 3.47.4, AGP 9.0.0, Gradle 9.1.0, R8 (full mode default), Android SDK 36, adb via usbipd WSL passthrough.
|
|
|
|
|
|
|
|
|
|
**Spec:** In-conversation analysis (2026-09-17) — Play Console reported: DEX code optimization Medium, optimization 40%, obfuscation 42%, shrinking 41%. Root cause: blanket keep rules. Expected outcome: shrink/obfuscation ~65-75%, never 100% (remaining DEX is genuinely used plugin code). Baseline-profile work explicitly OUT OF SCOPE.
|
|
|
|
|
|
|
|
|
|
## Global Constraints
|
|
|
|
|
|
|
|
|
|
- Working dir: `/mnt/d/Flutter_Projects/TimbanganSiab` (git branch `main`; user explicitly authorized committing directly to `main`)
|
|
|
|
|
- Release build command (exact): `flutter build appbundle --release --obfuscate --split-debug-info=build/debug-info --dart-define=SIAB_DEVICE_NAME=SIAB`
|
|
|
|
|
- `flutter install` takes NO `--dart-define` flag; build APK with the flag first, then `adb install -r`
|
|
|
|
|
- PATH required: `export PATH="/home/ifitworks/flutter/bin:/mnt/d/android-sdk/platform-tools:$PATH"`
|
|
|
|
|
- Device: Redmi A5 (serial `863d0058304831323851054b1c83ab`), app id `id.ptsemangat.siab_scale`, installed copy is signed with release key
|
|
|
|
|
- If device missing from `adb devices`: `"/mnt/c/Program Files/usbipd-win/usbipd.exe" attach --wsl --busid 1-2`
|
|
|
|
|
- Baseline DEX size (pre-change): `classes.dex` = 1097572 bytes
|
|
|
|
|
- No new dependencies. No `git push` (user runs push themselves).
|
|
|
|
|
- Do NOT touch: `gradle.properties` migrator flags (`android.builtInKotlin=false`, `android.newDsl=false`), settings.gradle.kts versions, workflow file.
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
### Task 1: Strip redundant ProGuard keep rules
|
|
|
|
|
|
|
|
|
|
**Files:**
|
|
|
|
|
- Modify: `android/app/proguard-rules.pro` (full rewrite)
|
|
|
|
|
|
|
|
|
|
**Interfaces:**
|
|
|
|
|
- Consumes: nothing (config file only)
|
|
|
|
|
- Produces: rules consumed by R8 during release build in Task 2
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 1: Replace entire contents of `android/app/proguard-rules.pro` with:**
|
|
|
|
|
|
|
|
|
|
```proguard
|
|
|
|
|
# Play Core deferred components
|
|
|
|
|
-dontwarn com.google.android.play.core.**
|
|
|
|
|
-dontwarn com.google.android.play.core.splitcompat.**
|
|
|
|
|
-dontwarn com.google.android.play.core.splitinstall.**
|
|
|
|
|
-dontwarn com.google.android.play.core.tasks.**
|
|
|
|
|
|
|
|
|
|
# Aggressive R8 optimization (missing from default configs)
|
|
|
|
|
-allowaccessmodification
|
|
|
|
|
-repackageclasses ''
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Removed (verified redundant): all 5 `io.flutter.**` keep lines (Flutter SDK auto-applies `flutter_proguard_rules.pro` which keeps `FlutterPlugin` implementors with `allowobfuscation`; JNI natives use `@Keep`; app methods are `@Keep`d by GeneratedPluginRegistrant), `-keep class id.ptsemangat.siab_scale.** { *; }` (manifest keeps `MainActivity`, `@Keep` on `GeneratedPluginRegistrant`), `-keep class com.lib.flutter_blue_plus.**`, `-keep class com.tekartik.sqflite.**` (both instantiated statically in `GeneratedPluginRegistrant` + covered by Flutter's FlutterPlugin rule).
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 2: Commit**
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
git add android/app/proguard-rules.pro
|
|
|
|
|
git commit -m "perf: strip redundant blanket proguard keeps for DEX shrink/obfuscation"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
### Task 2: Rebuild AAB and verify R8 output
|
|
|
|
|
|
|
|
|
|
**Files:**
|
|
|
|
|
- Create/replace: `build/app/outputs/bundle/release/app-release.aab`, `build/app/outputs/mapping/release/mapping.txt`
|
|
|
|
|
|
|
|
|
|
**Interfaces:**
|
|
|
|
|
- Consumes: Task 1 rules
|
|
|
|
|
- Produces: smaller AAB + mapping for Task 3/4
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 1: Build**
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
export PATH="/home/ifitworks/flutter/bin:/mnt/d/android-sdk/platform-tools:$PATH"
|
|
|
|
|
cd /mnt/d/Flutter_Projects/TimbanganSiab
|
|
|
|
|
flutter build appbundle --release --obfuscate --split-debug-info=build/debug-info --dart-define=SIAB_DEVICE_NAME=SIAB
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Expected: `✓ Built ... app-release.aab`. Fail if build fails.
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 2: Verify DEX shrank and mapping regenerated**
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
unzip -p build/app/outputs/bundle/release/app-release.aab base/dex/classes.dex | wc -c
|
|
|
|
|
# must be < 1097572 (baseline)
|
|
|
|
|
ls -la build/app/outputs/mapping/release/mapping.txt
|
|
|
|
|
# must exist, freshly created
|
|
|
|
|
grep -c "^io.flutter" build/app/outputs/mapping/release/mapping.txt || true
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 3: Check build log for R8 missing-class warnings** — if any `Missing class` warnings appear, add ONLY `-dontwarn <exact.class>` lines for those classes (append to proguard-rules.pro), never `-keep`.
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 4: Record actual DEX size in report; no commit needed (build outputs are gitignored).**
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
### Task 3: On-device smoke test (Redmi A5)
|
|
|
|
|
|
|
|
|
|
**Files:**
|
|
|
|
|
- Installs `app-release.apk` to device
|
|
|
|
|
|
|
|
|
|
**Interfaces:**
|
|
|
|
|
- Consumes: Task 2 build config; same flags for APK build
|
|
|
|
|
- Produces: pass/fail runtime evidence for Task 4
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 1: Ensure device present** — if `adb devices` empty or `no permissions`: `"/mnt/c/Program Files/usbipd-win/usbipd.exe" attach --wsl --busid 1-2; sleep 5; adb kill-server; adb devices -l`. Need status `device`.
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 2: Build + install**
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
export PATH="/home/ifitworks/flutter/bin:/mnt/d/android-sdk/platform-tools:$PATH"
|
|
|
|
|
cd /mnt/d/Flutter_Projects/TimbanganSiab
|
|
|
|
|
flutter build apk --release --obfuscate --split-debug-info=build/debug-info --dart-define=SIAB_DEVICE_NAME=SIAB
|
|
|
|
|
adb install -r build/app/outputs/flutter-apk/app-release.apk
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Expected: `Success`. If `INSTALL_FAILED_UPDATE_INCOMPATIBLE` → `adb uninstall id.ptsemangat.siab_scale` then retry.
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 3: Launch + crash scan**
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
adb logcat -c
|
|
|
|
|
adb shell monkey -p id.ptsemangat.siab_scale -c android.intent.category.LAUNCHER 1
|
|
|
|
|
sleep 12
|
|
|
|
|
adb shell pidof id.ptsemangat.siab_scale # must print PID (app alive)
|
|
|
|
|
adb logcat -d | grep -iE "FATAL|NoClassDef|NoSuchMethod|UnsatisfiedLink|ClassNotFoundException" | head -20
|
|
|
|
|
# expected: no matches
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 4: Manual checks by user** (blocks Task 4): BLE scan lists devices; weighing screen loads; history screen loads (sqflite); CSV share works (share_plus). Record user confirmation in report.
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
### Task 4: Commit and hand off push
|
|
|
|
|
|
|
|
|
|
**Files:** none beyond Task 1 commit (verify clean `git status` except gitignored build/)
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 1:** `git status` — confirm only build/ artifacts untracked; commit anything from Task 2 Step 3 if proguard file changed again.
|
|
|
|
|
- [ ] **Step 2:** Report: baseline vs new DEX sizes, mapping exists, device test result, user manual-check confirmation.
|
|
|
|
|
- [ ] **Step 3:** Print push command for user (does NOT run push — needs user auth):
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
git push origin main
|
|
|
|
|
```
|