Fix Compose Preview runtime dependency version mismatch
Problem
The Compose Preview runtime currently packages hardcoded Compose and Material3 dependencies:
val composeVersion = "1.6.0"
val material3Version = "1.2.0"
These dependencies are converted to DEX and bundled into AndroidIDE assets.
When a user project uses different Compose/Material3 versions, the Preview compiler may successfully compile the user's source code against the project's resolved dependencies, but the generated bytecode is executed against AndroidIDE's bundled Compose runtime.
This can cause runtime ABI mismatches such as:
java.lang.NoSuchMethodError:
No static method darkColorScheme-... in
androidx.compose.material3.ColorSchemeKt
For example:
User project:
Material3 1.x
↓
compilation
↓
bytecode expects method X
AndroidIDE Preview runtime:
Material3 1.2.0
↓
method X is missing
↓
NoSuchMethodError
Proposed solution
Instead of using hardcoded Compose dependency versions for the Preview runtime, use the resolved dependencies from the user's Gradle project.
The Preview pipeline should:
- Trigger a project build/sync when the required Compose DEX files are missing.
- Obtain the resolved Compose-related artifacts for the selected project variant from Gradle.
- Use the actual resolved AAR/JAR files rather than reconstructing dependencies from hardcoded versions.
- Extract "classes.jar" from AARs when necessary.
- Convert the resolved runtime classes to DEX using D8.
- Cache the resulting DEX files.
- Rebuild the cache when the resolved dependency set changes.
Conceptually:
User Project
│
▼
Gradle dependency resolution
│
▼
Resolved Compose artifacts
│
├── runtime
├── ui
├── foundation
├── material3
└── other required dependencies
│
▼
Extract classes.jar
│
▼
D8
│
▼
Preview runtime DEX
│
▼
Compose Preview
Cache invalidation
The DEX cache should not only check whether the DEX file exists.
A dependency fingerprint could be generated from the resolved artifacts, for example:
group:name:version
for every Compose-related dependency.
If the fingerprint changes:
old fingerprint != new fingerprint
the Preview runtime DEX should be regenerated.
If it remains unchanged, the existing DEX can be reused.
Expected result
Compose Preview should execute using the same resolved Compose/Material3 dependency versions that were used to compile the user's project.
This should prevent errors such as:
NoSuchMethodError
NoSuchFieldError
IncompatibleClassChangeError
ClassNotFoundException
caused by mismatched Compose runtime versions.
Additional consideration
The Preview compiler should also use a Compose Compiler plugin compatible with the project's Kotlin compiler.
For Kotlin 2.x, the Preview compiler should use the corresponding Kotlin Compose Compiler plugin rather than the legacy "androidx.compose.compiler:compiler"artifact.
For example:
Kotlin Compiler: 2.3.21
Compose Compiler Plugin: 2.3.21
This should be handled separately from the runtime dependency synchronization described above.
Fix Compose Preview runtime dependency version mismatch
Problem
The Compose Preview runtime currently packages hardcoded Compose and Material3 dependencies:
These dependencies are converted to DEX and bundled into AndroidIDE assets.
When a user project uses different Compose/Material3 versions, the Preview compiler may successfully compile the user's source code against the project's resolved dependencies, but the generated bytecode is executed against AndroidIDE's bundled Compose runtime.
This can cause runtime ABI mismatches such as:
For example:
Proposed solution
Instead of using hardcoded Compose dependency versions for the Preview runtime, use the resolved dependencies from the user's Gradle project.
The Preview pipeline should:
Conceptually:
Cache invalidation
The DEX cache should not only check whether the DEX file exists.
A dependency fingerprint could be generated from the resolved artifacts, for example:
group:name:version
for every Compose-related dependency.
If the fingerprint changes:
old fingerprint != new fingerprint
the Preview runtime DEX should be regenerated.
If it remains unchanged, the existing DEX can be reused.
Expected result
Compose Preview should execute using the same resolved Compose/Material3 dependency versions that were used to compile the user's project.
This should prevent errors such as:
caused by mismatched Compose runtime versions.
Additional consideration
The Preview compiler should also use a Compose Compiler plugin compatible with the project's Kotlin compiler.
For Kotlin 2.x, the Preview compiler should use the corresponding Kotlin Compose Compiler plugin rather than the legacy
"androidx.compose.compiler:compiler"artifact.For example:
This should be handled separately from the runtime dependency synchronization described above.