Browse Source

Initial implementation of experimental interop with Jetpack Compose (#1190)

* Initial implementation of experimental interop with Jetpack Compose

* Small refactoring
pull/1205/head
akurasov 3 years ago committed by GitHub
parent
commit
59ab245fdf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 139
      gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/ComposePlugin.kt
  2. 16
      gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/android/AndroidExtension.kt

139
gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/ComposePlugin.kt

@ -9,9 +9,12 @@ package org.jetbrains.compose
import org.gradle.api.Plugin import org.gradle.api.Plugin
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.artifacts.ComponentMetadataContext
import org.gradle.api.artifacts.ComponentMetadataRule
import org.gradle.api.artifacts.dsl.ComponentModuleMetadataHandler import org.gradle.api.artifacts.dsl.ComponentModuleMetadataHandler
import org.gradle.api.artifacts.dsl.DependencyHandler import org.gradle.api.artifacts.dsl.DependencyHandler
import org.gradle.api.plugins.ExtensionAware import org.gradle.api.plugins.ExtensionAware
import org.jetbrains.compose.android.AndroidExtension
import org.jetbrains.compose.desktop.DesktopExtension import org.jetbrains.compose.desktop.DesktopExtension
import org.jetbrains.compose.desktop.application.internal.configureApplicationImpl import org.jetbrains.compose.desktop.application.internal.configureApplicationImpl
import org.jetbrains.compose.desktop.application.internal.currentTarget import org.jetbrains.compose.desktop.application.internal.currentTarget
@ -26,6 +29,7 @@ class ComposePlugin : Plugin<Project> {
override fun apply(project: Project) { override fun apply(project: Project) {
val composeExtension = project.extensions.create("compose", ComposeExtension::class.java) val composeExtension = project.extensions.create("compose", ComposeExtension::class.java)
val desktopExtension = composeExtension.extensions.create("desktop", DesktopExtension::class.java) val desktopExtension = composeExtension.extensions.create("desktop", DesktopExtension::class.java)
val androidExtension = composeExtension.extensions.create("android", AndroidExtension::class.java)
if (!project.buildFile.endsWith(".gradle.kts")) { if (!project.buildFile.endsWith(".gradle.kts")) {
// add compose extension for Groovy DSL to work // add compose extension for Groovy DSL to work
@ -50,54 +54,73 @@ class ComposePlugin : Plugin<Project> {
// we want to avoid creating tasks like package, run, etc. to avoid conflicts with other plugins // we want to avoid creating tasks like package, run, etc. to avoid conflicts with other plugins
configureApplicationImpl(project, desktopExtension.application) configureApplicationImpl(project, desktopExtension.application)
} }
}
fun ComponentModuleMetadataHandler.replaceAndroidx(original: String, replacement: String) { if (androidExtension.useAndroidX) {
module(original) { println("useAndroidX is an experimental feature at the moment!")
it.replacedBy(replacement, "org.jetbrains.compose isn't compatible with androidx.compose, because it is the same library published with different maven coordinates") RedirectAndroidVariants.androidxVersion = androidExtension.androidxVersion
listOf(
RedirectAndroidVariants::class.java,
).forEach(project.dependencies.components::all)
}
fun ComponentModuleMetadataHandler.replaceAndroidx(original: String, replacement: String) {
module(original) {
it.replacedBy(replacement, "org.jetbrains.compose isn't compatible with androidx.compose, because it is the same library published with different maven coordinates")
}
}
//redirecting all android artifacts to androidx.compose
project.dependencies.modules {
if (!androidExtension.useAndroidX) {
// Replace 'androidx.compose' artifacts by 'org.jetbrains.compose' artifacts.
// It is needed, because 'org.jetbrains.compose' artifacts are the same artifacts as 'androidx.compose'
// (but with different version).
// And Gradle will throw an error when it cannot determine which class from which artifact should it use.
//
// Note that we don't provide a configuration parameter to disable dependency replacement,
// because without replacement, gradle will fail anyway because classpath contains two incompatible artifacts.
//
// We should define all replacements, even for transient dependencies.
// For example, a library can depend on androidx.compose.foundation:foundation-layout
//
// List of all org.jetbrains.compose libraries is here:
// https://maven.pkg.jetbrains.space/public/p/compose/dev/org/jetbrains/compose/
//
// (use ./gradle printAllAndroidxReplacements to know what dependencies should be here)
//
// It is temporarily solution until we will be publishing all MPP artifacts in Google Maven repository.
// Or align versions with androidx artifacts and point MPP-android artifacts to androidx artifacts (is it possible?)
listOf(
"androidx.compose.animation:animation",
"androidx.compose.animation:animation-core",
"androidx.compose.compiler:compiler",
"androidx.compose.compiler:compiler-hosted",
"androidx.compose.foundation:foundation",
"androidx.compose.foundation:foundation-layout",
"androidx.compose.material:material",
"androidx.compose.material:material-icons-core",
"androidx.compose.material:material-icons-extended",
"androidx.compose.material:material-ripple",
"androidx.compose.runtime:runtime",
"androidx.compose.runtime:runtime-saveable",
"androidx.compose.ui:ui",
"androidx.compose.ui:ui-geometry",
"androidx.compose.ui:ui-graphics",
"androidx.compose.ui:ui-test",
"androidx.compose.ui:ui-test-junit4",
"androidx.compose.ui:ui-text",
"androidx.compose.ui:ui-unit",
"androidx.compose.ui:ui-util"
).forEach() { module ->
it.replaceAndroidx(
module,
module.replace("androidx.compose", "org.jetbrains.compose")
)
}
}
} }
}
project.dependencies.modules {
// Replace 'androidx.compose' artifacts by 'org.jetbrains.compose' artifacts.
// It is needed, because 'org.jetbrains.compose' artifacts are the same artifacts as 'androidx.compose'
// (but with different version).
// And Gradle will throw an error when it cannot determine which class from which artifact should it use.
//
// Note that we don't provide a configuration parameter to disable dependency replacement,
// because without replacement, gradle will fail anyway because classpath contains two incompatible artifacts.
//
// We should define all replacements, even for transient dependencies.
// For example, a library can depend on androidx.compose.foundation:foundation-layout
//
// List of all org.jetbrains.compose libraries is here:
// https://maven.pkg.jetbrains.space/public/p/compose/dev/org/jetbrains/compose/
//
// (use ./gradle printAllAndroidxReplacements to know what dependencies should be here)
//
// It is temporarily solution until we will be publishing all MPP artifacts in Google Maven repository.
// Or align versions with androidx artifacts and point MPP-android artifacts to androidx artifacts (is it possible?)
it.replaceAndroidx("androidx.compose.animation:animation", "org.jetbrains.compose.animation:animation")
it.replaceAndroidx("androidx.compose.animation:animation-core", "org.jetbrains.compose.animation:animation-core")
it.replaceAndroidx("androidx.compose.compiler:compiler", "org.jetbrains.compose.compiler:compiler")
it.replaceAndroidx("androidx.compose.compiler:compiler-hosted", "org.jetbrains.compose.compiler:compiler-hosted")
it.replaceAndroidx("androidx.compose.foundation:foundation", "org.jetbrains.compose.foundation:foundation")
it.replaceAndroidx("androidx.compose.foundation:foundation-layout", "org.jetbrains.compose.foundation:foundation-layout")
it.replaceAndroidx("androidx.compose.material:material", "org.jetbrains.compose.material:material")
it.replaceAndroidx("androidx.compose.material:material-icons-core", "org.jetbrains.compose.material:material-icons-core")
it.replaceAndroidx("androidx.compose.material:material-icons-extended", "org.jetbrains.compose.material:material-icons-extended")
it.replaceAndroidx("androidx.compose.material:material-ripple", "org.jetbrains.compose.material:material-ripple")
it.replaceAndroidx("androidx.compose.runtime:runtime", "org.jetbrains.compose.runtime:runtime")
it.replaceAndroidx("androidx.compose.runtime:runtime-saveable", "org.jetbrains.compose.runtime:runtime-saveable")
it.replaceAndroidx("androidx.compose.ui:ui", "org.jetbrains.compose.ui:ui")
it.replaceAndroidx("androidx.compose.ui:ui-geometry", "org.jetbrains.compose.ui:ui-geometry")
it.replaceAndroidx("androidx.compose.ui:ui-graphics", "org.jetbrains.compose.ui:ui-graphics")
it.replaceAndroidx("androidx.compose.ui:ui-test", "org.jetbrains.compose.ui:ui-test")
it.replaceAndroidx("androidx.compose.ui:ui-test-junit4", "org.jetbrains.compose.ui:ui-test-junit4")
it.replaceAndroidx("androidx.compose.ui:ui-text", "org.jetbrains.compose.ui:ui-text")
it.replaceAndroidx("androidx.compose.ui:ui-unit", "org.jetbrains.compose.ui:ui-unit")
it.replaceAndroidx("androidx.compose.ui:ui-util", "org.jetbrains.compose.ui:ui-util")
} }
project.tasks.withType(KotlinCompile::class.java) { project.tasks.withType(KotlinCompile::class.java) {
@ -108,6 +131,32 @@ class ComposePlugin : Plugin<Project> {
} }
} }
class RedirectAndroidVariants : ComponentMetadataRule {
override fun execute(context: ComponentMetadataContext) = with(context.details) {
if (id.group.startsWith("org.jetbrains.compose")) {
val group = id.group.replaceFirst("org.jetbrains.compose", "androidx.compose")
val newReference = "$group:${id.module.name}:$androidxVersion"
listOf(
"debugApiElements-published",
"debugRuntimeElements-published",
"releaseApiElements-published",
"releaseRuntimeElements-published"
).forEach { variantNameToAlter ->
withVariant(variantNameToAlter) { variantMetadata ->
variantMetadata.withDependencies { dependencies ->
dependencies.removeAll { true } //there are references to org.jetbrains artifacts now
dependencies.add(newReference)
}
}
}
}
}
companion object {
var androidxVersion: String? = null
}
}
object Dependencies { object Dependencies {
val desktop = DesktopDependencies val desktop = DesktopDependencies
val animation get() = composeDependency("org.jetbrains.compose.animation:animation") val animation get() = composeDependency("org.jetbrains.compose.animation:animation")

16
gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/android/AndroidExtension.kt

@ -0,0 +1,16 @@
package org.jetbrains.compose.android
import org.gradle.api.model.ObjectFactory
import org.gradle.api.plugins.ExtensionAware
import org.gradle.api.tasks.Input
import javax.inject.Inject
abstract class AndroidExtension @Inject constructor(private val objectFactory: ObjectFactory) : ExtensionAware {
@Input
var useAndroidX : Boolean = false
@Input
var androidxVersion: String = "1.0.1" //should be set by CI, but could be overridden in build script
@Input
var mppSolutionGroup: String = "org.jetbrains.compose" //it is added for future use by Google
}
Loading…
Cancel
Save