Repository navigation
ADFA-6923: Keep Compose for plugins in release builds - #2220
Daniel-ADFA wants to merge 2 commits into
Conversation
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.
There was a problem hiding this comment.
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.
|
No actionable comments were generated in the recent review. Summary
Merge Risk:
|
| -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.** { *; } |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
sourceInformationmethods, 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
ComposeViewgets 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.
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.