Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Compose Multiplatformってどうなんだろう? | Flutter × Kotlin Multiplatform by CyberAgent #7

Compose Multiplatformってどうなんだろう? | Flutter × Kotlin Multiplatform by CyberAgent #7

Seiya Kokushi

August 04, 2022
Tweet

More Decks by Seiya Kokushi

Other Decks in Technology

Transcript

  1. plugins { id("com.android.application") kotlin("multiplatform") id("org.jetbrains.compose") } w $PNQPTF.VMUJQMBUGPSNͷϏϧυઃఆΛߦ͏QMVHJO w DPNQPTFKCHSBEMFQMVHJOTDPNQPTF

    w $PNQPTF1MVHJOLU IUUQTHJUIVCDPN+FU#SBJOTDPNQPTFKCCMPCNBTUFSHSBEMFQMVHJOTDPNQPTFTSDNBJOLPUMJO PSHKFUCSBJOTDPNQPTF$PNQPTF1MVHJOLU chat-mpp/build.gradle.kts
  2. chat-mpp/gradle.properties compose.version=1.2.0-alpha01-dev725 pluginManagement { // … plugins { val kotlinVersion

    = extra["kotlin.version"] as String val agpVersion = extra["agp.version"] as String val composeVersion = extra["compose.version"] as String kotlin("jvm").version(kotlinVersion) kotlin("multiplatform").version(kotlinVersion) kotlin("android").version(kotlinVersion) id("com.android.base").version(agpVersion) id("com.android.application").version(agpVersion) id("com.android.library").version(agpVersion) id("org.jetbrains.compose").version(composeVersion) } } chat-mpp/settings.gradle.kts w CVJMEHSBEMFLUTͷQMVHJOʹόʔδϣϯࢦఆͯ͠΋0,
  3. kotlin { android() iosX64("uikitX64") { binaries { executable() { entryPoint

    = "main" freeCompilerArgs += listOf( "-linker-option", "-framework", "-linker-option", "Metal", "-linker-option", "-framework", "-linker-option", "CoreText", "-linker-option", "-framework", "-linker-option", "CoreGraphics" ) } } } iosArm64("uikitArm64") { binaries { executable() { entryPoint = "main" freeCompilerArgs += listOf( "-linker-option", "-framework", "-linker-option", "Metal", "-linker-option", "-framework", "-linker-option", "CoreText", "-linker-option", "-framework", "-linker-option", "CoreGraphics" ) } } } // … } w ͳͥVJLJU9YY͕͍͍ͭͯΔʁ chat-mpp/build.gradle.kts
  4. IUUQTHJUIVCDPN+FU#SBJOTDPNQPTFKCCMPCEDFGDEBCFCGDCCDE HSBEMFQMVHJOTDPNQPTFTSDNBJOLPUMJOPSHKFUCSBJOTDPNQPTFFYQFSJNFOUBMVJLJUJOUFSOBM DPO fi HVSF&YQFSJNFOUBM6JLJU"QQMJDBUJPOLU- internal fun Project.configureExperimentalUikitApplication( mppExt: KotlinMultiplatformExtension,

    application: ExperimentalUiKitApplication ) { // … 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 // ... } configureIosDeployTasks(application) } w σόΠεʹΞϓϦΛσϓϩΠ͢ΔλΠϛϯάͰ 
 6JLJU5BSHFUͰఆٛ͞Ε໊ͨલͱҰக͢ΔλʔήοτΛͱΓʹ͍͘ chat-mpp/build.gradle.kts
  5. kotlin { // … sourceSets { val commonMain by getting

    { dependencies { implementation(compose.ui) implementation(compose.foundation) implementation(compose.material) implementation(compose.runtime) implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.3") } } // … val androidMain by getting { dependsOn(commonMain) kotlin.srcDirs("src/jvmMain/kotlin") dependencies { api("androidx.appcompat:appcompat:1.4.1") implementation("androidx.activity:activity-compose:1.4.0") } } // … val nativeMain by creating { dependsOn(commonMain) } val uikitMain by creating { dependsOn(nativeMain) } val uikitX64Main by getting { dependsOn(uikitMain) } val uikitArm64Main by getting { dependsOn(uikitMain) } } } chat-mpp/build.gradle.kts
  6. kotlin { // … sourceSets { val commonMain by getting

    { dependencies { implementation(compose.ui) implementation(compose.foundation) implementation(compose.material) implementation(compose.runtime) implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.3") } } // … val androidMain by getting { dependsOn(commonMain) kotlin.srcDirs("src/jvmMain/kotlin") dependencies { api("androidx.appcompat:appcompat:1.4.1") implementation("androidx.activity:activity-compose:1.4.0") } } // … val nativeMain by creating { dependsOn(commonMain) } val uikitMain by creating { dependsOn(nativeMain) } val uikitX64Main by getting { dependsOn(uikitMain) } val uikitArm64Main by getting { dependsOn(uikitMain) } } } DPNQPTFؔ࿈ͷ ϥΠϒϥϦͷґଘΛ௥Ճ chat-mpp/build.gradle.kts
  7. IUUQTHJUIVCDPN+FU#SBJOTDPNQPTFKCCMPCEDFGDEBCFCGDCCDE HSBEMFQMVHJOTDPNQPTFTSDNBJOLPUMJOPSHKFUCSBJOTDPNQPTF$PNQPTF1MVHJOLU- w Ͳ͜Λࢦ͍ͯ͠Δͷ͔ʁ w $PNQPTF1MVHJOLUͷதʹఆ͕ٛ͋Δ w OBWJHBUJPOͳͲ͸·ͩͳ͍ object Dependencies

    { val desktop = DesktopDependencies val animation get() = composeDependency("org.jetbrains.compose.animation:animation") val animationGraphics get() = composeDependency("org.jetbrains.compose.animation:animation-graphics") val foundation get() = composeDependency("org.jetbrains.compose.foundation:foundation") val material get() = composeDependency("org.jetbrains.compose.material:material") @ExperimentalComposeLibrary val material3 get() = composeDependency("org.jetbrains.compose.material3:material3") val runtime get() = composeDependency("org.jetbrains.compose.runtime:runtime") val ui get() = composeDependency("org.jetbrains.compose.ui:ui") @ExperimentalComposeLibrary val uiTestJUnit4 get() = composeDependency("org.jetbrains.compose.ui:ui-test-junit4") val uiTooling get() = composeDependency("org.jetbrains.compose.ui:ui-tooling") val preview get() = composeDependency("org.jetbrains.compose.ui:ui-tooling-preview") val materialIconsExtended get() = composeDependency("org.jetbrains.compose.material:material-icons-extended") val web: WebDependencies get() = WebDependencies } chat-mpp/build.gradle.kts
  8. IUUQTHJUIVCDPN+FU#SBJOTDPNQPTFKCCMPCEDFGDEBCFCGDCCDE HSBEMFQMVHJOTDPNQPTFTSDNBJOLPUMJOPSHKFUCSBJOTDPNQPTF$PNQPTF1MVHJOLU- w PSHKFUCSBJOTDPNQPTFYYY͸BOESPJEYΛϑΥʔΫ͍ͯ͠Δ w +FU#SBJOT͕.VMUJQMBUGPSNରԠ w +FU#SBJOTBOESPJEY object Dependencies

    { val desktop = DesktopDependencies val animation get() = composeDependency("org.jetbrains.compose.animation:animation") val animationGraphics get() = composeDependency("org.jetbrains.compose.animation:animation-graphics") val foundation get() = composeDependency("org.jetbrains.compose.foundation:foundation") val material get() = composeDependency("org.jetbrains.compose.material:material") @ExperimentalComposeLibrary val material3 get() = composeDependency("org.jetbrains.compose.material3:material3") val runtime get() = composeDependency("org.jetbrains.compose.runtime:runtime") val ui get() = composeDependency("org.jetbrains.compose.ui:ui") @ExperimentalComposeLibrary val uiTestJUnit4 get() = composeDependency("org.jetbrains.compose.ui:ui-test-junit4") val uiTooling get() = composeDependency("org.jetbrains.compose.ui:ui-tooling") val preview get() = composeDependency("org.jetbrains.compose.ui:ui-tooling-preview") val materialIconsExtended get() = composeDependency("org.jetbrains.compose.material:material-icons-extended") val web: WebDependencies get() = WebDependencies } chat-mpp/build.gradle.kts
  9. chat-mpp/build.gradle.kts IUUQTHJUIVCDPN+FU#SBJOTDPNQPTFKCCMPCEDFGDEBCFCGDCCDE HSBEMFQMVHJOTDPNQPTFTSDNBJOLPUMJOPSHKFUCSBJOTDPNQPTF$PNQPTF1MVHJOLU- w DPNQPTFKCDPNQPTF಺ͰTVCNPEVMFͱͯ͠ࢀর w DPNQPTFFYUFSOBMEPDMBWB w DPNQPTFGSBNFXPSLTTVQQPSU w

    DPNQPTFHPMEFO w DPNQPTFQSFCVJMUTBOESPJEYJOUFSOBM object Dependencies { val desktop = DesktopDependencies val animation get() = composeDependency("org.jetbrains.compose.animation:animation") val animationGraphics get() = composeDependency("org.jetbrains.compose.animation:animation-graphics") val foundation get() = composeDependency("org.jetbrains.compose.foundation:foundation") val material get() = composeDependency("org.jetbrains.compose.material:material") @ExperimentalComposeLibrary val material3 get() = composeDependency("org.jetbrains.compose.material3:material3") val runtime get() = composeDependency("org.jetbrains.compose.runtime:runtime") val ui get() = composeDependency("org.jetbrains.compose.ui:ui") @ExperimentalComposeLibrary val uiTestJUnit4 get() = composeDependency("org.jetbrains.compose.ui:ui-test-junit4") val uiTooling get() = composeDependency("org.jetbrains.compose.ui:ui-tooling") val preview get() = composeDependency("org.jetbrains.compose.ui:ui-tooling-preview") val materialIconsExtended get() = composeDependency("org.jetbrains.compose.material:material-icons-extended") val web: WebDependencies get() = WebDependencies }
  10. compose.experimental { // … uikit.application { bundleIdPrefix = "org.jetbrains" projectName

    = "Chat" deployConfigurations { simulator("IPhone8") { //Usage: ./gradlew iosDeployIPhone8Debug device = IOSDevices.IPHONE_8 } simulator("IPad") { //Usage: ./gradlew iosDeployIPadDebug device = IOSDevices.IPAD_MINI_6th_Gen } connectedDevice("Device") { //First need specify your teamId here, or in local.properties (compose.ios.teamId=***) //teamId="***" //Usage: ./gradlew iosDeployDeviceRelease } } } } w σόΠεΛม͑Δ͜ͱ΋Մೳ ͔ͳΓଟ͘ͷσόΠεʹରԠ  w *04%FWJDFTLUʹҰཡ͕͋Δ IUUQTHJUIVCDPN+FU#SBJOTDPNQPTFKCCMPCNBTUFSHSBEMFQMVHJOTDPNQPTFTSDNBJOLPUMJOPSH KFUCSBJOTDPNQPTFFYQFSJNFOUBMETM*04%FWJDFTLU chat-mpp/build.gradle.kts
  11. commonMain/ChatApp.kt @Composable fun ChatApp() { // … MaterialTheme { Box(modifier

    = Modifier.fillMaxSize()) { Scaffold( topBar = { TopAppBar( title = { Text("Chat sample") } ) } ) { Column( modifier = Modifier.fillMaxSize() ) { Box(Modifier.weight(1f)) { Messages(state.messages) } SendMessage { text -> store.send( Action.SendMessage( Message(myUser, timeMs = timestampMs(), text) ) ) } } } } } // … }
  12. uikitMain/kotlin/main.uikit.kt fun main() { val args = emptyArray<String>() memScoped {

    val argc = args.size + 1 val argv = (arrayOf("skikoApp") + args).map { it.cstr.ptr }.toCValues() autoreleasepool { UIApplicationMain(argc, argv, null, NSStringFromClass(SkikoAppDelegate)) } } } class SkikoAppDelegate : UIResponder, UIApplicationDelegateProtocol { companion object : UIResponderMeta(), UIApplicationDelegateProtocolMeta @ObjCObjectBase.OverrideInit constructor() : super() private var _window: UIWindow? = null override fun window() = _window override fun setWindow(window: UIWindow?) { _window = window } override fun application(application: UIApplication, didFinishLaunchingWithOptions: Map<Any?, *>?): Boolean { window = UIWindow(frame = UIScreen.mainScreen.bounds) window!!.rootViewController = Application("Chat") { ChatApp() } window!!.makeKeyAndVisible() return true } } IUUQTHJUIVCDPN+FU#SBJOTBOESPJEYCMPCFDEDGFFGDCG DPNQPTFVJVJTSDVJLJU.BJOLPUMJOBOESPJEYDPNQPTFVJVJLJU$PNQPTF8JOEPXVJLJULU-
  13. uikitMain/kotlin/main.uikit.kt fun main() { val args = emptyArray<String>() memScoped {

    val argc = args.size + 1 val argv = (arrayOf("skikoApp") + args).map { it.cstr.ptr }.toCValues() autoreleasepool { UIApplicationMain(argc, argv, null, NSStringFromClass(SkikoAppDelegate)) } } } class SkikoAppDelegate : UIResponder, UIApplicationDelegateProtocol { companion object : UIResponderMeta(), UIApplicationDelegateProtocolMeta @ObjCObjectBase.OverrideInit constructor() : super() private var _window: UIWindow? = null override fun window() = _window override fun setWindow(window: UIWindow?) { _window = window } override fun application(application: UIApplication, didFinishLaunchingWithOptions: Map<Any?, *>?): Boolean { window = UIWindow(frame = UIScreen.mainScreen.bounds) window!!.rootViewController = Application("Chat") { ChatApp() } window!!.makeKeyAndVisible() return true } } IUUQTHJUIVCDPN+FU#SBJOTBOESPJEYCMPCFDEDGFFGDCG DPNQPTFVJVJTSDVJLJU.BJOLPUMJOBOESPJEYDPNQPTFVJVJLJU$PNQPTF8JOEPXVJLJULU- DPNQPTFͱ6*,JUͷੈքΛͭͳ͙ 🤝