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