Skip to content

build: compress DEX and native libs in APK (legacy packaging) - #364

Draft
TimeToBuildBob wants to merge 1 commit into
ActivityWatch:masterfrom
TimeToBuildBob:apk-size-legacy-packaging
Draft

TimeToBuildBob wants to merge 1 commit into
ActivityWatch:masterfrom
TimeToBuildBob:apk-size-legacy-packaging

Conversation

@TimeToBuildBob

@TimeToBuildBob TimeToBuildBob commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Proposes dex.useLegacyPackaging = true and jniLibs.useLegacyPackaging = true in mobile/build.gradle, compressing DEX and native-library ZIP entries. The current diff applies to both universal and per-ABI APKs; it is not a universal-only change.

Related: #61. This is a packaging experiment, not an issue-closing fix or an IzzyOnDroid relisting path.

Distribution decision still needed

IzzySoft's follow-up confirms that ActivityWatch is not eligible for IzzyOnDroid under its no-LLM policy. A smaller APK does not change that decision.

The remaining motivation is reducing download/transfer cost, especially for the universal APK. Compressing native libraries requires extraction on install, trading smaller APKs against extraction overhead and an additional native-library copy on device. Universal and single-ABI builds have different trade-offs; do not infer installed-size savings from download savings alone.

Before adopting this globally, maintainers should decide whether compression should be universal-only or also apply to per-ABI builds, and clarify F-Droid's preference as IzzySoft suggested. This PR does not establish that preference.

Verification

Current-head tests passed, including the release-variant R8 smoke test and Android API 29 E2E check. The APK build matrix was skipped, so these checks do not provide before/after release APK size measurements or installed-footprint evidence.

Still required before choosing a default: comparable universal/per-ABI build sizes, installed-footprint and startup checks for the compressed native-library path, and a maintainer decision on distribution scope. The size reductions discussed in the issue remain estimates, not measurements of this PR.

Sets dex.useLegacyPackaging = true and jniLibs.useLegacyPackaging = true
so that DEX and .so files are stored compressed rather than uncompressed.

Per-ABI APKs are currently 61–73 MB uncompressed. IzzyOnDroid maintainer
estimates legacy packaging reduces APK size by 30–40 MB, potentially
bringing arm64 within the ~30 MB per-app limit.

Trade-off: compressed .so prevents Android 9+ from mmapping the library
directly from the APK zip, adding extraction overhead on install/update.
The size benefit is significant enough for third-party repo distribution.

Closes: ActivityWatch#61 (pending CI measurement)
Git-Session-Id: 63be8af6-6fc3-4ea8-9852-4cf1b5219c81
@TimeToBuildBob

TimeToBuildBob commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor Author

🤖 AI code review

Adds a packaging block to mobile/build.gradle that sets useLegacyPackaging = true for both dex and jniLibs, forcing DEX and native libraries to be stored compressed in APKs. This is intended to reduce APK download size for distribution channels with size limits, at the cost of requiring extraction of native libraries at install time.

Safe to merge — no P0/P1 findings

Confidence 5/5

✅ No findings. The diff looks correct to me on this pass.

Files changed (1) — the diff as I read it
  • mobile/build.gradle — Adds a packaging block with dex.useLegacyPackaging = true and jniLibs.useLegacyPackaging = true.
Previous review passes
commit score findings engine when
59b89c1963fa 5/5 0 llm 2026-10-11 18:22 UTC

Reviewed 59b89c1963fa · openrouter/deepseek/deepseek-v4-flash-0731 · llm engine · 15s · about this reviewer

Maintainer commands

@TimeToBuildBob review (own line) — fresh review · @TimeToBuildBob fix — a worker acts on the findings. Once per comment; 👀 = received.

@TimeToBuildBob

TimeToBuildBob commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor Author

Updated after IzzySoft's clarification on ActivityWatch/aw-android#61: this PR is now draft, not waiting only on a merge click.

IzzyOnDroid relisting is ruled out under its no-LLM policy. The diff currently enables compression globally, while universal and per-ABI builds have different download/installed-storage trade-offs. The APK build matrix was skipped, so passing tests do not supply the promised size comparison.

Removed the issue-closing claim from the description. Maintainer distribution-scope/F-Droid preference and measured APK/installed-footprint evidence remain prerequisites to selecting a default; no code change or merge made.

@TimeToBuildBob
TimeToBuildBob marked this pull request as draft October 11, 2026 20:06
@TimeToBuildBob TimeToBuildBob mentioned this pull request Oct 11, 2026
@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

@greptileai review

@greptile-apps

greptile-apps Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 5/5

[High impact] No actionable defect was found; the packaging change appears safe to merge.

Summary

Enables useLegacyPackaging for DEX and native libraries in mobile/build.gradle, applying compression to both universal and per-ABI APKs.

  • Android APKs compress DEX files and native libraries.

Reviews (1) · Last reviewed commit: "build: compress DEX and native libs in A..." · Reviewed by Greptile

@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

Measured compression effect on the published v0.14.3 APKs

The build matrix is skipped on PRs, so there is no before/after APK measurement from CI. I measured the compression effect directly against the published v0.14.3 artifacts instead (byte sizes match the release assets exactly; SHA-256 verified for the four per-ABI APKs, universal downloaded from the release).

Method: useLegacyPackaging = true for dex/jniLibs changes how those ZIP entries are stored (STORED → DEFLATE). I read each published APK, re-deflated every lib/**.so and classes*.dex entry at zlib level 6 (≈ the JDK Deflater default), and compared against the current stored size. This is a recompression estimate on real artifacts, not a rebuild — the actual AGP deflate stream may differ slightly.

One finding first: the dex half of this PR is a no-op

classes.dex is already DEFLATED in the published APKs (2,970,528 → 947,116 bytes); its compress_size equals the deflate size. So dex.useLegacyPackaging = true changes nothing here — all of the effect comes from jniLibs. Worth knowing before anyone reasons about the DEX side.

Download size (native libs are currently STORED)

APK current est. after saving %
arm64-v8a 70.56 MB 25.40 MB 45.16 MB 64.0%
armeabi-v7a 61.40 MB 23.47 MB 37.94 MB 61.8%
x86 73.20 MB 26.25 MB 46.95 MB 64.1%
x86_64 73.13 MB 25.77 MB 47.36 MB 64.8%
universal 271.24 MB 93.84 MB 177.40 MB 65.4%

The native payloads compress ~2.9×, roughly 4 MB better than the ~30 MB / "around 40 MB" figures in #61 — the per-ABI APKs would land at ~24-26 MB.

Installed footprint is where universal and per-ABI diverge

Legacy packaging also sets extractNativeLibs=true, so libs are extracted at install rather than mmapped from the APK. Derived (not measured) on an arm64 device:

  • Universal: ≈ 94 MB APK + ≈ 69 MB extracted arm64 libs ≈ 163 MB, versus ≈ 271 MB today — better on both axes (the non-matching ABI libs stay compressed inside the APK instead of sitting on disk).
  • Per-ABI: ≈ 25 MB APK + ≈ 69 MB extracted libs ≈ 94 MB, versus ≈ 70.6 MB today — a ~24 MB installed regression traded for the ~45 MB download saving.

So the universal-only option this PR leaves open is the one with no installed-footprint penalty; the global option costs per-ABI installs ~24 MB and an install-time extraction step.

Not verified

  • No startup measurement for the extracted-library path (no Java/emulator toolchain here); the mechanism is extraction at first launch.
  • No real rebuild, so AGP's actual deflate output is unconfirmed.

I'm not selecting a default — that's the maintainer scope decision this PR is waiting on. But the data reframes it: it is no longer "universal vs global at ~30-40 MB", it is "universal is a strict win on both axes; global trades ~24 MB of per-ABI installed storage for the download saving." Given IzzyOnDroid relisting is ruled out on policy (not size), the remaining question is whether download size alone justifies that per-ABI cost.

Head: 59b89c1963fa1eabb336560c1d6a5349096187fb

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant