mirror of
https://github.com/jlengrand/compose-multiplatform.git
synced 2026-03-10 08:11:20 +00:00
uikit deploy, split Gradle and Xcode (#2406)
This commit is contained in:
@@ -9,12 +9,7 @@ import org.gradle.api.Project
|
||||
import org.jetbrains.compose.desktop.application.internal.OS
|
||||
import org.jetbrains.compose.desktop.application.internal.currentOS
|
||||
import org.jetbrains.compose.experimental.dsl.ExperimentalUiKitApplication
|
||||
import org.jetbrains.compose.experimental.uikit.tasks.ExperimentalPackComposeApplicationForXCodeTask
|
||||
import org.jetbrains.compose.experimental.uikit.tasks.ExperimentalPackComposeApplicationForXCodeTask.UikitTarget
|
||||
import org.jetbrains.compose.internal.toDir
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType
|
||||
|
||||
internal fun Project.configureExperimentalUikitApplication(
|
||||
mppExt: KotlinMultiplatformExtension,
|
||||
@@ -22,31 +17,8 @@ internal fun Project.configureExperimentalUikitApplication(
|
||||
) {
|
||||
if (currentOS != OS.MacOS) return
|
||||
|
||||
tasks.register(
|
||||
"packComposeUikitApplicationForXCode",
|
||||
ExperimentalPackComposeApplicationForXCodeTask::class.java
|
||||
) { packTask ->
|
||||
val targetType = project.providers.environmentVariable("SDK_NAME").map {
|
||||
if (it.startsWith("iphoneos"))
|
||||
UikitTarget.Arm64
|
||||
else UikitTarget.X64
|
||||
}.orElse(UikitTarget.X64)
|
||||
val buildType = project.providers.environmentVariable("CONFIGURATION").map {
|
||||
if (it.equals("release", ignoreCase = true)) NativeBuildType.RELEASE
|
||||
else NativeBuildType.DEBUG
|
||||
}.orElse(NativeBuildType.DEBUG)
|
||||
val target = mppExt.targets.getByName(targetType.get().targetName) as KotlinNativeTarget
|
||||
val kotlinBinary = target.binaries.getExecutable(buildType.get())
|
||||
val targetBuildDir = project.providers.environmentVariable("TARGET_BUILD_DIR").toDir(project)
|
||||
val executablePath = project.providers.environmentVariable("EXECUTABLE_PATH")
|
||||
|
||||
packTask.targetType.set(targetType)
|
||||
packTask.buildType.set(buildType)
|
||||
packTask.dependsOn(kotlinBinary.linkTask)
|
||||
packTask.kotlinBinary.set(kotlinBinary.outputFile)
|
||||
packTask.destinationDir.set(targetBuildDir)
|
||||
packTask.executablePath.set(executablePath)
|
||||
}
|
||||
|
||||
configureIosDeployTasks(application)
|
||||
configureIosDeployTasks(
|
||||
mppExt = mppExt,
|
||||
application = application,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,20 +5,26 @@
|
||||
|
||||
package org.jetbrains.compose.experimental.uikit.internal
|
||||
|
||||
import org.gradle.api.*
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.tasks.TaskContainer
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
import org.jetbrains.compose.experimental.dsl.DeployTarget
|
||||
import org.jetbrains.compose.experimental.dsl.ExperimentalUiKitApplication
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||
|
||||
const val SDK_PREFIFX_SIMULATOR = "iphonesimulator"
|
||||
const val SDK_PREFIX_IPHONEOS = "iphoneos"
|
||||
const val TEAM_ID_PROPERTY_KEY = "compose.ios.teamId"
|
||||
const val RELATIVE_PRODUCTS_PATH = "build/Build/Products"
|
||||
const val BUILD_DIR_NAME = "build"
|
||||
const val RELATIVE_PRODUCTS_PATH = "$BUILD_DIR_NAME/Build/Products"
|
||||
|
||||
fun Project.getBuildIosDir(id: String) = buildDir.resolve("ios").resolve(id)
|
||||
|
||||
internal fun Project.configureIosDeployTasks(application: ExperimentalUiKitApplication) {
|
||||
internal fun Project.configureIosDeployTasks(
|
||||
mppExt: KotlinMultiplatformExtension,
|
||||
application: ExperimentalUiKitApplication,
|
||||
) {
|
||||
val projectName = application.projectName
|
||||
val bundleIdPrefix = application.bundleIdPrefix
|
||||
|
||||
@@ -30,6 +36,7 @@ internal fun Project.configureIosDeployTasks(application: ExperimentalUiKitAppli
|
||||
when (target.deploy) {
|
||||
is DeployTarget.Simulator -> {
|
||||
registerSimulatorTasks(
|
||||
mppExt = mppExt,
|
||||
id = id,
|
||||
deploy = target.deploy,
|
||||
projectName = projectName,
|
||||
@@ -43,6 +50,7 @@ internal fun Project.configureIosDeployTasks(application: ExperimentalUiKitAppli
|
||||
}
|
||||
is DeployTarget.ConnectedDevice -> {
|
||||
registerConnectedDeviceTasks(
|
||||
mppExt = mppExt,
|
||||
id = id,
|
||||
deploy = target.deploy,
|
||||
projectName = projectName,
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2020-2022 JetBrains s.r.o. and respective authors and developers.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.compose.experimental.uikit.internal
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.jetbrains.compose.experimental.uikit.tasks.ExperimentalPackComposeApplicationForXCodeTask
|
||||
import org.jetbrains.compose.internal.fileToDir
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType
|
||||
import java.io.File
|
||||
|
||||
internal fun Project.configurePackComposeUiKitApplicationForXCodeTask(
|
||||
mppExt: KotlinMultiplatformExtension,
|
||||
id: String,
|
||||
configName: String,
|
||||
projectName: String,
|
||||
targetBuildPath: File,
|
||||
targetType: ExperimentalPackComposeApplicationForXCodeTask.UikitTarget,
|
||||
) = tasks.register(
|
||||
"packComposeUikitApplicationForXCode$id$configName",
|
||||
ExperimentalPackComposeApplicationForXCodeTask::class.java
|
||||
) { packTask ->
|
||||
val buildType = project.provider { configName }.map {
|
||||
if (it.equals("release", ignoreCase = true)) NativeBuildType.RELEASE
|
||||
else NativeBuildType.DEBUG
|
||||
}.orElse(NativeBuildType.DEBUG)
|
||||
val target = mppExt.targets.getByName(targetType.targetName) as KotlinNativeTarget
|
||||
val kotlinBinary = target.binaries.getExecutable(buildType.get())
|
||||
val targetBuildDir = project.provider { targetBuildPath }.fileToDir(project)
|
||||
val executablePath = "${projectName}.app/${projectName}"
|
||||
|
||||
packTask.targetType.set(targetType)
|
||||
packTask.buildType.set(buildType)
|
||||
packTask.dependsOn(kotlinBinary.linkTask)
|
||||
packTask.kotlinBinary.set(kotlinBinary.outputFile)
|
||||
packTask.destinationDir.set(targetBuildDir)
|
||||
packTask.executablePath.set(executablePath)
|
||||
}
|
||||
@@ -37,9 +37,6 @@ internal fun Project.configureTaskToGenerateXcodeProject(
|
||||
type: application
|
||||
platform: iOS
|
||||
deploymentTarget: "12.0"
|
||||
prebuildScripts:
|
||||
- script: cd "${rootDir.absolutePath}" && ./gradlew -i -p . packComposeUikitApplicationForXCode
|
||||
name: GradleCompile
|
||||
info:
|
||||
path: plists/Ios/Info.plist
|
||||
settings:
|
||||
|
||||
@@ -5,16 +5,19 @@
|
||||
|
||||
package org.jetbrains.compose.experimental.uikit.internal
|
||||
|
||||
import org.gradle.api.*
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
import org.jetbrains.compose.desktop.application.internal.MacUtils
|
||||
import org.jetbrains.compose.experimental.dsl.DeployTarget
|
||||
import org.jetbrains.compose.experimental.dsl.UiKitConfiguration
|
||||
import org.jetbrains.compose.experimental.uikit.tasks.AbstractComposeIosTask
|
||||
import org.jetbrains.compose.experimental.uikit.tasks.ExperimentalPackComposeApplicationForXCodeTask
|
||||
import org.jetbrains.compose.internal.getLocalProperty
|
||||
import org.jetbrains.compose.internal.localPropertiesFile
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||
|
||||
fun Project.registerConnectedDeviceTasks(
|
||||
mppExt: KotlinMultiplatformExtension,
|
||||
id: String,
|
||||
deploy: DeployTarget.ConnectedDevice,
|
||||
projectName: String,
|
||||
@@ -44,21 +47,27 @@ fun Project.registerConnectedDeviceTasks(
|
||||
|
||||
for (configuration in configurations) {
|
||||
val configName = configuration.name
|
||||
val iosCompiledAppDir = xcodeProjectDir.resolve(RELATIVE_PRODUCTS_PATH)
|
||||
.resolve("$configName-iphoneos/${projectName}.app")
|
||||
val targetBuildPath = xcodeProjectDir.resolve(RELATIVE_PRODUCTS_PATH)
|
||||
.resolve("$configName-iphoneos")
|
||||
val iosCompiledAppDir = targetBuildPath.resolve("${projectName}.app")
|
||||
|
||||
val taskPackageUiKitAppForXcode = configurePackComposeUiKitApplicationForXCodeTask(
|
||||
mppExt = mppExt,
|
||||
id = id,
|
||||
configName = configName,
|
||||
projectName = projectName,
|
||||
targetBuildPath = targetBuildPath,
|
||||
targetType = ExperimentalPackComposeApplicationForXCodeTask.UikitTarget.Arm64,
|
||||
)
|
||||
|
||||
val taskBuild = tasks.composeIosTask<AbstractComposeIosTask>("iosBuildIphoneOs$id$configName") {
|
||||
dependsOn(taskGenerateXcodeProject)
|
||||
dependsOn(taskPackageUiKitAppForXcode)
|
||||
doLast {
|
||||
// xcrun xcodebuild -showsdks (list all sdk)
|
||||
val sdk = SDK_PREFIX_IPHONEOS + getSimctlListData().runtimes.first().version
|
||||
val scheme = projectName // xcrun xcodebuild -list -project . (list all schemes)
|
||||
|
||||
val buildDir = "build"
|
||||
|
||||
// cleanup build directory as xcodebuild does not do it (provoking unexpected side effects).
|
||||
project.delete(xcodeProjectDir.resolve(buildDir))
|
||||
|
||||
runExternalTool(
|
||||
MacUtils.xcrun,
|
||||
listOf(
|
||||
@@ -66,7 +75,7 @@ fun Project.registerConnectedDeviceTasks(
|
||||
"-scheme", scheme,
|
||||
"-project", ".",
|
||||
"-configuration", configName,
|
||||
"-derivedDataPath", buildDir,
|
||||
"-derivedDataPath", BUILD_DIR_NAME,
|
||||
"-arch", "arm64",
|
||||
"-sdk", sdk,
|
||||
"-allowProvisioningUpdates",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
package org.jetbrains.compose.experimental.uikit.internal
|
||||
|
||||
import org.gradle.api.*
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
import org.jetbrains.compose.desktop.application.internal.Arch
|
||||
import org.jetbrains.compose.desktop.application.internal.MacUtils
|
||||
@@ -13,8 +13,11 @@ import org.jetbrains.compose.desktop.application.internal.currentArch
|
||||
import org.jetbrains.compose.experimental.dsl.DeployTarget
|
||||
import org.jetbrains.compose.experimental.dsl.UiKitConfiguration
|
||||
import org.jetbrains.compose.experimental.uikit.tasks.AbstractComposeIosTask
|
||||
import org.jetbrains.compose.experimental.uikit.tasks.ExperimentalPackComposeApplicationForXCodeTask
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||
|
||||
fun Project.registerSimulatorTasks(
|
||||
mppExt: KotlinMultiplatformExtension,
|
||||
id: String,
|
||||
deploy: DeployTarget.Simulator,
|
||||
projectName: String,
|
||||
@@ -92,33 +95,39 @@ fun Project.registerSimulatorTasks(
|
||||
|
||||
for (configuration in configurations) {
|
||||
val configName = configuration.name
|
||||
val iosCompiledAppDir = xcodeProjectDir.resolve(RELATIVE_PRODUCTS_PATH)
|
||||
.resolve("$configName-iphonesimulator/${projectName}.app")
|
||||
val targetBuildPath = xcodeProjectDir.resolve(RELATIVE_PRODUCTS_PATH)
|
||||
.resolve("$configName-iphonesimulator")
|
||||
val iosCompiledAppDir = targetBuildPath.resolve("${projectName}.app")
|
||||
|
||||
val taskPackageUiKitAppForXcode = configurePackComposeUiKitApplicationForXCodeTask(
|
||||
mppExt = mppExt,
|
||||
id = id,
|
||||
configName = configName,
|
||||
projectName = projectName,
|
||||
targetBuildPath = targetBuildPath,
|
||||
targetType = ExperimentalPackComposeApplicationForXCodeTask.UikitTarget.X64,
|
||||
)
|
||||
|
||||
val taskBuild = tasks.composeIosTask<AbstractComposeIosTask>("iosSimulatorBuild$id$configName") {
|
||||
dependsOn(taskGenerateXcodeProject)
|
||||
dependsOn(taskPackageUiKitAppForXcode)
|
||||
doLast {
|
||||
// xcrun xcodebuild -showsdks (list all sdk)
|
||||
val sdk = SDK_PREFIFX_SIMULATOR + getSimctlListData().runtimes.first().version
|
||||
val scheme = projectName // xcrun xcodebuild -list -project . (list all schemes)
|
||||
repeat(2) {
|
||||
// todo repeat(2) is workaround of error (domain=NSPOSIXErrorDomain, code=22)
|
||||
// The bundle identifier of the application could not be determined
|
||||
// Ensure that the application's Info.plist contains a value for CFBundleIdentifier.
|
||||
runExternalTool(
|
||||
MacUtils.xcrun,
|
||||
listOf(
|
||||
"xcodebuild",
|
||||
"-scheme", scheme,
|
||||
"-project", ".",
|
||||
"-configuration", configName,
|
||||
"-derivedDataPath", "build",
|
||||
"-arch", simulatorArch,
|
||||
"-sdk", sdk
|
||||
),
|
||||
workingDir = xcodeProjectDir
|
||||
)
|
||||
}
|
||||
runExternalTool(
|
||||
MacUtils.xcrun,
|
||||
listOf(
|
||||
"xcodebuild",
|
||||
"-scheme", scheme,
|
||||
"-project", ".",
|
||||
"-configuration", configName,
|
||||
"-derivedDataPath", BUILD_DIR_NAME,
|
||||
"-arch", simulatorArch,
|
||||
"-sdk", sdk
|
||||
),
|
||||
workingDir = xcodeProjectDir
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ abstract class ExperimentalPackComposeApplicationForXCodeTask : DefaultTask() {
|
||||
@TaskAction
|
||||
fun run() {
|
||||
val destinationDir = destinationDir.get().asFile
|
||||
project.delete(destinationDir)
|
||||
project.mkdir(destinationDir)
|
||||
|
||||
val executableSource = kotlinBinary.get().asFile
|
||||
val dsymSource = File(executableSource.absolutePath + ".dSYM")
|
||||
@@ -52,6 +54,7 @@ abstract class ExperimentalPackComposeApplicationForXCodeTask : DefaultTask() {
|
||||
}
|
||||
}
|
||||
|
||||
executableDestination.parentFile.mkdirs()
|
||||
// We need to preserve executable flag for resulting executable, "FileKt.copyTo" extension method does not allow this.
|
||||
Files.copy(executableSource.toPath(), executableDestination.toPath(), StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING)
|
||||
}
|
||||
|
||||
@@ -37,6 +37,9 @@ internal inline fun <reified T : Task> Project.registerTask(
|
||||
internal fun Provider<String>.toDir(project: Project): Provider<Directory> =
|
||||
project.layout.dir(map { File(it) })
|
||||
|
||||
internal fun Provider<File>.fileToDir(project: Project): Provider<Directory> =
|
||||
project.layout.dir(this)
|
||||
|
||||
val Project.localPropertiesFile get() = project.rootProject.file("local.properties")
|
||||
|
||||
fun Project.getLocalProperty(key: String): String? {
|
||||
|
||||
Reference in New Issue
Block a user