Skip to content

Add R8 minification and baseline/startup profiles to Android - #11

Merged
jakepurple13 merged 1 commit into
masterfrom
android-r8-baseline-profiles
Oct 15, 2026
Merged

jakepurple13 merged 1 commit into
masterfrom
android-r8-baseline-profiles

Conversation

@jakepurple13

Copy link
Copy Markdown
Owner

Summary

Turns on R8 for the Android release build and adds baseline and startup profiles that are generated on CI. Also updates AGP and all libraries, since AGP 9 is needed for the profile tooling.

Results (release build, measured on a physical S6003L, API 31)

Before After
Release APK 19.8 MB 4.86 MB (−75%)
Dex (uncompressed) 56.3 MB 3.8 MB

Cold startup, median of 10 runs:

Without profile With profile
Time to initial display 1803 ms 1127 ms
Time to full display 1942 ms 1175 ms (−39.5%)

Changes

Build updates

  • AGP 8.12.3 → 9.4.1, Gradle 8.13 → 9.8.1, Kotlin 2.2.21 → 2.4.21, Compose Multiplatform 1.10.0-beta01 → 1.12.2, KSP → 2.3.12, and every other library bumped to its latest stable version.
  • :common and :storage now use com.android.kotlin.multiplatform.library. AGP 9 no longer allows KMP together with com.android.library.
  • :android uses AGP's built-in Kotlin instead of kotlin("android").
  • Room KSP moves from ksp to kspAndroid, which matches what it generated before.
  • compileSdk is 37 because several libraries require it. targetSdk stays at 36.
  • The iosX64 target is removed because Compose 1.12 no longer publishes it.
  • kotlinx.datetime.Clock → kotlin.time.Clock, and an opt-in for DeferredTargetAnimation (now stable) is removed.
  • Removed ui-test-junit4-android from the app's runtime dependencies. Nothing used it, and it was shipping in the APK.

Minification

  • Release has isMinifyEnabled and isShrinkResources on, using proguard-android-optimize.txt.
  • proguard-rules.pro is empty because R8 reported no missing keep rules.

Profiles

  • New :baselineprofile module.
    • BaselineProfileGenerator plays a short game (draw, Auto Move, Undo, Settings drawer, New Game) and emits both a baseline profile and a startup profile. The startup profile drives dexLayoutOptimization.
    • StartupBenchmarks compares cold startup with no compilation against cold startup with the profile required.
  • ReportDrawn() is added in MainActivity so time to full display is measured. The Settings and New Game icon buttons get content descriptions, which the test uses and screen readers benefit from.
  • <profileable android:shell="true"> is added to the manifest.

CI

  • A new baselineProfile job runs on a Gradle Managed Device (Pixel 6, API 34, AOSP image) with KVM. It uploads the generated profiles as an artifact.
  • The aab and apk jobs now depend on that job and download the fresh profiles before building. The committed profiles in android/src/release/generated/baselineProfiles/ are the local fallback.

Testing

  • The minified release build was installed on a device and the main flows were tested: new game, draw, Auto Move, Undo, Settings, New Game, and restoring a saved game.
  • Profile generation was run locally on the managed-device emulator twice and on a physical device.
  • The :desktop JVM and :common wasm targets compile.
  • iosMain still fails to compile, as it did before: its dependency on storage is commented out.

Notes

  • The workflow ignores .github/** and only runs on pushes to master, so this PR doesn't trigger it. Use Run workflow on this branch to try it before merging.
  • Generation passes a test class filter so only the generator runs. When the skipped benchmark tests ran in the same pass, the plugin intermittently failed to find the generated profile.
  • .gitignore also contains a .hotswan/ entry that was already uncommitted in the working tree.

🤖 Generated with Claude Code

- Update AGP to 9.4.1, Gradle to 9.8.1, Kotlin to 2.4.21, Compose
  Multiplatform to 1.12.2 and all libraries to latest stable.
- Migrate :common and :storage to com.android.kotlin.multiplatform.library
  (required by AGP 9), use built-in Kotlin in :android, and move Room KSP
  to kspAndroid. Drop the iosX64 target (unsupported by Compose 1.12).
- Bump compileSdk to 37 (required by updated libraries); targetSdk stays 36.
- Migrate kotlinx.datetime.Clock to kotlin.time.Clock.
- Enable R8 and resource shrinking for release.
- Add :baselineprofile module with a generator that also emits a startup
  profile, plus startup macrobenchmarks. Add ReportDrawn and content
  descriptions on the settings/new game icons.
- Generate profiles on CI with a Gradle Managed Device emulator and feed
  them into the APK and AAB builds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jakepurple13
jakepurple13 merged commit 43e408e into master Oct 15, 2026
6 checks passed
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