Skip to content

Commit 1aefaa0

Browse files
terrakokKpotko
authored andcommitted
Configure compose resources in XCFrameworks.
(cherry picked from commit e5a45e4)
1 parent e7e8e12 commit 1aefaa0

File tree

22 files changed

+348
-243
lines changed

22 files changed

+348
-243
lines changed

gradle-plugins/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ subprojects {
1717
mavenCentral()
1818
google()
1919
mavenLocal()
20+
maven("https://packages.jetbrains.team/maven/p/kt/dev")
2021
}
2122

2223
plugins.withId("java") {

gradle-plugins/compose/build.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ dependencies {
5757

5858
compileOnly(gradleApi())
5959
compileOnly(localGroovy())
60-
compileOnly(kotlin("gradle-plugin"))
60+
//the version supports XCFramework with resources https://youtrack.jetbrains.com/issue/KT-75823
61+
compileOnly(kotlin("gradle-plugin", "2.2.0-Beta2-1"))
6162
compileOnly(kotlin("native-utils"))
6263
compileOnly(libs.plugin.android)
6364
compileOnly(libs.plugin.android.api)

gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/resources/ComposeResources.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ private fun Project.onKgpApplied(config: Provider<ResourcesExtension>, kgp: Kotl
3636

3737
if (kmpResourcesAreAvailable) {
3838
configureMultimoduleResources(kotlinExtension, config)
39+
configureXCFrameworkComposeResources(kotlinExtension, kgp)
3940
} else {
4041
if (!disableMultimoduleResources) {
4142
if (!hasKmpResources) logger.info(
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package org.jetbrains.compose.resources
2+
3+
import org.gradle.api.Project
4+
import org.jetbrains.compose.internal.Version
5+
import org.jetbrains.kotlin.gradle.ComposeKotlinGradlePluginApi
6+
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
7+
import org.jetbrains.kotlin.gradle.plugin.KotlinBasePlugin
8+
import org.jetbrains.kotlin.gradle.plugin.extraProperties
9+
import org.jetbrains.kotlin.gradle.plugin.mpp.Framework
10+
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
11+
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFrameworkTask
12+
import org.jetbrains.kotlin.gradle.plugin.mpp.resources.KotlinTargetResourcesPublication
13+
14+
private const val MIN_KGP_VERSION_FOR_XCFRAMEWORK_RESOURCES = "2.2.0-Beta2-1"
15+
16+
@OptIn(ComposeKotlinGradlePluginApi::class)
17+
internal fun Project.configureXCFrameworkComposeResources(
18+
kotlinExtension: KotlinMultiplatformExtension,
19+
kgp: KotlinBasePlugin
20+
) {
21+
val kgpVersion = Version.fromString(kgp.pluginVersion)
22+
val kmpResources = extraProperties.get(KMP_RES_EXT) as KotlinTargetResourcesPublication
23+
val requiredVersion = Version.fromString(MIN_KGP_VERSION_FOR_XCFRAMEWORK_RESOURCES)
24+
val isAvailable = kgpVersion >= requiredVersion
25+
26+
tasks.withType(XCFrameworkTask::class.java).configureEach { task ->
27+
if (isAvailable) {
28+
logger.info("Configure compose resources in ${task.name}")
29+
kotlinExtension.targets
30+
.withType(KotlinNativeTarget::class.java)
31+
.configureEach { target ->
32+
target.binaries.withType(Framework::class.java).configureEach { framework ->
33+
task.addTargetResources(
34+
resources = kmpResources.resolveResources(target),
35+
target = framework.target.konanTarget
36+
)
37+
}
38+
}
39+
} else {
40+
logger.warn("Compose resources are supported in XCFrameworks " +
41+
"since '$MIN_KGP_VERSION_FOR_XCFRAMEWORK_RESOURCES' Kotlin Gradle plugin version")
42+
}
43+
}
44+
}

gradle-plugins/compose/src/test/kotlin/org/jetbrains/compose/test/tests/integration/ResourcesTest.kt

Lines changed: 185 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,124 @@ class ResourcesTest : GradlePluginTestBase() {
612612
}
613613
}
614614

615+
@Test
616+
fun xcframeworkResourcesAreNotSupported() {
617+
Assumptions.assumeTrue(currentOS == OS.MacOS)
618+
619+
with(
620+
testProject(
621+
"misc/appleResources",
622+
defaultTestEnvironment.copy(kotlinVersion = "2.1.0"))
623+
) {
624+
file("build.gradle.kts").modify { content ->
625+
"""
626+
|import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework
627+
|
628+
|plugins {
629+
| kotlin("multiplatform")
630+
| kotlin("plugin.compose")
631+
| id("org.jetbrains.compose")
632+
|}
633+
|
634+
|kotlin {
635+
| val xcf = XCFramework("ComposeApp")
636+
|
637+
| macosArm64()
638+
|
639+
| listOf(
640+
| iosX64(),
641+
| iosArm64(),
642+
| iosSimulatorArm64()
643+
| ).forEach {
644+
| it.binaries.framework {
645+
| baseName = "ComposeApp"
646+
| isStatic = true
647+
| xcf.add(this)
648+
| }
649+
| }
650+
|
651+
| sourceSets {
652+
| commonMain {
653+
| dependencies {
654+
| implementation(compose.runtime)
655+
| implementation(compose.material)
656+
| implementation(compose.components.resources)
657+
| }
658+
| }
659+
| }
660+
|}
661+
|
662+
""".trimMargin()
663+
}
664+
gradle(":assembleComposeAppDebugXCFramework", "--dry-run").checks {
665+
check.logContains("Compose resources are supported in XCFrameworks since '2.2.0-Beta2-1' Kotlin Gradle plugin version")
666+
}
667+
}
668+
}
669+
670+
@Test
671+
fun xcframeworkResources() {
672+
Assumptions.assumeTrue(currentOS == OS.MacOS)
673+
with(
674+
testProject(
675+
"misc/appleResources",
676+
defaultTestEnvironment.copy(kotlinVersion = "2.2.0-Beta2-1"))
677+
) {
678+
file("build.gradle.kts").modify { content ->
679+
"""
680+
|import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework
681+
|
682+
|plugins {
683+
| kotlin("multiplatform")
684+
| kotlin("plugin.compose")
685+
| id("org.jetbrains.compose")
686+
|}
687+
|
688+
|kotlin {
689+
| val xcf = XCFramework("ComposeApp")
690+
|
691+
| macosX64()
692+
|
693+
| listOf(
694+
| macosArm64(),
695+
| iosArm64()
696+
| ).forEach {
697+
| it.binaries.framework {
698+
| baseName = "ComposeApp"
699+
| isStatic = true
700+
| xcf.add(this)
701+
| }
702+
| }
703+
|
704+
| sourceSets {
705+
| commonMain {
706+
| dependencies {
707+
| implementation(compose.runtime)
708+
| implementation(compose.material)
709+
| implementation(compose.components.resources)
710+
| }
711+
| }
712+
| }
713+
|}
714+
|
715+
""".trimMargin()
716+
}
717+
gradle(":assembleComposeAppDebugXCFramework", "--dry-run").checks {
718+
check.logContains("Configure compose resources in assembleComposeAppDebugXCFramework")
719+
}
720+
gradle(":assembleComposeAppDebugXCFramework").checks {
721+
assertDirectoriesContentEquals(
722+
file("build/XCFrameworks/debug/ComposeApp.xcframework/ios-arm64/ComposeApp.framework/composeResources"),
723+
file("expected/XCFrameworks/iosComposeResources")
724+
)
725+
assertDirectoriesContentEquals(
726+
file("build/XCFrameworks/debug/ComposeApp.xcframework/macos-arm64/ComposeApp.framework/composeResources"),
727+
file("expected/XCFrameworks/macosComposeResources")
728+
)
729+
}
730+
}
731+
}
732+
615733
@Test
616734
fun iosResources() {
617735
Assumptions.assumeTrue(currentOS == OS.MacOS)
@@ -624,11 +742,11 @@ class ResourcesTest : GradlePluginTestBase() {
624742
additionalEnvVars = iosEnv
625743
)
626744

627-
with(TestProject("misc/iosResources", testEnv)) {
745+
with(TestProject("misc/appleResources", testEnv)) {
628746
gradle(":podspec", "-Pkotlin.native.cocoapods.generate.wrapper=true").checks {
629747
assertEqualTextFiles(
630-
file("iosResources.podspec"),
631-
file("expected/iosResources.podspec")
748+
file("appleResources.podspec"),
749+
file("expected/appleResources.podspec")
632750
)
633751
file("build/compose/cocoapods/compose-resources").checkExists()
634752
}
@@ -695,8 +813,30 @@ class ResourcesTest : GradlePluginTestBase() {
695813
check.taskNoSource(":prepareComposeResourcesTaskForIosX64Main")
696814
check.taskSkipped(":generateResourceAccessorsForIosX64Main")
697815

698-
file("build/compose/cocoapods/compose-resources/composeResources/iosresources.generated.resources/drawable/compose-multiplatform.xml").checkExists()
699-
file("build/compose/cocoapods/compose-resources/composeResources/iosresources.generated.resources/drawable/icon.xml").checkExists()
816+
file("build/compose/cocoapods/compose-resources/composeResources/appleresources.generated.resources/drawable/compose-multiplatform.xml").checkExists()
817+
file("build/compose/cocoapods/compose-resources/composeResources/appleresources.generated.resources/drawable/icon.xml").checkExists()
818+
}
819+
}
820+
}
821+
822+
@Test
823+
fun cocoapodsIosXCFrameworkResources() {
824+
Assumptions.assumeTrue(currentOS == OS.MacOS)
825+
826+
with(
827+
testProject(
828+
"misc/appleResources",
829+
defaultTestEnvironment.copy(kotlinVersion = "2.2.0-Beta2-1"))
830+
) {
831+
gradle(":podPublishDebugXCFramework").checks {
832+
assertDirectoriesContentEquals(
833+
file("build/cocoapods/publish/debug/shared.xcframework/ios-arm64/shared.framework/composeResources"),
834+
file("expected/XCFrameworks/iosComposeResources")
835+
)
836+
assertDirectoriesContentEquals(
837+
file("build/cocoapods/publish/debug/shared.xcframework/ios-arm64_x86_64-simulator/shared.framework/composeResources"),
838+
file("expected/XCFrameworks/iosComposeResources")
839+
)
700840
}
701841
}
702842
}
@@ -713,11 +853,26 @@ class ResourcesTest : GradlePluginTestBase() {
713853
additionalEnvVars = macosEnv
714854
)
715855

716-
with(TestProject("misc/macosResources", testEnv)) {
856+
with(TestProject("misc/appleResources", testEnv)) {
857+
file("build.gradle.kts").modify { content ->
858+
content.replace(
859+
"""
860+
| iosX64()
861+
| iosArm64()
862+
| iosSimulatorArm64()
863+
""".trimMargin(),
864+
"""
865+
| macosX64()
866+
| macosArm64()
867+
""".trimMargin()
868+
)
869+
}
870+
file("src/iosMain").renameTo(file("src/macosMain"))
871+
717872
gradle(":podspec", "-Pkotlin.native.cocoapods.generate.wrapper=true").checks {
718873
assertEqualTextFiles(
719-
file("macosResources.podspec"),
720-
file("expected/macosResources.podspec")
874+
file("appleResources.podspec"),
875+
file("expected/appleResources.podspec")
721876
)
722877
file("build/compose/cocoapods/compose-resources").checkExists()
723878
}
@@ -784,38 +939,52 @@ class ResourcesTest : GradlePluginTestBase() {
784939
check.taskNoSource(":prepareComposeResourcesTaskForMacosX64Main")
785940
check.taskSkipped(":generateResourceAccessorsForMacosX64Main")
786941

787-
file("build/compose/cocoapods/compose-resources/composeResources/macosresources.generated.resources/drawable/compose-multiplatform.xml").checkExists()
788-
file("build/compose/cocoapods/compose-resources/composeResources/macosresources.generated.resources/drawable/icon.xml").checkExists()
942+
file("build/compose/cocoapods/compose-resources/composeResources/appleresources.generated.resources/drawable/compose-multiplatform.xml").checkExists()
943+
file("build/compose/cocoapods/compose-resources/composeResources/appleresources.generated.resources/drawable/icon.xml").checkExists()
789944
}
790945
}
791946
}
792947

793948
@Test
794949
fun iosTestResources() {
795950
Assumptions.assumeTrue(currentOS == OS.MacOS)
796-
with(testProject("misc/iosResources")) {
951+
with(testProject("misc/appleResources")) {
797952
gradle(":linkDebugTestIosX64", "--dry-run").checks {
798953
check.taskSkipped(":copyTestComposeResourcesForIosX64")
799954
check.taskSkipped(":linkDebugTestIosX64")
800955
}
801956
gradle(":copyTestComposeResourcesForIosX64").checks {
802-
file("build/bin/iosX64/debugTest/compose-resources/composeResources/iosresources.generated.resources/drawable/compose-multiplatform.xml").checkExists()
803-
file("build/bin/iosX64/debugTest/compose-resources/composeResources/iosresources.generated.resources/drawable/icon.xml").checkExists()
957+
file("build/bin/iosX64/debugTest/compose-resources/composeResources/appleresources.generated.resources/drawable/compose-multiplatform.xml").checkExists()
958+
file("build/bin/iosX64/debugTest/compose-resources/composeResources/appleresources.generated.resources/drawable/icon.xml").checkExists()
804959
}
805960
}
806961
}
807962

808963
@Test
809964
fun macosTestResources() {
810965
Assumptions.assumeTrue(currentOS == OS.MacOS)
811-
with(testProject("misc/macosResources")) {
966+
with(testProject("misc/appleResources")) {
967+
file("build.gradle.kts").modify { content ->
968+
content.replace(
969+
"""
970+
| iosX64()
971+
| iosArm64()
972+
| iosSimulatorArm64()
973+
""".trimMargin(),
974+
"""
975+
| macosX64()
976+
| macosArm64()
977+
""".trimMargin()
978+
)
979+
}
980+
file("src/iosMain").renameTo(file("src/macosMain"))
812981
gradle(":linkDebugTestMacosX64", "--dry-run").checks {
813982
check.taskSkipped(":copyTestComposeResourcesForMacosX64")
814983
check.taskSkipped(":linkDebugTestMacosX64")
815984
}
816985
gradle(":copyTestComposeResourcesForMacosX64").checks {
817-
file("build/bin/macosX64/debugTest/compose-resources/composeResources/macosresources.generated.resources/drawable/compose-multiplatform.xml").checkExists()
818-
file("build/bin/macosX64/debugTest/compose-resources/composeResources/macosresources.generated.resources/drawable/icon.xml").checkExists()
986+
file("build/bin/macosX64/debugTest/compose-resources/composeResources/appleresources.generated.resources/drawable/compose-multiplatform.xml").checkExists()
987+
file("build/bin/macosX64/debugTest/compose-resources/composeResources/appleresources.generated.resources/drawable/icon.xml").checkExists()
819988
}
820989
}
821990
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="600dp"
3+
android:height="600dp"
4+
android:viewportWidth="600"
5+
android:viewportHeight="600">
6+
<path
7+
android:pathData="M301.21,418.53C300.97,418.54 300.73,418.56 300.49,418.56C297.09,418.59 293.74,417.72 290.79,416.05L222.6,377.54C220.63,376.43 219,374.82 217.85,372.88C216.7,370.94 216.09,368.73 216.07,366.47L216.07,288.16C216.06,287.32 216.09,286.49 216.17,285.67C216.38,283.54 216.91,281.5 217.71,279.6L199.29,268.27L177.74,256.19C175.72,260.43 174.73,265.23 174.78,270.22L174.79,387.05C174.85,393.89 178.57,400.2 184.53,403.56L286.26,461.02C290.67,463.51 295.66,464.8 300.73,464.76C300.91,464.76 301.09,464.74 301.27,464.74C301.24,449.84 301.22,439.23 301.22,439.23L301.21,418.53Z"
8+
android:fillColor="#041619"
9+
android:fillType="nonZero"/>
10+
<path
11+
android:pathData="M409.45,242.91L312.64,188.23C303.64,183.15 292.58,183.26 283.68,188.51L187.92,245C183.31,247.73 179.93,251.62 177.75,256.17L177.74,256.19L199.29,268.27L217.71,279.6C217.83,279.32 217.92,279.02 218.05,278.74C218.24,278.36 218.43,277.98 218.64,277.62C219.06,276.88 219.52,276.18 220.04,275.51C221.37,273.8 223.01,272.35 224.87,271.25L289.06,233.39C290.42,232.59 291.87,231.96 293.39,231.51C295.53,230.87 297.77,230.6 300,230.72C302.98,230.88 305.88,231.73 308.47,233.2L373.37,269.85C375.54,271.08 377.49,272.68 379.13,274.57C379.68,275.19 380.18,275.85 380.65,276.53C380.86,276.84 381.05,277.15 381.24,277.47L397.79,266.39L420.34,252.93L420.31,252.88C417.55,248.8 413.77,245.35 409.45,242.91Z"
12+
android:fillColor="#37BF6E"
13+
android:fillType="nonZero"/>
14+
<path
15+
android:pathData="M381.24,277.47C381.51,277.92 381.77,278.38 382.01,278.84C382.21,279.24 382.39,279.65 382.57,280.06C382.91,280.88 383.19,281.73 383.41,282.59C383.74,283.88 383.92,285.21 383.93,286.57L383.93,361.1C383.96,363.95 383.35,366.77 382.16,369.36C381.93,369.86 381.69,370.35 381.42,370.83C379.75,373.79 377.32,376.27 374.39,378L310.2,415.87C307.47,417.48 304.38,418.39 301.21,418.53L301.22,439.23C301.22,439.23 301.24,449.84 301.27,464.74C306.1,464.61 310.91,463.3 315.21,460.75L410.98,404.25C419.88,399 425.31,389.37 425.22,379.03L425.22,267.85C425.17,262.48 423.34,257.34 420.34,252.93L397.79,266.39L381.24,277.47Z"
16+
android:fillColor="#3870B2"
17+
android:fillType="nonZero"/>
18+
<path
19+
android:pathData="M177.75,256.17C179.93,251.62 183.31,247.73 187.92,245L283.68,188.51C292.58,183.26 303.64,183.15 312.64,188.23L409.45,242.91C413.77,245.35 417.55,248.8 420.31,252.88L420.34,252.93L498.59,206.19C494.03,199.46 487.79,193.78 480.67,189.75L320.86,99.49C306.01,91.1 287.75,91.27 273.07,99.95L114.99,193.2C107.39,197.69 101.81,204.11 98.21,211.63L177.74,256.19L177.75,256.17ZM301.27,464.74C301.09,464.74 300.91,464.76 300.73,464.76C295.66,464.8 290.67,463.51 286.26,461.02L184.53,403.56C178.57,400.2 174.85,393.89 174.79,387.05L174.78,270.22C174.73,265.23 175.72,260.43 177.74,256.19L98.21,211.63C94.86,218.63 93.23,226.58 93.31,234.82L93.31,427.67C93.42,438.97 99.54,449.37 109.4,454.92L277.31,549.77C284.6,553.88 292.84,556.01 301.2,555.94L301.2,555.8C301.39,543.78 301.33,495.26 301.27,464.74Z"
20+
android:strokeWidth="10"
21+
android:fillColor="#00000000"
22+
android:strokeColor="#083042"
23+
android:fillType="nonZero"/>
24+
<path
25+
android:pathData="M498.59,206.19L420.34,252.93C423.34,257.34 425.17,262.48 425.22,267.85L425.22,379.03C425.31,389.37 419.88,399 410.98,404.25L315.21,460.75C310.91,463.3 306.1,464.61 301.27,464.74C301.33,495.26 301.39,543.78 301.2,555.8L301.2,555.94C309.48,555.87 317.74,553.68 325.11,549.32L483.18,456.06C497.87,447.39 506.85,431.49 506.69,414.43L506.69,230.91C506.6,222.02 503.57,213.5 498.59,206.19Z"
26+
android:strokeWidth="10"
27+
android:fillColor="#00000000"
28+
android:strokeColor="#083042"
29+
android:fillType="nonZero"/>
30+
<path
31+
android:pathData="M301.2,555.94C292.84,556.01 284.6,553.88 277.31,549.76L109.4,454.92C99.54,449.37 93.42,438.97 93.31,427.67L93.31,234.82C93.23,226.58 94.86,218.63 98.21,211.63C101.81,204.11 107.39,197.69 114.99,193.2L273.07,99.95C287.75,91.27 306.01,91.1 320.86,99.49L480.67,189.75C487.79,193.78 494.03,199.46 498.59,206.19C503.57,213.5 506.6,222.02 506.69,230.91L506.69,414.43C506.85,431.49 497.87,447.39 483.18,456.06L325.11,549.32C317.74,553.68 309.48,555.87 301.2,555.94Z"
32+
android:strokeWidth="10"
33+
android:fillColor="#00000000"
34+
android:strokeColor="#083042"
35+
android:fillType="nonZero"/>
36+
</vector>

0 commit comments

Comments
 (0)