dima-avdeev-jb
3 years ago
committed by
GitHub
19 changed files with 608 additions and 64 deletions
@ -1,29 +0,0 @@ |
|||||||
name: ComposeFallingBalls |
|
||||||
options: |
|
||||||
bundleIdPrefix: org.jetbrains |
|
||||||
settings: |
|
||||||
DEVELOPMENT_TEAM: N462MKSJ7M |
|
||||||
CODE_SIGN_IDENTITY: "iPhone Developer" |
|
||||||
CODE_SIGN_STYLE: Automatic |
|
||||||
MARKETING_VERSION: "1.0" |
|
||||||
CURRENT_PROJECT_VERSION: "4" |
|
||||||
SDKROOT: iphoneos |
|
||||||
targets: |
|
||||||
ComposeFallingBalls: |
|
||||||
type: application |
|
||||||
platform: iOS |
|
||||||
deploymentTarget: "12.0" |
|
||||||
prebuildScripts: |
|
||||||
- script: cd "$SRCROOT" && ./gradlew -i -p . packComposeUikitApplicationForXCode |
|
||||||
name: GradleCompile |
|
||||||
info: |
|
||||||
path: plists/Ios/Info.plist |
|
||||||
properties: |
|
||||||
UILaunchStoryboardName: "" |
|
||||||
sources: |
|
||||||
- "src/" |
|
||||||
settings: |
|
||||||
LIBRARY_SEARCH_PATHS: "$(inherited)" |
|
||||||
ENABLE_BITCODE: "YES" |
|
||||||
ONLY_ACTIVE_ARCH: "NO" |
|
||||||
VALID_ARCHS: "arm64" |
|
@ -1,29 +0,0 @@ |
|||||||
name: ComposeMinesweeper |
|
||||||
options: |
|
||||||
bundleIdPrefix: org.jetbrains |
|
||||||
settings: |
|
||||||
DEVELOPMENT_TEAM: N462MKSJ7M |
|
||||||
CODE_SIGN_IDENTITY: "iPhone Developer" |
|
||||||
CODE_SIGN_STYLE: Automatic |
|
||||||
MARKETING_VERSION: "1.0" |
|
||||||
CURRENT_PROJECT_VERSION: "4" |
|
||||||
SDKROOT: iphoneos |
|
||||||
targets: |
|
||||||
ComposeMinesweeper: |
|
||||||
type: application |
|
||||||
platform: iOS |
|
||||||
deploymentTarget: "12.0" |
|
||||||
prebuildScripts: |
|
||||||
- script: cd "$SRCROOT" && ./gradlew -i -p . packComposeUikitApplicationForXCode |
|
||||||
name: GradleCompile |
|
||||||
info: |
|
||||||
path: plists/Ios/Info.plist |
|
||||||
properties: |
|
||||||
UILaunchStoryboardName: "" |
|
||||||
sources: |
|
||||||
- "src/" |
|
||||||
settings: |
|
||||||
LIBRARY_SEARCH_PATHS: "$(inherited)" |
|
||||||
ENABLE_BITCODE: "YES" |
|
||||||
ONLY_ACTIVE_ARCH: "NO" |
|
||||||
VALID_ARCHS: "arm64" |
|
@ -0,0 +1,59 @@ |
|||||||
|
/* |
||||||
|
* 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.dsl |
||||||
|
|
||||||
|
/** |
||||||
|
* iOS device type |
||||||
|
* xcrun simctl list devices |
||||||
|
*/ |
||||||
|
@Suppress("unused") |
||||||
|
public enum class IOSDevices(val id: String) { |
||||||
|
IPHONE_6S("com.apple.CoreSimulator.SimDeviceType.iPhone-6s"), |
||||||
|
IPHONE_6S_PLUS("com.apple.CoreSimulator.SimDeviceType.iPhone-6s-Plus"), |
||||||
|
IPHONE_SE("com.apple.CoreSimulator.SimDeviceType.iPhone-SE"), |
||||||
|
IPHONE_7("com.apple.CoreSimulator.SimDeviceType.iPhone-7"), |
||||||
|
IPHONE_7_PLUS("com.apple.CoreSimulator.SimDeviceType.iPhone-7-Plus"), |
||||||
|
IPHONE_8("com.apple.CoreSimulator.SimDeviceType.iPhone-8"), |
||||||
|
IPHONE_8_PLUS("com.apple.CoreSimulator.SimDeviceType.iPhone-8-Plus"), |
||||||
|
IPHONE_X("com.apple.CoreSimulator.SimDeviceType.iPhone-X"), |
||||||
|
IPHONE_XS("com.apple.CoreSimulator.SimDeviceType.iPhone-XS"), |
||||||
|
IPHONE_XS_MAX("com.apple.CoreSimulator.SimDeviceType.iPhone-XS-Max"), |
||||||
|
IPHONE_XR("com.apple.CoreSimulator.SimDeviceType.iPhone-XR"), |
||||||
|
IPHONE_11("com.apple.CoreSimulator.SimDeviceType.iPhone-11"), |
||||||
|
IPHONE_11_PRO("com.apple.CoreSimulator.SimDeviceType.iPhone-11-Pro"), |
||||||
|
IPHONE_11_PRO_MAX("com.apple.CoreSimulator.SimDeviceType.iPhone-11-Pro-Max"), |
||||||
|
IPHONE_SE_2nd_Gen("com.apple.CoreSimulator.SimDeviceType.iPhone-SE--2nd-generation-"), |
||||||
|
IPHONE_12_MINI("com.apple.CoreSimulator.SimDeviceType.iPhone-12-mini"), |
||||||
|
IPHONE_12("com.apple.CoreSimulator.SimDeviceType.iPhone-12"), |
||||||
|
IPHONE_12_PRO("com.apple.CoreSimulator.SimDeviceType.iPhone-12-Pro"), |
||||||
|
IPHONE_12_PRO_MAX("com.apple.CoreSimulator.SimDeviceType.iPhone-12-Pro-Max"), |
||||||
|
IPHONE_13_PRO("com.apple.CoreSimulator.SimDeviceType.iPhone-13-Pro"), |
||||||
|
IPHONE_13_PRO_MAX("com.apple.CoreSimulator.SimDeviceType.iPhone-13-Pro-Max"), |
||||||
|
IPHONE_13_MINI("com.apple.CoreSimulator.SimDeviceType.iPhone-13-mini"), |
||||||
|
IPHONE_13("com.apple.CoreSimulator.SimDeviceType.iPhone-13"), |
||||||
|
IPOD_TOUCH_7th_Gen("com.apple.CoreSimulator.SimDeviceType.iPod-touch--7th-generation-"), |
||||||
|
IPAD_MINI_4("com.apple.CoreSimulator.SimDeviceType.iPad-mini-4"), |
||||||
|
IPAD_AIR_2("com.apple.CoreSimulator.SimDeviceType.iPad-Air-2"), |
||||||
|
IPAD_PRO_9_7_INCH("com.apple.CoreSimulator.SimDeviceType.iPad-Pro--9-7-inch-"), |
||||||
|
IPAD_PRO("com.apple.CoreSimulator.SimDeviceType.iPad-Pro"), |
||||||
|
IPAD_5th_Gen("com.apple.CoreSimulator.SimDeviceType.iPad--5th-generation-"), |
||||||
|
IPAD_PRO_12_9_INCH_2nd_Gen("com.apple.CoreSimulator.SimDeviceType.iPad-Pro--12-9-inch---2nd-generation-"), |
||||||
|
IPAD_PRO_10_5_INCH("com.apple.CoreSimulator.SimDeviceType.iPad-Pro--10-5-inch-"), |
||||||
|
IPAD_6th_Gen("com.apple.CoreSimulator.SimDeviceType.iPad--6th-generation-"), |
||||||
|
IPAD_7th_Gen("com.apple.CoreSimulator.SimDeviceType.iPad--7th-generation-"), |
||||||
|
IPAD_PRO_11_INCH("com.apple.CoreSimulator.SimDeviceType.iPad-Pro--11-inch-"), |
||||||
|
IPAD_PRO_12_9_INCH_3rd_Gen("com.apple.CoreSimulator.SimDeviceType.iPad-Pro--12-9-inch---3rd-generation-"), |
||||||
|
IPAD_PRO_11_INCH_2nd_Gen("com.apple.CoreSimulator.SimDeviceType.iPad-Pro--11-inch---2nd-generation-"), |
||||||
|
IPAD_PRO_12_9_INCH_4th_Gen("com.apple.CoreSimulator.SimDeviceType.iPad-Pro--12-9-inch---4th-generation-"), |
||||||
|
IPAD_MINI_5th_Gen("com.apple.CoreSimulator.SimDeviceType.iPad-mini--5th-generation-"), |
||||||
|
IPAD_AIR_3th_Gen("com.apple.CoreSimulator.SimDeviceType.iPad-Air--3rd-generation-"), |
||||||
|
IPAD_8th_Gen("com.apple.CoreSimulator.SimDeviceType.iPad--8th-generation-"), |
||||||
|
IPAD_9th_Gen("com.apple.CoreSimulator.SimDeviceType.iPad-9th-generation"), |
||||||
|
IPAD_AIR_4th_Gen("com.apple.CoreSimulator.SimDeviceType.iPad-Air--4th-generation-"), |
||||||
|
IPAD_PRO_11_INCH_3rd_Gen("com.apple.CoreSimulator.SimDeviceType.iPad-Pro-11-inch-3rd-generation"), |
||||||
|
IPAD_12_9_INCH_5th_Gen("com.apple.CoreSimulator.SimDeviceType.iPad-Pro-12-9-inch-5th-generation"), |
||||||
|
IPAD_MINI_6th_Gen("com.apple.CoreSimulator.SimDeviceType.iPad-mini-6th-generation"), |
||||||
|
} |
@ -0,0 +1,33 @@ |
|||||||
|
/* |
||||||
|
* 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.dsl |
||||||
|
|
||||||
|
import org.gradle.api.Action |
||||||
|
import org.gradle.api.model.ObjectFactory |
||||||
|
import javax.inject.Inject |
||||||
|
|
||||||
|
open class IosDeployConfigurations @Inject constructor( |
||||||
|
val objects: ObjectFactory |
||||||
|
) { |
||||||
|
internal val deployTargets: MutableList<DeployTargetWithId> = mutableListOf() |
||||||
|
public fun simulator(id: String, configureSimulator: Action<DeployTarget.Simulator>) { |
||||||
|
val currentSimulator = objects.newInstance(DeployTarget.Simulator::class.java) |
||||||
|
configureSimulator.execute(currentSimulator) |
||||||
|
deployTargets.add(DeployTargetWithId(id, currentSimulator)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
sealed interface DeployTarget { |
||||||
|
open class Simulator : DeployTarget { |
||||||
|
var device: IOSDevices = IOSDevices.IPHONE_8 |
||||||
|
var buildConfiguration: String = "Debug" |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
internal class DeployTargetWithId( |
||||||
|
val id: String, |
||||||
|
val deploy: DeployTarget |
||||||
|
) |
@ -0,0 +1,77 @@ |
|||||||
|
/* |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
|
||||||
|
@file:Suppress("unused") |
||||||
|
|
||||||
|
package org.jetbrains.compose.experimental.uikit.internal |
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable |
||||||
|
|
||||||
|
@Serializable |
||||||
|
internal class SimctlListData( |
||||||
|
val devicetypes: List<DeviceTypeData>, |
||||||
|
val runtimes: List<RuntimeData>, |
||||||
|
val devices: Map<String, List<DeviceData>>, |
||||||
|
val pairs: Map<String, WatchAndPhonePairData>, |
||||||
|
) |
||||||
|
|
||||||
|
@Serializable |
||||||
|
internal class DeviceTypeData( |
||||||
|
val name: String, |
||||||
|
val minRuntimeVersion: Long, |
||||||
|
val bundlePath: String, |
||||||
|
val maxRuntimeVersion: Long, |
||||||
|
val identifier: String, |
||||||
|
val productFamily: String |
||||||
|
) |
||||||
|
|
||||||
|
@Serializable |
||||||
|
internal class RuntimeData( |
||||||
|
val name: String, |
||||||
|
val bundlePath: String, |
||||||
|
val buildversion: String, |
||||||
|
val runtimeRoot: String, |
||||||
|
val identifier: String, |
||||||
|
val version: String, |
||||||
|
val isAvailable: Boolean, |
||||||
|
val supportedDeviceTypes: List<SupportedDeviceTypeData> |
||||||
|
) |
||||||
|
|
||||||
|
@Serializable |
||||||
|
internal class SupportedDeviceTypeData( |
||||||
|
val bundlePath: String, |
||||||
|
val name: String, |
||||||
|
val identifier: String, |
||||||
|
val productFamily: String |
||||||
|
) |
||||||
|
|
||||||
|
@Serializable |
||||||
|
internal class DeviceData( |
||||||
|
val name: String, |
||||||
|
val availabilityError: String? = null, |
||||||
|
val dataPath: String, |
||||||
|
val dataPathSize: Long, |
||||||
|
val logPath: String, |
||||||
|
val udid: String, |
||||||
|
val isAvailable: Boolean, |
||||||
|
val deviceTypeIdentifier: String, |
||||||
|
val state: String, |
||||||
|
) |
||||||
|
|
||||||
|
internal val DeviceData.booted: Boolean |
||||||
|
get() = state == "Booted" |
||||||
|
|
||||||
|
@Serializable |
||||||
|
internal class WatchAndPhonePairData( |
||||||
|
val watch: DeviceInPairData, |
||||||
|
val phone: DeviceInPairData |
||||||
|
) |
||||||
|
|
||||||
|
@Serializable |
||||||
|
internal class DeviceInPairData( |
||||||
|
val name: String, |
||||||
|
val udid: String, |
||||||
|
val state: String, |
||||||
|
) |
@ -0,0 +1,25 @@ |
|||||||
|
/* |
||||||
|
* 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 kotlinx.serialization.json.Json |
||||||
|
import org.jetbrains.compose.desktop.application.internal.MacUtils |
||||||
|
import org.jetbrains.compose.experimental.uikit.tasks.AbstractComposeIosTask |
||||||
|
|
||||||
|
val json = Json { |
||||||
|
ignoreUnknownKeys = true |
||||||
|
} |
||||||
|
|
||||||
|
internal fun AbstractComposeIosTask.getSimctlListData(): SimctlListData { |
||||||
|
lateinit var simctlResult: SimctlListData |
||||||
|
runExternalTool( |
||||||
|
MacUtils.xcrun, listOf("simctl", "list", "--json"), |
||||||
|
processStdout = { stdout -> |
||||||
|
simctlResult = json.decodeFromString(SimctlListData.serializer(), stdout) |
||||||
|
} |
||||||
|
) |
||||||
|
return simctlResult |
||||||
|
} |
@ -0,0 +1,84 @@ |
|||||||
|
/* |
||||||
|
* 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.* |
||||||
|
import org.gradle.api.tasks.TaskContainer |
||||||
|
import org.jetbrains.compose.desktop.application.internal.MacUtils |
||||||
|
import org.jetbrains.compose.desktop.application.internal.UnixUtils |
||||||
|
import org.jetbrains.compose.experimental.dsl.DeployTarget |
||||||
|
import org.jetbrains.compose.experimental.dsl.ExperimentalUiKitApplication |
||||||
|
import org.jetbrains.compose.experimental.uikit.tasks.AbstractComposeIosTask |
||||||
|
|
||||||
|
const val XCODE_GEN_GIT = "https://github.com/yonaskolb/XcodeGen.git" |
||||||
|
const val XCODE_GEN_TAG = "2.26.0" |
||||||
|
const val TASK_INSTALL_XCODE_GEN_NAME = "iosInstallXcodeGen" |
||||||
|
const val TASK_USE_XCODE_GEN_NAME = "iosUseXCodeGen" |
||||||
|
const val SDK_PREFIFX_SIMULATOR = "iphonesimulator" |
||||||
|
const val SDK_PREFIX_IPHONEOS = "iphoneos" |
||||||
|
|
||||||
|
internal fun Project.configureIosDeployTasks(application: ExperimentalUiKitApplication) { |
||||||
|
val projectName = application.projectName |
||||||
|
val bundleIdPrefix = application.bundleIdPrefix |
||||||
|
val xcodeGenSrc = rootProject.buildDir.resolve("xcodegen-$XCODE_GEN_TAG-src") |
||||||
|
val xcodeGenExecutable = xcodeGenSrc.resolve(".build/apple/Products/Release/xcodegen") |
||||||
|
val buildIosDir = buildDir.resolve("ios") |
||||||
|
|
||||||
|
tasks.composeIosTask<AbstractComposeIosTask>(TASK_INSTALL_XCODE_GEN_NAME) { |
||||||
|
onlyIf { !xcodeGenExecutable.exists() } |
||||||
|
doLast { |
||||||
|
xcodeGenSrc.deleteRecursively() |
||||||
|
runExternalTool( |
||||||
|
UnixUtils.git, |
||||||
|
listOf( |
||||||
|
"clone", |
||||||
|
"--depth", "1", |
||||||
|
"--branch", XCODE_GEN_TAG, |
||||||
|
XCODE_GEN_GIT, |
||||||
|
xcodeGenSrc.absolutePath |
||||||
|
) |
||||||
|
) |
||||||
|
runExternalTool( |
||||||
|
MacUtils.make, |
||||||
|
listOf("build"), |
||||||
|
workingDir = xcodeGenSrc |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
configureUseXcodeGenTask( |
||||||
|
buildIosDir = buildIosDir, |
||||||
|
projectName = projectName, |
||||||
|
bundleIdPrefix = bundleIdPrefix, |
||||||
|
xcodeGenExecutable = xcodeGenExecutable |
||||||
|
) |
||||||
|
|
||||||
|
application.deployConfigurations.deployTargets.forEach { target -> |
||||||
|
val id = target.id // .replaceFirstChar { it.uppercase() } // todo upperCase first char? ./gradlew iosDeployId |
||||||
|
when (target.deploy) { |
||||||
|
is DeployTarget.Simulator -> { |
||||||
|
registerSimulatorTasks( |
||||||
|
id = id, |
||||||
|
deploy = target.deploy, |
||||||
|
buildIosDir = buildIosDir, |
||||||
|
projectName = projectName, |
||||||
|
bundleIdPrefix = bundleIdPrefix |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
inline fun <reified T : Task> TaskContainer.composeIosTask( |
||||||
|
name: String, |
||||||
|
args: List<Any> = emptyList(), |
||||||
|
noinline configureFn: T.() -> Unit = {} |
||||||
|
) = register(name, T::class.java, *args.toTypedArray()).apply { |
||||||
|
configure { |
||||||
|
it.group = "Compose iOS" |
||||||
|
it.configureFn() |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,57 @@ |
|||||||
|
/* |
||||||
|
* 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.AbstractComposeIosTask |
||||||
|
import java.io.File |
||||||
|
|
||||||
|
internal fun Project.configureUseXcodeGenTask( |
||||||
|
buildIosDir: File, |
||||||
|
projectName: String, |
||||||
|
bundleIdPrefix: String, |
||||||
|
xcodeGenExecutable: File |
||||||
|
) { |
||||||
|
tasks.composeIosTask<AbstractComposeIosTask>(TASK_USE_XCODE_GEN_NAME) { |
||||||
|
dependsOn(TASK_INSTALL_XCODE_GEN_NAME) |
||||||
|
doLast { |
||||||
|
buildIosDir.mkdirs() |
||||||
|
buildIosDir.resolve("project.yml").writeText( |
||||||
|
""" |
||||||
|
name: $projectName |
||||||
|
options: |
||||||
|
bundleIdPrefix: $bundleIdPrefix |
||||||
|
settings: |
||||||
|
CODE_SIGN_IDENTITY: "iPhone Developer" |
||||||
|
CODE_SIGN_STYLE: Automatic |
||||||
|
MARKETING_VERSION: "1.0" |
||||||
|
CURRENT_PROJECT_VERSION: "4" |
||||||
|
SDKROOT: iphoneos |
||||||
|
targets: |
||||||
|
$projectName: |
||||||
|
type: application |
||||||
|
platform: iOS |
||||||
|
deploymentTarget: "12.0" |
||||||
|
prebuildScripts: |
||||||
|
- script: cd "${rootDir.absolutePath}" && ./gradlew -i -p . packComposeUikitApplicationForXCode |
||||||
|
name: GradleCompile |
||||||
|
info: |
||||||
|
path: plists/Ios/Info.plist |
||||||
|
properties: |
||||||
|
UILaunchStoryboardName: "" |
||||||
|
sources: |
||||||
|
- "../../src/" |
||||||
|
settings: |
||||||
|
LIBRARY_SEARCH_PATHS: "${'$'}(inherited)" |
||||||
|
ENABLE_BITCODE: "YES" |
||||||
|
ONLY_ACTIVE_ARCH: "NO" |
||||||
|
VALID_ARCHS: "arm64" |
||||||
|
""".trimIndent() |
||||||
|
) |
||||||
|
runExternalTool(xcodeGenExecutable, emptyList(), workingDir = buildIosDir) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,119 @@ |
|||||||
|
/* |
||||||
|
* 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.* |
||||||
|
import org.jetbrains.compose.desktop.application.internal.Arch |
||||||
|
import org.jetbrains.compose.desktop.application.internal.MacUtils |
||||||
|
import org.jetbrains.compose.desktop.application.internal.currentArch |
||||||
|
import org.jetbrains.compose.experimental.dsl.DeployTarget |
||||||
|
import org.jetbrains.compose.experimental.uikit.tasks.AbstractComposeIosTask |
||||||
|
import java.io.File |
||||||
|
|
||||||
|
|
||||||
|
fun Project.registerSimulatorTasks( |
||||||
|
id: String, |
||||||
|
deploy: DeployTarget.Simulator, |
||||||
|
buildIosDir: File, |
||||||
|
projectName: String, |
||||||
|
bundleIdPrefix: String |
||||||
|
) { |
||||||
|
val xcodeProjectDir = buildIosDir.resolve("$projectName.xcodeproj") |
||||||
|
val deviceName = "device-$id" |
||||||
|
|
||||||
|
val taskCreateSimulator = tasks.composeIosTask<AbstractComposeIosTask>("iosSimulatorCreate$id") { |
||||||
|
onlyIf { getSimctlListData().devices.map { it.value }.flatten().none { it.name == deviceName } } |
||||||
|
doFirst { |
||||||
|
val availableRuntimes = getSimctlListData().runtimes.filter { runtime -> |
||||||
|
runtime.supportedDeviceTypes.any { it.identifier == deploy.device.id } |
||||||
|
} |
||||||
|
val runtime = availableRuntimes.firstOrNull() ?: error("device not found is runtimes") |
||||||
|
runExternalTool( |
||||||
|
MacUtils.xcrun, |
||||||
|
listOf("simctl", "create", deviceName, deploy.device.id, runtime.identifier) |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
val taskBootSimulator = tasks.composeIosTask<AbstractComposeIosTask>("iosSimulatorBoot$id") { |
||||||
|
onlyIf { |
||||||
|
getSimctlListData().devices.map { it.value }.flatten().any { it.name == deviceName && it.booted.not() } |
||||||
|
} |
||||||
|
dependsOn(taskCreateSimulator) |
||||||
|
doLast { |
||||||
|
val device = getSimctlListData().devices.map { it.value }.flatten().firstOrNull { it.name == deviceName } |
||||||
|
?: error("device '$deviceName' not found") |
||||||
|
|
||||||
|
runExternalTool( |
||||||
|
MacUtils.xcrun, |
||||||
|
listOf("simctl", "boot", device.udid) |
||||||
|
) |
||||||
|
runExternalTool( |
||||||
|
MacUtils.open, |
||||||
|
listOf( |
||||||
|
"-a", "Simulator", |
||||||
|
"--args", "-CurrentDeviceUDID", device.udid |
||||||
|
) |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
val simulatorArch = when (currentArch) { |
||||||
|
Arch.X64 -> "x86_64" |
||||||
|
Arch.Arm64 -> "arm64" |
||||||
|
} |
||||||
|
val iosCompiledAppDir = xcodeProjectDir.resolve("build/Build/Products/Debug-iphonesimulator/$projectName.app") |
||||||
|
val taskBuild = tasks.composeIosTask<AbstractComposeIosTask>("iosSimulatorBuild$id") { |
||||||
|
dependsOn(TASK_USE_XCODE_GEN_NAME) |
||||||
|
doLast { |
||||||
|
val sdk = SDK_PREFIFX_SIMULATOR + getSimctlListData().runtimes.first().version // xcrun xcodebuild -showsdks |
||||||
|
val scheme = projectName // xcrun xcodebuild -list -project . |
||||||
|
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", deploy.buildConfiguration, |
||||||
|
"-derivedDataPath", "build", |
||||||
|
"-arch", simulatorArch, |
||||||
|
"-sdk", sdk |
||||||
|
), |
||||||
|
workingDir = xcodeProjectDir |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
val installIosSimulator = tasks.composeIosTask<AbstractComposeIosTask>("iosSimulatorInstall$id") { |
||||||
|
dependsOn(taskBuild, taskBootSimulator) |
||||||
|
doLast { |
||||||
|
val device = getSimctlListData().devices.map { it.value }.flatten() |
||||||
|
.firstOrNull { it.name == deviceName && it.booted } ?: error("device $deviceName not booted") |
||||||
|
runExternalTool( |
||||||
|
MacUtils.xcrun, |
||||||
|
listOf("simctl", "install", device.udid, iosCompiledAppDir.absolutePath) |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
tasks.composeIosTask<AbstractComposeIosTask>("iosDeploy$id") { |
||||||
|
dependsOn(installIosSimulator) |
||||||
|
doFirst { |
||||||
|
val device = getSimctlListData().devices.map { it.value }.flatten() |
||||||
|
.firstOrNull { it.name == deviceName && it.booted } ?: error("device $deviceName not booted") |
||||||
|
val bundleIdentifier = "$bundleIdPrefix.$projectName" |
||||||
|
runExternalTool( |
||||||
|
MacUtils.xcrun, |
||||||
|
listOf("simctl", "launch", "--console", device.udid, bundleIdentifier) |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,49 @@ |
|||||||
|
/* |
||||||
|
* 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.tasks |
||||||
|
|
||||||
|
import org.gradle.api.DefaultTask |
||||||
|
import org.gradle.api.file.Directory |
||||||
|
import org.gradle.api.internal.file.FileOperations |
||||||
|
import org.gradle.api.model.ObjectFactory |
||||||
|
import org.gradle.api.provider.Property |
||||||
|
import org.gradle.api.provider.Provider |
||||||
|
import org.gradle.api.provider.ProviderFactory |
||||||
|
import org.gradle.api.tasks.Internal |
||||||
|
import org.gradle.api.tasks.LocalState |
||||||
|
import org.gradle.process.ExecOperations |
||||||
|
import org.jetbrains.compose.desktop.application.internal.ComposeProperties |
||||||
|
import org.jetbrains.compose.desktop.application.internal.ExternalToolRunner |
||||||
|
import org.jetbrains.compose.desktop.application.internal.notNullProperty |
||||||
|
import javax.inject.Inject |
||||||
|
|
||||||
|
abstract class AbstractComposeIosTask : DefaultTask() { |
||||||
|
@get:Inject |
||||||
|
protected abstract val objects: ObjectFactory |
||||||
|
|
||||||
|
@get:Inject |
||||||
|
protected abstract val providers: ProviderFactory |
||||||
|
|
||||||
|
@get:Inject |
||||||
|
protected abstract val execOperations: ExecOperations |
||||||
|
|
||||||
|
@get:Inject |
||||||
|
protected abstract val fileOperations: FileOperations |
||||||
|
|
||||||
|
@get:LocalState |
||||||
|
protected val logsDir: Provider<Directory> = project.layout.buildDirectory.dir("compose/logs/$name") |
||||||
|
|
||||||
|
@get:Internal |
||||||
|
val verbose: Property<Boolean> = objects.notNullProperty<Boolean>().apply { |
||||||
|
set(providers.provider { |
||||||
|
logger.isDebugEnabled || ComposeProperties.isVerbose(providers).get() |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
@get:Internal |
||||||
|
internal val runExternalTool: ExternalToolRunner |
||||||
|
get() = ExternalToolRunner(verbose, logsDir, execOperations) |
||||||
|
} |
@ -0,0 +1,28 @@ |
|||||||
|
/* |
||||||
|
* 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.internal |
||||||
|
|
||||||
|
import kotlin.reflect.KProperty |
||||||
|
|
||||||
|
internal fun <T : Any> requiredDslProperty(missingMessage: String) = RequiredPropertyDelegate<T>(missingMessage) |
||||||
|
|
||||||
|
class RequiredPropertyDelegate<T>(val missingMessage: String) { |
||||||
|
var realValue: T? = null |
||||||
|
operator fun setValue( |
||||||
|
ref: Any, |
||||||
|
property: KProperty<*>, |
||||||
|
newValue: T |
||||||
|
) { |
||||||
|
realValue = newValue |
||||||
|
} |
||||||
|
|
||||||
|
operator fun getValue( |
||||||
|
ref: Any, |
||||||
|
property: KProperty<*> |
||||||
|
): T { |
||||||
|
return realValue ?: error(missingMessage) |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue