Skip to content

ADFA-6923: Keep Compose for plugins in release builds - #2220

Open
Daniel-ADFA wants to merge 2 commits into
stagefrom
fix/ADFA-6923
Open

Daniel-ADFA wants to merge 2 commits into
stagefrom
fix/ADFA-6923

Conversation

@Daniel-ADFA

@Daniel-ADFA Daniel-ADFA commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

ADFA-6923

Release builds crash Jetpack Compose Preview with NoSuchMethodError: plugins load parent-first, so the plugin's Compose calls resolve to the IDE's R8-shrunk copy. This adds Compose and the lifecycle, activity and savedstate libraries previews compile against to the plugin-overlap keep rules.

Cost: +6.2 MB uncompressed dex (+2.1 MB compressed). Checked against the R8 output: members user previews can call that the host strips go from 4,915 to 0, and stripped members the plugin's own code reaches from 3 to 0. Not yet run on a device with a release build.

Jetpack Compose Preview bundles Compose, but plugins load parent-first, so
its androidx.compose calls resolve to the IDE's own copy. R8 strips every
member the IDE does not call, and the preview fails with NoSuchMethodError
on release builds only. Add Compose and the runtime libraries it shares with
the IDE to the plugin-overlap keep rules.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.

Tip: disable this comment in your organization's Code Review settings.

@coderabbitai

coderabbitai Bot commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Explain Change →

No actionable comments were generated in the recent review.

Summary

  • Added R8 keep rules for androidx.compose, androidx.lifecycle, androidx.activity, and androidx.savedstate classes. This aims to prevent release-build Compose Preview crashes caused by missing methods in plugin-shared libraries.
  • The rules preserve all classes and members in these packages. This broad scope can increase release app size. The PR description reports a 6.2 MB increase in uncompressed dex after removing rules for packages that previews cannot reach.
  • The PR description reports no remaining method-reference misses in the affected packages.
  • Release-build device validation: not available.

The ProGuard configuration adds keep rules for classes in the AndroidX Compose, Lifecycle, Activity, and Saved State packages.

Changes: AndroidX keep rules

Layer / File(s) Summary
Add AndroidX package keep rules
app/proguard-rules.pro
Added keep rules for the androidx.compose, androidx.lifecycle, androidx.activity, and androidx.savedstate packages.

Estimated code review effort: 1 (Trivial) | ~4 minutes

Possibly related issues

Suggested reviewers: hal-eisen-adfa, davidschachteradfa

Merge Risk: Minimal · up to bb456

The keep rules align with the stated release-build compatibility fix; proceed with normal validation.

Pre-merge checks: Passed 5

Check name Status Explanation
Title check Passed The title clearly identifies the issue key and the main change: keeping Jetpack Compose for plugins in release builds.
Description check Passed The description explains the release-build crash, the parent-first class-loading cause, the keep-rule change, measured size impact, and validation status.
Docstring Coverage Passed No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 0 functions across 0 files. (1 skipped: 1 unsupported.)

Finishing Touches

Generate unit tests (beta)

  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Tip

🎯 Customize your risk assessments

Guide how CodeRabbit assesses merge risk and security architecture risk. Highlight sensitive changes and explain your security boundaries using Merge Risk Instructions and Security Risk Instructions in your review settings. Security architecture risk assessments require the Advanced plan or above.

✅ Automatic approvals, with your rules

Let CodeRabbit approve pull requests once required threads are resolved, pre-merge checks pass, and your risk limits are met. Enable Automatic approvals in review settings, with overrides for teams or file paths.

A rabbit checks the rules at night
Four AndroidX groups stay in sight
Compose, Lifecycle, Activity too
Saved State joins the kept-class crew
The burrow sleeps beneath the moon
While build-time shadows leave the room

Recent review info

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Essentials
  • Run ID: 7583985a-b94c-419b-8e6d-51a4ccf40f6a
Commits

Reviewing files that changed from the base of the PR and between e028963 and bb456ba.

Files selected for processing: 1

  • app/proguard-rules.pro

Included review availability: This review used your included allowance. 4 included reviews remain after this review. Your included PR review attempts over the past 7 days set your current allowance at 5 reviews per hour.

@Daniel-ADFA
Daniel-ADFA requested a review from a team November 4, 2026 05:43
Comment thread app/proguard-rules.pro Outdated
Comment on lines +272 to +279
-keep class androidx.compose.** { *; }
-keep class androidx.collection.** { *; }
-keep class androidx.emoji2.** { *; }
-keep class androidx.lifecycle.** { *; }
-keep class androidx.activity.** { *; }
-keep class androidx.savedstate.** { *; }
-keep class androidx.customview.** { *; }
-keep class androidx.tracing.** { *; }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The are very widely scoped. Is it possible to narrow down a bit?

Also, since the classes are loaded from DEX for the compose preview, can we not also add the dependency's DEX files to the same class loader so that it falls back to those if the IDE itself doesn't have those classes? I think that this will also result in more accurate preview results, since the preview will use the exact libraries the user has configured their project to use, and not what's shipped with the IDE.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Narrowed it a bit in bb456ba, but most of it has to stay. User previews compile on the device against the plugin's compose-jars.zip (Compose, lifecycle, savedstate, activity, core) and load parent-first, so any class the host also ships comes from the host's copy. A preview can call any public member of those libraries, plus the ComposerKt.sourceInformation calls the compiler inserts, which R8 strips. That's the crash. On a stage release build 4,915 of those members are missing: 4,841 in Compose, 36 activity, 35 lifecycle, 3 savedstate. So those four packages stay whole.

collection, emoji2, customview and tracing aren't on the preview classpath. With Compose kept whole, R8 keeps what Compose needs from them, and what's still stripped is only referenced by library classes the plugin never reaches. I dropped those four, which takes the cost from +7.0 MB to +6.2 MB uncompressed (+2.3 to +2.1 MB compressed).

On adding the project's DEX: ComposeClassLoader already does that. The compiled preview, the project's dex (build/intermediates/dex, which has the libraries too) and the plugin's Compose runtime dex all go into one DexClassLoader. It can't fix this crash because the host does have these classes; only some of their members were stripped. Parent-first only falls through on ClassNotFoundException, so the host's copy wins and we get NoSuchMethodError.

Using the project's exact versions would need child-first loading, and I agree previews would be more accurate. Three catches:

  • The plugin's own composables call the same stripped sourceInformation methods, so the preview UI would have to move into that loader too.
  • lifecycle and savedstate would still have to come from the host, because the ComposeView gets its owners from the IDE's activity and Fragment.
  • The project dex only exists after a build.

I'd do that as a follow-up in the plugin and ship this now, since 26.44 and 26.45 users are crashing. Happy to open a ticket for it.

androidx.collection, emoji2, customview and tracing are not on the
preview compile classpath, and R8 already keeps what the kept Compose
classes use from them. The members still stripped are referenced only
by plugin library classes the plugin's own code never reaches.

Cost drops from +7.0 MB to +6.2 MB uncompressed dex.
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.

2 participants