Repository navigation
Reduce APK size: 107.5 KiB → ~104.5 KiB (already near the floor) #181
Description
Summary
The release APK is already small: v2.07 = 110,058 bytes (107.5 KiB). The app is plain Java with no runtime dependencies (only junit for tests), no native libraries, and the release build already runs R8 (minifyEnabled true, proguard-android-optimize.txt, full mode by default in AGP 8.13) with shrinkResources true. Classes are already renamed and repackaged into a/*, and resource names are obfuscated (res/hU.webp).
The usual big wins don't apply here: there is no appcompat/material to drop, no .so to strip or split per ABI, no Kotlin stdlib, and no locale resources from dependencies. What is left is our own code. Realistic target: about 104–105 KiB (−3 %). One small PR is enough, and it's fine to defer it.
Measured on the CI-built decoder-v2-2.07.apk (no local build).
Measurement
APK (compressed bytes in the zip)
| Entry | Stored as | Size in APK | Share |
|---|---|---|---|
classes.dex (182,856 B uncompressed) |
deflate 48 % | 94,481 | 85.8 % |
| APK Signing Block (v2 sig 1,877 + dependency info 189 + padding to 4 KiB) | — | 4,096 | 3.7 % |
res/hU.webp launcher icon and TV banner, 400×400 lossy |
stored | 3,932 | 3.6 % |
META-INF/ v1 signature (CERT.RSA/SF, MANIFEST.MF) + AGP metadata |
deflate | 2,539 | 2.3 % |
resources.arsc |
stored | 1,772 | 1.6 % |
AndroidManifest.xml |
deflate | 1,562 | 1.4 % |
res/AM.xml (layout) |
deflate | 466 | 0.4 % |
| zip local headers + central directory + EOCD | — | ~1,210 | 1.1 % |
lib/, assets/, kotlin/, extra dex files |
— | none | 0 |
Inside classes.dex (uncompressed)
117 classes, 1,153 method refs, 669 field refs, 1,766 strings.
| Section | Bytes | Share |
|---|---|---|
code (bytecode, 450 methods) |
100,630 | 55 % |
string_data |
35,971 | 20 % |
| ID tables (string/type/proto/field/method/class) | 32,856 | 18 % |
debug_info (21 items) |
5,610 | 3 % |
| class_data, type_list, map, header | 7,789 | 4 % |
Biggest single string: the DebugServer web page (<!doctype html>…), 7,952 B raw, about 3.25 KB deflated. The other human-readable strings (log and UI messages) add about 7 KB raw. The rest of the code is spread across our own sources (Decoder.java alone is about 2,200 lines).
Ideas, ranked by saving
| # | Idea | Estimated saving | Risk / notes |
|---|---|---|---|
| 1 | Re-encode the launcher icon / TV banner at 192–256 px, lossy WebP q≈80 (it is 400×400 now). Measured with Pillow: 192 px q80 = 2,408 B, 160 px q80 = 1,970 B | −1.5…−2.0 KB (−1.4…−1.8 %) | Low. The same bitmap is used as android:banner, so check how it looks in the leanback launcher on the AG-216 / Allwinner boxes before going below 256 px. A vector icon (API 21 has VectorDrawable) could be smaller still, but old TV launchers may render it differently, so it needs a device check |
| 2 | Minify the DebugServer HTML/CSS/JS (indentation, comments). Keep the readable source and minify it in a small Gradle task, or by hand if it stays short | −0.6…−1.0 KB (−0.6…−0.9 %) | Low for the app, but a build-time step adds upkeep. Moving it to assets/ (gzipped or not) saves nothing: the dex is already deflated |
| 3 | Drop the AGP metadata from the APK: dependenciesInfo { includeInApk = false } and vcsInfo.include = false |
~0.1 KB in the zip. The 189 B dependency block is absorbed by the 4 KiB signing-block padding, so about 0 there | None. Optional tidy-up only, not worth a PR of its own |
| 4 | Strip Log.d/Log.v with -assumenosideeffects |
~0.3 KB | Not recommended: LogBuffer reads the app's own logcat lines for the /log debug endpoint (#96), so this would drop diagnostics |
| 5 | Remove the v1 (JAR) signature (v1SigningEnabled false) |
~2.5 KB | Not possible: minSdk 21 (Android 5–6 TV boxes) needs v1. It only becomes possible with minSdk 24+ |
| 6 | ABI splits / AAB / localeFilters / useLegacyPackaging / dropping appcompat or material / Kotlin metadata |
0 | Not applicable: no native libs, no dependencies, one default locale, Java only |
| 7 | Refactor or deduplicate code (e.g. split Decoder.java) for size |
uncertain, likely <2 KB | Not worth it for size alone. R8 already inlines and removes dead code |
Realistic total: about 2.5–3 KB, so 107.5 KiB → ~104.5 KiB (−3 %).
Related finding (not about size, but needed before any R8 change)
The CI workflow does not archive mapping.txt. Release stack traces (from Crash.java / logcat) show only obfuscated names like a.a0, and nobody can retrace them. Proposal: upload android/app/build/outputs/mapping/release/mapping.txt as a workflow artifact, or as a release asset next to the APK. APK size impact: 0.
Do not add -keepattributes SourceFile,LineNumberTable for readable traces without weighing it: that adds a few KB. The mapping file is the cheaper option.
Proposed PRs (in order)
- CI: archive the R8
mapping.txtper build/release (workflow only, no app change, so no version bump). - App: smaller icon/banner + minified DebugServer HTML (+ optional AGP metadata flags). One PR, ~−3 KB. Check the icon and banner on a TV box (leanback launcher) and a phone launcher, and check that the debug web page still works. As with every app PR on v2: versionName +0.01, versionCode +1.
Everything else above is either not applicable or not worth the risk for an APK this size. If nobody needs the extra 3 %, closing this as "already near the floor" is also a valid result.
Activity
ci: keep the R8 mapping.txt of every build as an artifact and attach …
Merge pull request #183 from OpenIPC/ci/r8-mapping-181
Merge pull request #184 from OpenIPC/feat/apk-size-181
compot-dev commentedon Oct 15, 2026
Done in #183 and #184 (v2.08).
mapping.txtfor every build (artifact<name>-mapping) and attaches it to the releases (decoder-v2-mapping.txtonlatest,mapping-<ver>.txton newv2.xx). Older releases stay without a mapping.Checked: the icon on the TECNO KM4 launcher and the Decoder tile in the Android TV app list on the AG-216 are sharp, and the debug page works.
The APK is now close to its floor, so nothing more is planned here.
feat: smaller APK — launcher icon / TV banner 256 px lossless WebP, d…
ci: keep the R8 mapping.txt of every build as an artifact and attach …
Merge pull request #183 from OpenIPC/ci/r8-mapping-181
Merge pull request #184 from OpenIPC/feat/apk-size-181
docs: README trimmed, details in docs/ (#191)