Add runtime libraries compatibility check for Compose projects
Fixes [CMP-9288](https://youtrack.jetbrains.com/issue/CMP-9288) Check
compose libraries compatibility
<img width="1083" height="264" alt="image"
src="https://github.com/user-attachments/assets/4b321025-7b76-4a8e-a1f8-12a7ddabbd56"
/>
To disable the check there is a new gradle property:
`org.jetbrains.compose.library.compatibility.check.disable`
## Testing
- Added integration tests to verify version mismatches and override
behavior.
## Release Notes
### Features - Gradle Plugin
- Add a compatibility check for runtime libraries to ensure consistency
with the expected Compose version.
Update test projects for Gradle plugin to use direct dependencies
instead of aliases
Describe proposed changes and the issue being fixed
Fixes [CMP-9183](https://youtrack.jetbrains.com/issue/CMP-9183)
## Testing
Existing tests should continue to pass
## Release Notes
N/A
Fixes https://youtrack.jetbrains.com/issue/CMP-8873
## Testing
Tested manually. Swift export is experimental
## Release Notes
### Fixes - Resources
- Update iOS resource copying to an iOS app bundle to support Swift
Export libraries
Deprecate Gradle plugin dependency aliases and provide direct
replacement.
Fixes [CMP-7613](https://youtrack.jetbrains.com/issue/CMP-7613) Consider
deprecating aliases `compose.material3`, etc in favour of using Gradle
version catalog
## Testing
Run a sample app, open build.gradle.kts, apply all suggested
replacements.
## Release Notes
### Migration Notes - Multiple Platforms
- Dependency aliases in Gradle plugin (e.g. `compose.ui`) are now
deprecated. Use provided direct artifact coordinates and add them to the
version catalog.
Support for Compose Resources in native macOS executables.
- Added a new integration test `macosExecutableResources` to verify
resource copying for macOS executables.
- Updated `configureNativeApplication.kt` to pass Compose resource
directories from Kotlin Native binaries to the packaging task.
- Resources are now copied into the `.app/Contents/Resources` directory
for packaged macOS applications.
- Packaging tasks for macOS now depend on the corresponding resource
copying task.
## Testing
Executing tasks: [:compose:test-Gradle(9.0.0)-Agp(8.9.0), --tests,
org.jetbrains.compose.test.tests.integration.ResourcesTest.macosExectuableResources]
## Release Notes
### Fixes - Resources
- Fixed an issue where resources were not copied when packaging the
macOS native target, causing the application to crash when it attempted
to read those resources.
Provides `generateResourceContentHashAnnotation` property for
`generateResourceAccessorsFor*` tasks that defines whether to generate
`@ResourceContentHash` annotation for resource accessors.
The property can be set the following way:
```
tasks.configureEach {
if (this is org.jetbrains.compose.resources.ResourceAccessorsConfiguration) {
generateResourceContentHashAnnotation.set(true)
}
}
```
## Release Notes
### Features - Multiple Platforms
- Provide public API for `@ResourceContentHash` annotation generation
- Updated Gradle to support version 9.0.0.
- Improved Compose resource configuration to handle AGP versions below
8.10 with a fallback implementation.
- Bumped Kotlin to 2.2.0 release and updated related dependencies.
- Adjusted tests to reflect changes in AGP-specific behavior and
logging.
Fixes https://youtrack.jetbrains.com/issue/CMP-8771
## Release Notes
### Fixes - Gradle Plugin
- Support `AGP 9.0.0`
Used by Compose Hot Reload to mark a related accessor as dirty if the
hash is changed after reloading of new accessors.
Fixes [CMP-8513](https://youtrack.jetbrains.com/issue/CMP-8513)
## Release Notes
N/A
Fixes
https://youtrack.jetbrains.com/issue/CMP-8050/Desktop-runRelease-crash-when-upgrade-to-CMP-1.8.0-rc01
`./gradlew runRelease` throws an error:
```
Exception in thread "main" kotlinx.a.g: Serializer for class 'LoginRoute' is not found
```
in this code:
```
import androidx.compose.ui.window.singleWindowApplication
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import kotlinx.serialization.Serializable
fun main() = singleWindowApplication {
NavHost(
navController = rememberNavController(),
startDestination = LoginRoute()
) {
composable<LoginRoute> {}
}
}
@Serializable
data class LoginRoute(val id: Long? = null)
```
with obfuscation enabled:
```
compose.desktop {
application {
mainClass = "MainKt"
nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "org.jetbrains.nav_cupcake"
packageVersion = "1.0.0"
}
buildTypes.release.proguard {
obfuscate.set(true)
}
}
}
```
It crashes because:
- we use `@InternalSerializationApi kotlinx.serialization.serializer`
which is used by Navigation
- it uses reflection underneath. Looks like it tries to find serializer
2 ways:
- Looking at the field `static final LoginRoute.Companion.serializer`
- Looking at the `inner class LoginRoute.Companion` and its name
- The [the
default](https://github.com/Kotlin/kotlinx.serialization/blob/4667a18/rules/common.pro)
rules:
- [no obfuscation] work by the second way, but doesn't work by the first
- [with obfuscation] don't work by both ways
The new rule support the first for both obfuscated/non-obfuscated code
## Details
### Old rules
#### Without obfuscation
```
// LoginRoute.class
public final class LoginRoute {
public static final Companion Companion = new Companion((byte)0);
...
public static final class Companion {
private Companion() {}
}
}
// LoginRoute$Companion.class
public final class Companion {
private Companion() {}
}
```
#### With obfuscation
```
// LoginRoute.class
@Serializable
public final class LoginRoute {
public static final a Companion = new a((byte)0);
...
}
// a.class
public final class a {
private a() {}
}
```
### With new rule
#### Without obfuscation
```
// LoginRoute.class
@Serializable
public final class LoginRoute {
public static final Companion Companion = new Companion((byte)0);
...
public static final class Companion {
private Companion() {}
public final KSerializer<LoginRoute> serializer() {
return (KSerializer<LoginRoute>)LoginRoute.$serializer.INSTANCE;
}
}
}
// LoginRoute$Companion.class
public final class Companion {
private Companion() {}
public final KSerializer<LoginRoute> serializer() {
return (KSerializer<LoginRoute>)LoginRoute.$serializer.INSTANCE;
}
}
```
#### With obfuscation
```
// LoginRoute.class
@Serializable
public final class LoginRoute {
public static final a Companion = new a((byte)0);
...
}
// a.class
public final class a {
private a() {}
public final b serializer() {
return (b)LoginRoute$$serializer.INSTANCE;
}
}
```
## Testing
- new test
- snippet above doesn't produce the error anymore
## Release Notes
### Fixes - Desktop
Fix `runRelease` task when navigation and `obfuscate.set(true)` are used
CompatibilityDistributionTest::testWebJsWasmReconfigured makes sure that
composeCompatibilityBrowserDistribution task can be reconfigured to be
used with arbitrary set of input tasks
## Testing
Pipeline
## Release Notes
N/A
The goal of this particular PR is to make code generated by
composeCompatibilityBrowserDistribution safer in scenarios where
original script was injected (and executed as a consequence of this)
before DOM is loaded
## Testing
Manual
## Release Notes
N/A
## Testing
Clone https://github.com/Schahen/ComposeWebApp and run
```
./gradlew :composeApp: composeCompatibilityBrowserDistribution
```
## Release Notes
### Features - Web
- Introduce composeCompatibilityBrowserDistribution task. This task
combines two prod distributions - for js and for wasm in such way so
that if modern require features are not supported by the consumer
browser, application switch to js mode.
---------
Co-authored-by: Oleksandr Karpovich <a.n.karpovich@gmail.com>
Co-authored-by: Konstantin Tskhovrebov <konstantin.tskhovrebov@jetbrains.com>
Fixes
https://youtrack.jetbrains.com/issue/CMP-8268/Decouple-material3-versioning-from-Compose
## Release Notes
### Migration Notes - Multiple Platforms
- Material3 versioning is decoupled for the CMP 1.9.0 release due the
upstream Jetpack Compose Material3 1.4 has not been released as stable
yet
- `compose.material3` now points to the latest stable Material3 version,
1.8.2. If the latest Material3 features are needed, please include it
this way:
```
implementation("org.jetbrains.compose.material3:material3:1.9.0-alpha04")
```
Fixes https://youtrack.jetbrains.com/issue/CMP-8425
## Testing
Updated the relevant test
## Release Notes
### Highlights - Web
- Setting `org.jetbrains.compose.experimental.jscanvas.enabled=true` is
not required anymore when having a kotlin/js target
Problem is the new AGP androidLibrary target has `platformType ==
KotlinPlatformType.jvm` as well.
Fixes https://youtrack.jetbrains.com/issue/CMP-8325
## Testing
Unit tests
## Release Notes
N/A
After https://github.com/JetBrains/compose-multiplatform-core/pull/2097
is merged, CI fails with:
```
Warning: com.jetbrains.JBR: can't find referenced method 'java.lang.Object invokeExact(java.lang.Class,java.lang.Class,java.lang.Class,java.lang.Class,java.util.Map,java.util.function.Function)' in library class java.lang.invoke.MethodHandle
Warning: com.jetbrains.JBR: can't find referenced method 'java.lang.Object invokeExact(java.lang.invoke.MethodHandles$Lookup)' in library class java.lang.invoke.MethodHandle
<============-> 96% EXECUTING [3s] Warning: there were 2 unresolved references to library class members.aseJars
You probably need to update the library versions.-crash-in-the-field
(https://www.guardsquare.com/proguard/manual/troubleshooting#unresolvedlibraryclassmember)
Unexpected error
java.io.IOException: Please correct the above warnings first.
```
During Gradle tests.
## Testing
Tests for Gradle plugin pass
## Release Notes
### Fixes - Desktop
N/A
When users use `androidx.navigation`, they see `@Serialization`
annotation they can use, without explictly adding
`kotlinx.serialization`. They see, because it is added as an `api`
dependency.
The Compose Gradle plugin on the other hand provide `./gradlew
runRelease` task that uses ProGuard to minify binaries. Because the
plugin should support not only Compose, but also all support libraries
(androidx, components), we should bundle serialization ProGuard rules
into it.
Fixes https://youtrack.jetbrains.com/issue/CMP-8050
## Testing
```
import androidx.compose.ui.window.singleWindowApplication
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
fun main() = singleWindowApplication {
NavHost(
navController = rememberNavController(),
startDestination = LoginRoute()
) {
composable<LoginRoute> {}
}
}
sealed interface Route
@kotlinx.serialization.Serializable
data class LoginRoute(val id: Long? = null) : Route
```
Doesn't crash when run `./gradlew runRelease`
## Release Notes
### Fixes - Desktop
- Fix "Serializer for class is not found" using `androidx.navigation`
and running `./gradlew runRelease`
- `kotlinx.serialization` ProGuard rules are bundled in the Compose
Gradle plugin
Updated the test to use a more relevant project setup and refined checks
for resource handling. Improved validation by verifying resource files
in the generated JAR.
## Release Notes
N/A
Gradle Plugin DSL to change the generated Res class name:
```kotlin
compose.resources {
nameOfResClass = "MyRes"
}
```
Fixes [CMP-7341](https://youtrack.jetbrains.com/issue/CMP-7341) Support
generating custom resource class name
## Testing
Integration tests.
## Release Notes
### Features - Resources
- Gradle Plugin DSL to change the generated Res class name
Co-authored-by: Omico <me@omico.icu>
Refactor resource accessors generator to minify output source files.
- Number of items per file was decreased to 100
- Common part of the path extracted to the private const
- Added imports
- Removed the private object with item's properties
- The file structure was reorganized
Fixes [CMP-7934](https://youtrack.jetbrains.com/issue/CMP-7934) Too
large String0.commonMain.kt will break code insight feature in AS
## Testing
Integration tests.
This should be tested by QA
## Release Notes
### Fixes - Resources
- Fix IDE highlighting/resoulution when a generated file with resource
accessors is too big