Skip to content

Commit b486bcc

Browse files
authored
Match the app's linked R.jar in the render classpath across AGP forms (#24)
Every ComposeView-backed preview loads androidx.customview.poolingcontainer.R$id at PoolingContainer.<clinit>; that class ships only in the app's AAPT2-linked R.jar, not the runtime jar. The non-KMP render path matched that jar at compile_and_runtime_r_class_jar only, but an app's linked R can live under compile_and_runtime_not_namespaced_r_class_jar depending on the AGP config or version. When it does, the R.jar is dropped from the render classpath, so every preview crashes at ComposeViewAdapter and falls back to the portrait Robolectric path with the @Preview size ignored. Match both forms with the compile_and_runtime*r_class_jar wildcard, the same pattern wireKmpConsumerResources already uses for KMP consuming apps.
1 parent c063316 commit b486bcc

1 file changed

Lines changed: 14 additions & 10 deletions

File tree

compose-nav-graph-gradle/src/main/kotlin/com/github/skydoves/navgraph/gradle/NavGraphGradlePlugin.kt

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -998,18 +998,22 @@ public class NavGraphGradlePlugin : Plugin<Project> {
998998
rClassPath.from(
999999
layout.buildDirectory.dir("intermediates").map { d ->
10001000
// The FULL R closure — this module's R AND every dependency's R, incl. androidx (e.g.
1001-
// androidx.customview.poolingcontainer.R, which a ComposeView-backed preview loads at render). For an
1002-
// app the AAPT2-linked R is under compile_and_runtime_r_class_jar/<variant> (the app links
1003-
// everything); for a library the main R is module-only, so the closure lives under <variant>UnitTest.
1004-
// CRUCIAL: take ONLY the linked `process<…>Resources` R — whose IDs match the unit-test `.ap_` we
1005-
// feed — NOT the sibling `generate<…>StubRFile` R, a stub with PHANTOM ids. With non-transitive R a
1006-
// cross-module `R.string.x` is a non-final field resolved at render time; if the stub (listed first)
1007-
// wins the classloader, the id points at nothing in the `.ap_` → Resources$NotFoundException → a
1008-
// blank/failed render (this is why feature modules that reference another module's R went blank).
1001+
// androidx.customview.poolingcontainer.R$id, which EVERY ComposeView-backed preview loads at render
1002+
// via PoolingContainer.<clinit>; if it's absent the renderer aborts at ComposeViewAdapter and the
1003+
// preview silently falls back to the portrait Robolectric path). The app's AAPT2-linked R jar dir
1004+
// varies by AGP config/version — `compile_and_runtime_r_class_jar` OR
1005+
// `compile_and_runtime_not_namespaced_r_class_jar` — so match BOTH via `compile_and_runtime*r_class_jar`
1006+
// (the same wildcard wireKmpConsumerResources uses for the consuming app); a library's module-only R
1007+
// closure lives under <variant>UnitTest. CRUCIAL: take ONLY the linked `process<…>Resources` R — whose
1008+
// IDs match the unit-test `.ap_` we feed — NOT the sibling `generate<…>StubRFile` R, a stub with
1009+
// PHANTOM ids. With non-transitive R a cross-module `R.string.x` is a non-final field resolved at
1010+
// render time; if the stub (listed first) wins the classloader, the id points at nothing in the `.ap_`
1011+
// → Resources$NotFoundException → a blank/failed render (why feature modules referencing another
1012+
// module's R went blank).
10091013
fileTree(d.asFile).matching {
10101014
include(
1011-
"**/compile_and_runtime_r_class_jar/$v/process*Resources/R.jar",
1012-
"**/compile_and_runtime_r_class_jar/${v}UnitTest/process*Resources/R.jar",
1015+
"**/compile_and_runtime*r_class_jar/$v/process*Resources/R.jar",
1016+
"**/compile_and_runtime*r_class_jar/${v}UnitTest/process*Resources/R.jar",
10131017
)
10141018
}
10151019
},

0 commit comments

Comments
 (0)