From b447f92313d1ef6b7b5585ccdcb3ccc7afc18017 Mon Sep 17 00:00:00 2001 From: Thomas Vos Date: Tue, 11 Mar 2025 10:51:47 +0100 Subject: [PATCH] Resources improvements for native macOS app (#5245) This PR fixes compose resources for native macOS app (see currently broken chat app using runDebugExecutableMacosArm64). This PR also adds support for embedding resources into native macOS framework. Similar to how it works on iOS. This allows using the macOS compose code in an Xcode project. Just like iOS, using kotlin code as framwork. Then call the main function from the Xcode project to run the compose app. https://github.com/JetBrains/compose-multiplatform/pull/5219 https://github.com/JetBrains/compose-multiplatform/pull/5169 ## Testing - For executable: run chat app using runDebugExecutableMacosArm64 - For framework: Tested by adding macOS support to the iOS Xcode project in chat app (not in this PR). Can add the sample app if needed. There were also tests added to verify this. ## Release Notes N/A --- components/gradle.properties | 2 +- .../compose/resources/ResourceReader.macos.kt | 28 +++- .../internal/checkExperimentalTargets.kt | 17 ++- .../compose/resources/IosResources.kt | 17 ++- .../compose/resources/IosResourcesTasks.kt | 12 +- .../test/tests/integration/ResourcesTest.kt | 125 ++++++++++++++++++ .../appModule/build.gradle.kts | 2 + .../composeResources/values/macos_strings.xml | 3 + .../kotlin/me/sample/app/App.macos.kt | 10 ++ .../cmplib/build.gradle.kts | 2 + .../featureModule/build.gradle.kts | 2 + .../kmpResourcePublication/gradle.properties | 1 + .../misc/macosResources/build.gradle.kts | 32 +++++ .../expected/macosResources.podspec | 54 ++++++++ .../misc/macosResources/gradle.properties | 2 + .../misc/macosResources/settings.gradle.kts | 24 ++++ .../drawable/compose-multiplatform.xml | 36 +++++ .../src/commonMain/kotlin/App.kt | 39 ++++++ .../composeResources/drawable/icon.xml | 36 +++++ .../misc/testResources/build.gradle.kts | 3 + .../misc/testResources/gradle.properties | 3 +- gradle-plugins/gradle.properties | 2 +- 22 files changed, 432 insertions(+), 20 deletions(-) create mode 100644 gradle-plugins/compose/src/test/test-projects/misc/kmpResourcePublication/appModule/src/macosMain/composeResources/values/macos_strings.xml create mode 100644 gradle-plugins/compose/src/test/test-projects/misc/kmpResourcePublication/appModule/src/macosMain/kotlin/me/sample/app/App.macos.kt create mode 100644 gradle-plugins/compose/src/test/test-projects/misc/macosResources/build.gradle.kts create mode 100644 gradle-plugins/compose/src/test/test-projects/misc/macosResources/expected/macosResources.podspec create mode 100644 gradle-plugins/compose/src/test/test-projects/misc/macosResources/gradle.properties create mode 100644 gradle-plugins/compose/src/test/test-projects/misc/macosResources/settings.gradle.kts create mode 100644 gradle-plugins/compose/src/test/test-projects/misc/macosResources/src/commonMain/composeResources/drawable/compose-multiplatform.xml create mode 100644 gradle-plugins/compose/src/test/test-projects/misc/macosResources/src/commonMain/kotlin/App.kt create mode 100644 gradle-plugins/compose/src/test/test-projects/misc/macosResources/src/macosMain/composeResources/drawable/icon.xml diff --git a/components/gradle.properties b/components/gradle.properties index 7268ab9edf..bef0bca191 100644 --- a/components/gradle.properties +++ b/components/gradle.properties @@ -9,7 +9,7 @@ android.useAndroidX=true #Versions kotlin.version=2.1.0 agp.version=8.2.2 -compose.version=1.8.0-alpha01 +compose.version=1.8.0-alpha03 deploy.version=0.1.0-SNAPSHOT #Compose diff --git a/components/resources/library/src/macosMain/kotlin/org/jetbrains/compose/resources/ResourceReader.macos.kt b/components/resources/library/src/macosMain/kotlin/org/jetbrains/compose/resources/ResourceReader.macos.kt index 4b042d1108..61ddd3aa9a 100644 --- a/components/resources/library/src/macosMain/kotlin/org/jetbrains/compose/resources/ResourceReader.macos.kt +++ b/components/resources/library/src/macosMain/kotlin/org/jetbrains/compose/resources/ResourceReader.macos.kt @@ -39,12 +39,32 @@ internal actual fun getPlatformResourceReader(): ResourceReader = object : Resou private fun getPathOnDisk(path: String): String { val fm = NSFileManager.defaultManager() val currentDirectoryPath = fm.currentDirectoryPath + val pathFix = getPathWithoutPackage(path) return listOf( + // Framework binary + // todo: support fallback path at bundle root? + NSBundle.mainBundle.resourcePath + "/compose-resources/" + path, + // Executable binary //todo in future bundle resources with app and use all sourceSets (skikoMain, nativeMain) - "$currentDirectoryPath/src/macosMain/composeResources/$path", - "$currentDirectoryPath/src/macosTest/composeResources/$path", - "$currentDirectoryPath/src/commonMain/composeResources/$path", - "$currentDirectoryPath/src/commonTest/composeResources/$path" + "$currentDirectoryPath/src/macosMain/composeResources/$pathFix", + "$currentDirectoryPath/src/macosTest/composeResources/$pathFix", + "$currentDirectoryPath/src/commonMain/composeResources/$pathFix", + "$currentDirectoryPath/src/commonTest/composeResources/$pathFix" ).firstOrNull { p -> fm.fileExistsAtPath(p) } ?: throw MissingResourceException(path) } + + private fun getPathWithoutPackage(path: String): String { + // At the moment resources are not bundled when running a macOS executable binary. + // As a workaround, load the resources from the actual path on disk. So the + // "composeResources/PACKAGE/" prefix must be removed. For example: + // "composeResources/chat_mpp.shared.generated.resources/drawable/background.jpg" + // Will be transformed into: + // "drawable/background.jpg" + // In the future when resources are bundled when running macOS executable binary this + // workaround is no longer needed. + require(path.startsWith("composeResources/")) { "Invalid path: $path" } + return path + .substringAfter("composeResources/") // remove "composeResources/" part + .substringAfter("/") // remove PACKAGE path + } } \ No newline at end of file diff --git a/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/experimental/internal/checkExperimentalTargets.kt b/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/experimental/internal/checkExperimentalTargets.kt index 92320f02a2..f45bf088cb 100644 --- a/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/experimental/internal/checkExperimentalTargets.kt +++ b/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/experimental/internal/checkExperimentalTargets.kt @@ -71,13 +71,16 @@ private fun checkTarget(project: Project, target: KotlinTarget): CheckResult { project.configurations.forEach { configuration -> if (configuration.isCanBeResolved && configuration.name in targetConfigurationNames) { - val containsSkikoArtifact = configuration.resolvedConfiguration.resolvedArtifacts.any { - it.id.displayName.contains(SKIKO_ARTIFACT_PREFIX) - } - if (containsSkikoArtifact) { - val targetIsDisabled = project.findLocalOrGlobalProperty(targetType.gradlePropertyName).map { it != "true" } - if (targetIsDisabled.get()) { - return CheckResult.Fail(targetType) + val resolvedConfiguration = configuration.resolvedConfiguration + if (!resolvedConfiguration.hasError()) { + val containsSkikoArtifact = resolvedConfiguration.resolvedArtifacts.any { + it.id.displayName.contains(SKIKO_ARTIFACT_PREFIX) + } + if (containsSkikoArtifact) { + val targetIsDisabled = project.findLocalOrGlobalProperty(targetType.gradlePropertyName).map { it != "true" } + if (targetIsDisabled.get()) { + return CheckResult.Fail(targetType) + } } } } diff --git a/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/resources/IosResources.kt b/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/resources/IosResources.kt index ef6caa15b7..ccb994d4ef 100644 --- a/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/resources/IosResources.kt +++ b/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/resources/IosResources.kt @@ -33,7 +33,7 @@ internal fun Project.configureSyncIosComposeResources( } kotlinExtension.targets.withType(KotlinNativeTarget::class.java).all { nativeTarget -> - if (nativeTarget.isIosTarget()) { + if (nativeTarget.isIosOrMacTarget()) { nativeTarget.binaries.withType(Framework::class.java).all { iosFramework -> val frameworkClassifier = iosFramework.getClassifier() val checkNoSandboxTask = tasks.registerOrConfigure( @@ -116,6 +116,7 @@ private fun Framework.getClassifier(): String { } internal fun Framework.getSyncResourcesTaskName() = "sync${getClassifier()}ComposeResourcesForIos" + private fun Framework.isCocoapodsFramework() = name.startsWith("pod") private fun Framework.getFinalResourcesDir(): Provider { @@ -125,9 +126,9 @@ private fun Framework.getFinalResourcesDir(): Provider { } else { providers.environmentVariable("BUILT_PRODUCTS_DIR") .zip( - providers.environmentVariable("CONTENTS_FOLDER_PATH") - ) { builtProductsDir, contentsFolderPath -> - File("$builtProductsDir/$contentsFolderPath/$IOS_COMPOSE_RESOURCES_ROOT_DIR").canonicalPath + providers.environmentVariable("UNLOCALIZED_RESOURCES_FOLDER_PATH") + ) { builtProductsDir, unlocalizedResourcesFolderPath -> + File("$builtProductsDir/$unlocalizedResourcesFolderPath/$IOS_COMPOSE_RESOURCES_ROOT_DIR").canonicalPath } .flatMap { project.objects.directoryProperty().apply { set(File(it)) } @@ -142,4 +143,10 @@ private fun KotlinNativeTarget.isIosDeviceTarget(): Boolean = konanTarget === KonanTarget.IOS_ARM64 private fun KotlinNativeTarget.isIosTarget(): Boolean = - isIosSimulatorTarget() || isIosDeviceTarget() \ No newline at end of file + isIosSimulatorTarget() || isIosDeviceTarget() + +private fun KotlinNativeTarget.isMacTarget(): Boolean = + konanTarget === KonanTarget.MACOS_X64 || konanTarget === KonanTarget.MACOS_ARM64 + +private fun KotlinNativeTarget.isIosOrMacTarget(): Boolean = + isIosTarget() || isMacTarget() diff --git a/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/resources/IosResourcesTasks.kt b/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/resources/IosResourcesTasks.kt index b024e9412b..62afc07983 100644 --- a/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/resources/IosResourcesTasks.kt +++ b/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/resources/IosResourcesTasks.kt @@ -118,7 +118,17 @@ private fun getRequestedKonanTargetsByXcode(platform: String, archs: List error("Unknown iOS platform: '$platform'") + platform.startsWith("macosx") -> { + targets.addAll(archs.map { arch -> + when (arch) { + "arm64" -> KonanTarget.MACOS_ARM64 + "x86_64" -> KonanTarget.MACOS_X64 + else -> error("Unknown macOS arch: '$arch'") + } + }) + } + + else -> error("Unknown Apple platform: '$platform'") } return targets.toList() diff --git a/gradle-plugins/compose/src/test/kotlin/org/jetbrains/compose/test/tests/integration/ResourcesTest.kt b/gradle-plugins/compose/src/test/kotlin/org/jetbrains/compose/test/tests/integration/ResourcesTest.kt index c3dc325408..2ea8d1a149 100644 --- a/gradle-plugins/compose/src/test/kotlin/org/jetbrains/compose/test/tests/integration/ResourcesTest.kt +++ b/gradle-plugins/compose/src/test/kotlin/org/jetbrains/compose/test/tests/integration/ResourcesTest.kt @@ -22,6 +22,7 @@ import java.util.zip.ZipFile import kotlin.io.path.Path import kotlin.io.path.invariantSeparatorsPathString import kotlin.io.path.relativeTo +import kotlin.test.Ignore import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertNotNull @@ -241,6 +242,7 @@ class ResourcesTest : GradlePluginTestBase() { } } + @Ignore // ignored until compose update after https://github.com/JetBrains/compose-multiplatform/pull/5245 @Test fun testMultiModuleResources() { val environment = defaultTestEnvironment @@ -280,6 +282,13 @@ class ResourcesTest : GradlePluginTestBase() { libpath("iossimulatorarm64", "-kotlin_resources.kotlin_resources.zip") ) checkResourcesZip(iossimulatorarm64ResZip, resourcesFiles, false) + + val macosx64ResZip = + file(libpath("macosx64", "-kotlin_resources.kotlin_resources.zip")) + checkResourcesZip(macosx64ResZip, resourcesFiles, false) + val macosarm64ResZip = + file(libpath("macosarm64", "-kotlin_resources.kotlin_resources.zip")) + checkResourcesZip(macosarm64ResZip, resourcesFiles, false) } val jsResZip = file(libpath("js", "-kotlin_resources.kotlin_resources.zip")) checkResourcesZip(jsResZip, resourcesFiles, false) @@ -300,6 +309,13 @@ class ResourcesTest : GradlePluginTestBase() { ":appModule:iosSimulatorArm64Test" } gradle(iosTask) + + val macosTask = if (currentArch == Arch.X64) { + ":appModule:macosX64Test" + } else { + ":appModule:macosArm64Test" + } + gradle(macosTask) } file("featureModule/src/commonMain/kotlin/me/sample/app/Feature.kt").modify { content -> @@ -687,6 +703,95 @@ class ResourcesTest : GradlePluginTestBase() { } } + @Test + fun macosResources() { + Assumptions.assumeTrue(currentOS == OS.MacOS) + val macosEnv = mapOf( + "PLATFORM_NAME" to "macosx", + "ARCHS" to "arm64", + "CONFIGURATION" to "Debug", + ) + val testEnv = defaultTestEnvironment.copy( + additionalEnvVars = macosEnv + ) + + with(TestProject("misc/macosResources", testEnv)) { + gradle(":podspec", "-Pkotlin.native.cocoapods.generate.wrapper=true").checks { + assertEqualTextFiles( + file("macosResources.podspec"), + file("expected/macosResources.podspec") + ) + file("build/compose/cocoapods/compose-resources").checkExists() + } + + gradle( + ":syncFramework", + "-Pkotlin.native.cocoapods.platform=${macosEnv["PLATFORM_NAME"]}", + "-Pkotlin.native.cocoapods.archs=${macosEnv["ARCHS"]}", + "-Pkotlin.native.cocoapods.configuration=${macosEnv["CONFIGURATION"]}", + "--dry-run" + ).checks { + check.taskSkipped(":generateComposeResClass") + + check.taskSkipped(":convertXmlValueResourcesForCommonMain") + check.taskSkipped(":copyNonXmlValueResourcesForCommonMain") + check.taskSkipped(":prepareComposeResourcesTaskForCommonMain") + check.taskSkipped(":generateResourceAccessorsForCommonMain") + + check.taskSkipped(":convertXmlValueResourcesForNativeMain") + check.taskSkipped(":copyNonXmlValueResourcesForNativeMain") + check.taskSkipped(":prepareComposeResourcesTaskForNativeMain") + check.taskSkipped(":generateResourceAccessorsForNativeMain") + + check.taskSkipped(":convertXmlValueResourcesForAppleMain") + check.taskSkipped(":copyNonXmlValueResourcesForAppleMain") + check.taskSkipped(":prepareComposeResourcesTaskForAppleMain") + check.taskSkipped(":generateResourceAccessorsForAppleMain") + + check.taskSkipped(":convertXmlValueResourcesForMacosMain") + check.taskSkipped(":copyNonXmlValueResourcesForMacosMain") + check.taskSkipped(":prepareComposeResourcesTaskForMacosMain") + check.taskSkipped(":generateResourceAccessorsForMacosMain") + + check.taskSkipped(":convertXmlValueResourcesForMacosX64Main") + check.taskSkipped(":copyNonXmlValueResourcesForMacosX64Main") + check.taskSkipped(":prepareComposeResourcesTaskForMacosX64Main") + check.taskSkipped(":generateResourceAccessorsForMacosX64Main") + + check.taskSkipped(":syncPodComposeResourcesForIos") + } + gradle(":syncPodComposeResourcesForIos").checks { + check.taskNoSource(":convertXmlValueResourcesForCommonMain") + check.taskSuccessful(":copyNonXmlValueResourcesForCommonMain") + check.taskSuccessful(":prepareComposeResourcesTaskForCommonMain") + check.taskSkipped(":generateResourceAccessorsForCommonMain") + + check.taskNoSource(":convertXmlValueResourcesForNativeMain") + check.taskNoSource(":copyNonXmlValueResourcesForNativeMain") + check.taskNoSource(":prepareComposeResourcesTaskForNativeMain") + check.taskSkipped(":generateResourceAccessorsForNativeMain") + + check.taskNoSource(":convertXmlValueResourcesForAppleMain") + check.taskNoSource(":copyNonXmlValueResourcesForAppleMain") + check.taskNoSource(":prepareComposeResourcesTaskForAppleMain") + check.taskSkipped(":generateResourceAccessorsForAppleMain") + + check.taskNoSource(":convertXmlValueResourcesForMacosMain") + check.taskSuccessful(":copyNonXmlValueResourcesForMacosMain") + check.taskSuccessful(":prepareComposeResourcesTaskForMacosMain") + check.taskSkipped(":generateResourceAccessorsForMacosMain") + + check.taskNoSource(":convertXmlValueResourcesForMacosX64Main") + check.taskNoSource(":copyNonXmlValueResourcesForMacosX64Main") + check.taskNoSource(":prepareComposeResourcesTaskForMacosX64Main") + check.taskSkipped(":generateResourceAccessorsForMacosX64Main") + + file("build/compose/cocoapods/compose-resources/composeResources/macosresources.generated.resources/drawable/compose-multiplatform.xml").checkExists() + file("build/compose/cocoapods/compose-resources/composeResources/macosresources.generated.resources/drawable/icon.xml").checkExists() + } + } + } + @Test fun iosTestResources() { Assumptions.assumeTrue(currentOS == OS.MacOS) @@ -702,6 +807,22 @@ class ResourcesTest : GradlePluginTestBase() { } } + @Test + fun macosTestResources() { + Assumptions.assumeTrue(currentOS == OS.MacOS) + with(testProject("misc/macosResources")) { + gradle(":linkDebugTestMacosX64", "--dry-run").checks { + check.taskSkipped(":copyTestComposeResourcesForMacosX64") + check.taskSkipped(":linkDebugTestMacosX64") + } + gradle(":copyTestComposeResourcesForMacosX64").checks { + file("build/bin/macosX64/debugTest/compose-resources/composeResources/macosresources.generated.resources/drawable/compose-multiplatform.xml").checkExists() + file("build/bin/macosX64/debugTest/compose-resources/composeResources/macosresources.generated.resources/drawable/icon.xml").checkExists() + } + } + } + + @Ignore // ignored until compose update after https://github.com/JetBrains/compose-multiplatform/pull/5245 @Test fun checkTestResources() { with(testProject("misc/testResources")) { @@ -714,6 +835,10 @@ class ResourcesTest : GradlePluginTestBase() { check.logContains("Configure test resources for 'iosArm64' target") check.logContains("Configure main resources for 'iosSimulatorArm64' target") check.logContains("Configure test resources for 'iosSimulatorArm64' target") + check.logContains("Configure main resources for 'macosX64' target") + check.logContains("Configure test resources for 'macosX64' target") + check.logContains("Configure main resources for 'macosArm64' target") + check.logContains("Configure test resources for 'macosArm64' target") check.taskSuccessful(":desktopTest") } diff --git a/gradle-plugins/compose/src/test/test-projects/misc/kmpResourcePublication/appModule/build.gradle.kts b/gradle-plugins/compose/src/test/test-projects/misc/kmpResourcePublication/appModule/build.gradle.kts index 2c3b6955ef..07f8005434 100644 --- a/gradle-plugins/compose/src/test/test-projects/misc/kmpResourcePublication/appModule/build.gradle.kts +++ b/gradle-plugins/compose/src/test/test-projects/misc/kmpResourcePublication/appModule/build.gradle.kts @@ -13,6 +13,8 @@ kotlin { iosX64() iosArm64() iosSimulatorArm64() + macosX64() + macosArm64() js { browser() } wasmJs { browser() } diff --git a/gradle-plugins/compose/src/test/test-projects/misc/kmpResourcePublication/appModule/src/macosMain/composeResources/values/macos_strings.xml b/gradle-plugins/compose/src/test/test-projects/misc/kmpResourcePublication/appModule/src/macosMain/composeResources/values/macos_strings.xml new file mode 100644 index 0000000000..f9f89e586b --- /dev/null +++ b/gradle-plugins/compose/src/test/test-projects/misc/kmpResourcePublication/appModule/src/macosMain/composeResources/values/macos_strings.xml @@ -0,0 +1,3 @@ + + macOS string + \ No newline at end of file diff --git a/gradle-plugins/compose/src/test/test-projects/misc/kmpResourcePublication/appModule/src/macosMain/kotlin/me/sample/app/App.macos.kt b/gradle-plugins/compose/src/test/test-projects/misc/kmpResourcePublication/appModule/src/macosMain/kotlin/me/sample/app/App.macos.kt new file mode 100644 index 0000000000..4a4927ee00 --- /dev/null +++ b/gradle-plugins/compose/src/test/test-projects/misc/kmpResourcePublication/appModule/src/macosMain/kotlin/me/sample/app/App.macos.kt @@ -0,0 +1,10 @@ +package me.sample.app + +import androidx.compose.runtime.Composable +import kmpresourcepublication.appmodule.generated.resources.Res +import kmpresourcepublication.appmodule.generated.resources.macOS_str +import org.jetbrains.compose.resources.stringResource + +@Composable +actual fun getPlatformSpecificString(): String = + stringResource(Res.string.macOS_str) \ No newline at end of file diff --git a/gradle-plugins/compose/src/test/test-projects/misc/kmpResourcePublication/cmplib/build.gradle.kts b/gradle-plugins/compose/src/test/test-projects/misc/kmpResourcePublication/cmplib/build.gradle.kts index cc5a941daf..609f087d4a 100644 --- a/gradle-plugins/compose/src/test/test-projects/misc/kmpResourcePublication/cmplib/build.gradle.kts +++ b/gradle-plugins/compose/src/test/test-projects/misc/kmpResourcePublication/cmplib/build.gradle.kts @@ -22,6 +22,8 @@ kotlin { iosX64() iosArm64() iosSimulatorArm64() + macosX64() + macosArm64() js { browser() } wasmJs { browser() } diff --git a/gradle-plugins/compose/src/test/test-projects/misc/kmpResourcePublication/featureModule/build.gradle.kts b/gradle-plugins/compose/src/test/test-projects/misc/kmpResourcePublication/featureModule/build.gradle.kts index bd92b891d6..2ae9d3cefa 100644 --- a/gradle-plugins/compose/src/test/test-projects/misc/kmpResourcePublication/featureModule/build.gradle.kts +++ b/gradle-plugins/compose/src/test/test-projects/misc/kmpResourcePublication/featureModule/build.gradle.kts @@ -11,6 +11,8 @@ kotlin { iosX64() iosArm64() iosSimulatorArm64() + macosX64() + macosArm64() js { browser() } wasmJs { browser() } diff --git a/gradle-plugins/compose/src/test/test-projects/misc/kmpResourcePublication/gradle.properties b/gradle-plugins/compose/src/test/test-projects/misc/kmpResourcePublication/gradle.properties index 9cd73d38eb..3ae7c5803a 100644 --- a/gradle-plugins/compose/src/test/test-projects/misc/kmpResourcePublication/gradle.properties +++ b/gradle-plugins/compose/src/test/test-projects/misc/kmpResourcePublication/gradle.properties @@ -5,3 +5,4 @@ android.useAndroidX=true org.jetbrains.compose.experimental.uikit.enabled=true org.jetbrains.compose.experimental.jscanvas.enabled=true org.jetbrains.compose.experimental.wasm.enabled=true +org.jetbrains.compose.experimental.macos.enabled=true diff --git a/gradle-plugins/compose/src/test/test-projects/misc/macosResources/build.gradle.kts b/gradle-plugins/compose/src/test/test-projects/misc/macosResources/build.gradle.kts new file mode 100644 index 0000000000..2e30c124f4 --- /dev/null +++ b/gradle-plugins/compose/src/test/test-projects/misc/macosResources/build.gradle.kts @@ -0,0 +1,32 @@ +plugins { + kotlin("multiplatform") + kotlin("plugin.compose") + kotlin("native.cocoapods") + id("org.jetbrains.compose") +} + +kotlin { + cocoapods { + version = "1.0" + summary = "Some description for a Kotlin/Native module" + homepage = "Link to a Kotlin/Native module homepage" + pod("Base64", "1.1.2") + framework { + baseName = "shared" + isStatic = true + } + } + + macosX64() + macosArm64() + + sourceSets { + commonMain { + dependencies { + implementation(compose.runtime) + implementation(compose.material) + implementation(compose.components.resources) + } + } + } +} diff --git a/gradle-plugins/compose/src/test/test-projects/misc/macosResources/expected/macosResources.podspec b/gradle-plugins/compose/src/test/test-projects/misc/macosResources/expected/macosResources.podspec new file mode 100644 index 0000000000..b4f476089e --- /dev/null +++ b/gradle-plugins/compose/src/test/test-projects/misc/macosResources/expected/macosResources.podspec @@ -0,0 +1,54 @@ +Pod::Spec.new do |spec| + spec.name = 'macosResources' + spec.version = '1.0' + spec.homepage = 'Link to a Kotlin/Native module homepage' + spec.source = { :http=> ''} + spec.authors = '' + spec.license = '' + spec.summary = 'Some description for a Kotlin/Native module' + spec.vendored_frameworks = 'build/cocoapods/framework/shared.framework' + spec.libraries = 'c++' + + spec.dependency 'Base64', '1.1.2' + + if !Dir.exist?('build/cocoapods/framework/shared.framework') || Dir.empty?('build/cocoapods/framework/shared.framework') + raise " + + Kotlin framework 'shared' doesn't exist yet, so a proper Xcode project can't be generated. + 'pod install' should be executed after running ':generateDummyFramework' Gradle task: + + ./gradlew :generateDummyFramework + + Alternatively, proper pod installation is performed during Gradle sync in the IDE (if Podfile location is set)" + end + + spec.xcconfig = { + 'ENABLE_USER_SCRIPT_SANDBOXING' => 'NO', + } + + spec.pod_target_xcconfig = { + 'KOTLIN_PROJECT_PATH' => '', + 'PRODUCT_MODULE_NAME' => 'shared', + } + + spec.script_phases = [ + { + :name => 'Build macosResources', + :execution_position => :before_compile, + :shell_path => '/bin/sh', + :script => <<-SCRIPT + if [ "YES" = "$OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED" ]; then + echo "Skipping Gradle build task invocation due to OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED environment variable set to \"YES\"" + exit 0 + fi + set -ev + REPO_ROOT="$PODS_TARGET_SRCROOT" + "$REPO_ROOT/gradlew" -p "$REPO_ROOT" $KOTLIN_PROJECT_PATH:syncFramework \ + -Pkotlin.native.cocoapods.platform=$PLATFORM_NAME \ + -Pkotlin.native.cocoapods.archs="$ARCHS" \ + -Pkotlin.native.cocoapods.configuration="$CONFIGURATION" + SCRIPT + } + ] + spec.resources = ['build/compose/cocoapods/compose-resources'] +end \ No newline at end of file diff --git a/gradle-plugins/compose/src/test/test-projects/misc/macosResources/gradle.properties b/gradle-plugins/compose/src/test/test-projects/misc/macosResources/gradle.properties new file mode 100644 index 0000000000..dc1dcfb61b --- /dev/null +++ b/gradle-plugins/compose/src/test/test-projects/misc/macosResources/gradle.properties @@ -0,0 +1,2 @@ +org.gradle.jvmargs=-Xmx8096M +org.jetbrains.compose.experimental.macos.enabled=true \ No newline at end of file diff --git a/gradle-plugins/compose/src/test/test-projects/misc/macosResources/settings.gradle.kts b/gradle-plugins/compose/src/test/test-projects/misc/macosResources/settings.gradle.kts new file mode 100644 index 0000000000..fe637593ae --- /dev/null +++ b/gradle-plugins/compose/src/test/test-projects/misc/macosResources/settings.gradle.kts @@ -0,0 +1,24 @@ +rootProject.name = "macosResources" +pluginManagement { + repositories { + mavenLocal() + gradlePluginPortal() + google() + maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") + } + plugins { + id("org.jetbrains.kotlin.multiplatform").version("KOTLIN_VERSION_PLACEHOLDER") + id("org.jetbrains.kotlin.plugin.compose").version("KOTLIN_VERSION_PLACEHOLDER") + id("org.jetbrains.kotlin.native.cocoapods").version("KOTLIN_VERSION_PLACEHOLDER") + id("org.jetbrains.compose").version("COMPOSE_GRADLE_PLUGIN_VERSION_PLACEHOLDER") + } +} +dependencyResolutionManagement { + repositories { + mavenLocal() + maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") + mavenCentral() + gradlePluginPortal() + google() + } +} \ No newline at end of file diff --git a/gradle-plugins/compose/src/test/test-projects/misc/macosResources/src/commonMain/composeResources/drawable/compose-multiplatform.xml b/gradle-plugins/compose/src/test/test-projects/misc/macosResources/src/commonMain/composeResources/drawable/compose-multiplatform.xml new file mode 100644 index 0000000000..792ad8f711 --- /dev/null +++ b/gradle-plugins/compose/src/test/test-projects/misc/macosResources/src/commonMain/composeResources/drawable/compose-multiplatform.xml @@ -0,0 +1,36 @@ + + + + + + + + diff --git a/gradle-plugins/compose/src/test/test-projects/misc/macosResources/src/commonMain/kotlin/App.kt b/gradle-plugins/compose/src/test/test-projects/misc/macosResources/src/commonMain/kotlin/App.kt new file mode 100644 index 0000000000..17641ca754 --- /dev/null +++ b/gradle-plugins/compose/src/test/test-projects/misc/macosResources/src/commonMain/kotlin/App.kt @@ -0,0 +1,39 @@ +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.material.Button +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import org.jetbrains.compose.resources.ExperimentalResourceApi +import org.jetbrains.compose.resources.painterResource +import iosResources.generated.resources.* + +@OptIn(ExperimentalResourceApi::class) +@Composable +fun App() { + MaterialTheme { + var greetingText by remember { mutableStateOf("Hello, World!") } + var showImage by remember { mutableStateOf(false) } + Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) { + Button(onClick = { + showImage = !showImage + }) { + Text(greetingText) + } + AnimatedVisibility(showImage) { + Image( + painterResource(Res.drawable.compose_multiplatform), + null + ) + } + } + } +} diff --git a/gradle-plugins/compose/src/test/test-projects/misc/macosResources/src/macosMain/composeResources/drawable/icon.xml b/gradle-plugins/compose/src/test/test-projects/misc/macosResources/src/macosMain/composeResources/drawable/icon.xml new file mode 100644 index 0000000000..792ad8f711 --- /dev/null +++ b/gradle-plugins/compose/src/test/test-projects/misc/macosResources/src/macosMain/composeResources/drawable/icon.xml @@ -0,0 +1,36 @@ + + + + + + + + diff --git a/gradle-plugins/compose/src/test/test-projects/misc/testResources/build.gradle.kts b/gradle-plugins/compose/src/test/test-projects/misc/testResources/build.gradle.kts index 6ded4832b3..e0886927c1 100644 --- a/gradle-plugins/compose/src/test/test-projects/misc/testResources/build.gradle.kts +++ b/gradle-plugins/compose/src/test/test-projects/misc/testResources/build.gradle.kts @@ -15,6 +15,9 @@ kotlin { iosArm64() iosSimulatorArm64() + macosX64() + macosArm64() + sourceSets { commonMain { dependencies { diff --git a/gradle-plugins/compose/src/test/test-projects/misc/testResources/gradle.properties b/gradle-plugins/compose/src/test/test-projects/misc/testResources/gradle.properties index f4d7109663..2f532ce0ea 100644 --- a/gradle-plugins/compose/src/test/test-projects/misc/testResources/gradle.properties +++ b/gradle-plugins/compose/src/test/test-projects/misc/testResources/gradle.properties @@ -1,3 +1,4 @@ org.gradle.jvmargs=-Xmx8096M android.useAndroidX=true -org.jetbrains.compose.experimental.jscanvas.enabled=true \ No newline at end of file +org.jetbrains.compose.experimental.jscanvas.enabled=true +org.jetbrains.compose.experimental.macos.enabled=true \ No newline at end of file diff --git a/gradle-plugins/gradle.properties b/gradle-plugins/gradle.properties index bff42aa67b..66c36557c1 100644 --- a/gradle-plugins/gradle.properties +++ b/gradle-plugins/gradle.properties @@ -8,7 +8,7 @@ kotlin.code.style=official dev.junit.parallel=false # Default version of Compose Libraries used by Gradle plugin -compose.version=1.8.0-alpha01 +compose.version=1.8.0-alpha03 # The latest version of Kotlin compatible with compose.tests.compiler.version. Used only in tests/CI. compose.tests.kotlin.version=2.1.0 # __SUPPORTED_GRADLE_VERSIONS__