Slide 1

Slide 1 text

Flutter × Kotlin Multiplatform by 2022/04/27 #6 #ca_ fl utter_kmm by Taiki Suzuki طଘͷϓϩδΣΫτʹ KMMΛಋೖ͢ΔͨΊͷରԠࡦ

Slide 2

Slide 2 text

ࣗݾ঺հ #ca_ fl utter_kmm marty_suzuki marty-suzuki Taiki Suzuki

Slide 3

Slide 3 text

ΞδΣϯμ #ca_ fl utter_kmm •͜Ε·ͰͷऔΓ૊Έ •ϓϩδΣΫτͷߏ੒ͱΞʔΩςΫνϟ •KMMΛར༻ͨ͠৽ػೳ։ൃ •ݱࡏͱࠓޙͷల๬

Slide 4

Slide 4 text

͜Ε·ͰͷऔΓ૊Έ #ca_ fl utter_kmm

Slide 5

Slide 5 text

͜Ε·ͰͷऔΓ૊Έ #ca_ fl utter_kmm +BO ɹɹ,..Λར༻ͯ͠ ɹɹɹɹ"QJ$MJFOUͷڞ௨ԽΛ։࢝

Slide 6

Slide 6 text

͜Ε·ͰͷऔΓ૊Έ #ca_ fl utter_kmm +BO ɹɹ,..Λར༻ͯ͠ ɹɹɹɹ"QJ$MJFOUͷڞ௨ԽΛ։࢝ "OESPJEɾJ04ͰΞϓϦϦχϡʔΞϧϓϩδΣΫτ

Slide 7

Slide 7 text

͜Ε·ͰͷऔΓ૊Έ #ca_ fl utter_kmm +BO ɹɹ,..Λར༻ͯ͠ ɹɹɹɹ"QJ$MJFOUͷڞ௨ԽΛ։࢝ 'FC ɹɹ'MVUUFSY,..CZ$" "OESPJEɾJ04ͰΞϓϦϦχϡʔΞϧϓϩδΣΫτ

Slide 8

Slide 8 text

ͪΐ͏ͲҰ೥͘Β͍લʹ #ca_ fl utter_kmm https://speakerdeck.com/martysuzuki/iosnikmmwodao-ru-surutips ͜ͷษڧձͰొஃͨ͠໷ 
 ࡢ೔ͷ͜ͱͷΑ͏ʹ 
 ࠓ͸͖ͬΓͱࢥ͍ग़͢

Slide 9

Slide 9 text

͜Ε·ͰͷऔΓ૊Έ #ca_ fl utter_kmm +BO ɹɹ,..Λར༻ͯ͠ ɹɹɹɹ"QJ$MJFOUͷڞ௨ԽΛ։࢝ 'FC ɹɹ'MVUUFSY,..CZ$" .BS ɹɹ"QJ$MJFOUΛຊ൪؀ڥͰϦϦʔε "OESPJEɾJ04ͰΞϓϦϦχϡʔΞϧϓϩδΣΫτ

Slide 10

Slide 10 text

͜Ε·ͰͷऔΓ૊Έ #ca_ fl utter_kmm +BO ɹɹ,..Λར༻ͯ͠ ɹɹɹɹ"QJ$MJFOUͷڞ௨ԽΛ։࢝ 'FC ɹɹ'MVUUFSY,..CZ$" .BS ɹɹ"QJ$MJFOUΛຊ൪؀ڥͰϦϦʔε /BUJWFνʔϜͰ "QJ$MJFOUͷΈΛӡ༻ "OESPJEɾJ04ͰΞϓϦϦχϡʔΞϧϓϩδΣΫτ

Slide 11

Slide 11 text

͜Ε·ͰͷऔΓ૊Έ #ca_ fl utter_kmm +BO ɹɹ,..Λར༻ͯ͠ ɹɹɹɹ"QJ$MJFOUͷڞ௨ԽΛ։࢝ 'FC ɹɹ'MVUUFSY,..CZ$" .BS ɹɹ"QJ$MJFOUΛຊ൪؀ڥͰϦϦʔε +VM ɹɹ.1&νʔϜൃ଍ ɹɹɹɹ .VMUJQMBUGPSN&OHJOFFSJOH /BUJWFνʔϜͰ "QJ$MJFOUͷΈΛӡ༻ "OESPJEɾJ04ͰΞϓϦϦχϡʔΞϧϓϩδΣΫτ

Slide 12

Slide 12 text

Multiplatform EngineeringνʔϜൃ଍ #ca_ fl utter_kmm @ronnnnn_jp @marty_suzuki ΤϯυϢʔβʔͷମݧͱ։ൃޮ཰ΛଛͳΘͣʹγεςϜΛڞ௨Խ͢Δɻ ͦͯ͠ɺશϓϥοτϑΥʔϜʹ͓͚Δ"#&."ΞϓϦͷσϦόϦʔΛՃ଎ͤ͞Δɻ ϛογϣϯ

Slide 13

Slide 13 text

͜Ε·ͰͷऔΓ૊Έ #ca_ fl utter_kmm +BO ɹɹ,..Λར༻ͯ͠ ɹɹɹɹ"QJ$MJFOUͷڞ௨ԽΛ։࢝ 'FC ɹɹ'MVUUFSY,..CZ$" .BS ɹɹ"QJ$MJFOUΛຊ൪؀ڥͰϦϦʔε +VM ɹɹ.1&νʔϜൃ଍ ɹɹɹɹ .VMUJQMBUGPSN&OHJOFFSJOH 4FQ ɹɹϓϩδΣΫτߏ੒ͱ ɹɹɹɹΞʔΩςΫνϟͷઃܭ։࢝ /BUJWFνʔϜͰ "QJ$MJFOUͷΈΛӡ༻ "OESPJEɾJ04ͰΞϓϦϦχϡʔΞϧϓϩδΣΫτ

Slide 14

Slide 14 text

ϓϩδΣΫτߏ੒ͱΞʔΩςΫνϟ #ca_ fl utter_kmm https://developer.abema.io/2021/sessions/bvjpwJEoGP/

Slide 15

Slide 15 text

͜Ε·ͰͷऔΓ૊Έ #ca_ fl utter_kmm +BO ɹɹ,..Λར༻ͯ͠ ɹɹɹɹ"QJ$MJFOUͷڞ௨ԽΛ։࢝ 'FC ɹɹ'MVUUFSY,..CZ$" .BS ɹɹ"QJ$MJFOUΛຊ൪؀ڥͰϦϦʔε +VM ɹɹ.1&νʔϜൃ଍ ɹɹɹɹ .VMUJQMBUGPSN&OHJOFFSJOH 4FQ ɹɹϓϩδΣΫτߏ੒ͱ ɹɹɹɹΞʔΩςΫνϟͷઃܭ։࢝ +BO ɹɹϚΠϦετϓϩδΣΫτ ɹɹɹɹ,..Λར༻ͯ͠։ൃ։࢝ /BUJWFνʔϜͰ "QJ$MJFOUͷΈΛӡ༻ "OESPJEɾJ04ͰΞϓϦϦχϡʔΞϧϓϩδΣΫτ

Slide 16

Slide 16 text

͜Ε·ͰͷऔΓ૊Έ #ca_ fl utter_kmm +BO ɹɹ,..Λར༻ͯ͠ ɹɹɹɹ"QJ$MJFOUͷڞ௨ԽΛ։࢝ 'FC ɹɹ'MVUUFSY,..CZ$" .BS ɹɹ"QJ$MJFOUΛຊ൪؀ڥͰϦϦʔε +VM ɹɹ.1&νʔϜൃ଍ ɹɹɹɹ .VMUJQMBUGPSN&OHJOFFSJOH 4FQ ɹɹϓϩδΣΫτߏ੒ͱ ɹɹɹɹΞʔΩςΫνϟͷઃܭ։࢝ +BO ɹɹϚΠϦετϓϩδΣΫτ ɹɹɹɹ,..Λར༻ͯ͠։ൃ։࢝ .BS ɹɹϚΠϦετΛϦϦʔε /BUJWFνʔϜͰ "QJ$MJFOUͷΈΛӡ༻ "OESPJEɾJ04ͰΞϓϦϦχϡʔΞϧϓϩδΣΫτ

Slide 17

Slide 17 text

ϓϩδΣΫτߏ੒ͱΞʔΩςΫνϟ #ca_ fl utter_kmm

Slide 18

Slide 18 text

ϓϩδΣΫτߏ੒ͱΞʔΩςΫνϟ (2021 NovҎલ) #ca_ fl utter_kmm iOS Android iOS-MPP ApiClient Protobuf ,..

Slide 19

Slide 19 text

iOS Android iOS-MPP ,.. ϓϩδΣΫτߏ੒ͱΞʔΩςΫνϟ (2021 NovҎલ) #ca_ fl utter_kmm ApiClient Protobuf w ϦΫΤετͨ͠63-ͷϨεϙϯεΛQSPUPCVGͰฦ͢ w (JU)VC1BDLBHFTͰBSUJGBDUΛఏڙ

Slide 20

Slide 20 text

iOS Android ,.. ApiClient Protobuf iOS-MPP ϓϩδΣΫτߏ੒ͱΞʔΩςΫνϟ (2021 NovҎલ) #ca_ fl utter_kmm w ෳ਺ͷϞδϡʔϧΛJ04޲͚ʹͭʹ·ͱΊΔϞδϡʔϧ w (JU)VC3FMFBTFTͰYDGSBNFXPSLΛఏڙ

Slide 21

Slide 21 text

iOS ,.. ApiClient Protobuf Android iOS-MPP ϓϩδΣΫτߏ੒ͱΞʔΩςΫνϟ (2021 NovҎલ) #ca_ fl utter_kmm JNQMFNFOUBUJPO BQJDMJFOUBQJDMJFOU "OESPJEͱJ04͕ผϦϙδτϦʹͳ͓ͬͯΓ ͦΕͧΕͰར༻͍ͨ͠όʔδϣϯΛࢦఆ JNQMFNFOUBUJPO BQJDMJFOUBQJDMJFOU

Slide 22

Slide 22 text

Android ,.. ApiClient Protobuf iOS iOS-MPP ϓϩδΣΫτߏ੒ͱΞʔΩςΫνϟ (2021 NovҎલ) #ca_ fl utter_kmm w $PDPB1PETܦ༝ͰYDGSBNFXPSLΛར༻

Slide 23

Slide 23 text

ϓϩδΣΫτߏ੒ͱΞʔΩςΫνϟ (2021 NovҎ߱) #ca_ fl utter_kmm iOS Android iOS-MPP ApiClient Protobuf core apiservice core repository service service
 interface domain mapper core
 domain usecase
 model usecase
 mapper groups apiservice groups repository groups usecase groups usecase I/F groups domain ,..

Slide 24

Slide 24 text

,.. iOS Android iOS-MPP ApiClient Protobuf core apiservice core repository service service
 interface domain mapper core
 domain usecase
 model usecase
 mapper groups apiservice groups repository groups usecase groups usecase I/F groups domain ػೳ͝ͱͷ୯Ґͷgroups #ca_ fl utter_kmm w HSPVQTYYYͷػೳ͝ͱͷ୯ҐͷTVCQSPKFDU

Slide 25

Slide 25 text

,.. iOS Android iOS-MPP ApiClient Protobuf core apiservice core repository service service
 interface domain mapper core
 domain usecase
 model usecase
 mapper groups apiservice groups repository groups usecase groups usecase I/F groups domain ػೳ͝ͱͷ୯Ґͷgroups #ca_ fl utter_kmm groups apiservice groups repository groups usecase groups usecase I/F groups domain groups apiservice groups repository groups usecase groups usecase I/F groups domain groups apiservice groups repository groups usecase groups usecase I/F groups domain 'FBUVSF 
 ಛू .ZMJTU ϚΠϦετ 4FBSDI ݕࡧ 4MPU(SPVQ 
 ์ૹ࿮άϧʔϓ

Slide 26

Slide 26 text

,.. iOS Android iOS-MPP ApiClient Protobuf core apiservice core repository service service
 interface domain mapper core
 domain usecase
 model usecase
 mapper groups apiservice groups repository groups usecase groups usecase I/F groups domain ֤moduleͷ಺༰ #ca_ fl utter_kmm w EPNBJOPCKFDU w BQJTFSWJDFJOUFSGBDF w SFQPTJUPSZJOUFSGBDF w SFQPTJUPSZJOUFSGBDFͷ࣮૷ w VTFDBTFNPEFM w VTFDBTFJOUFSGBDF w VTFDBTFJOUFSGBDFͷ࣮૷ w EPNBJOPCKFDU͔ΒVTFDBTFNPEFM΁ͷϚοϐϯά w BQJTFSWJDFJOUFSGBDFͷ࣮૷ w QSPUPCVG͔ΒEPNBJOPCKFDU΁ͷϚοϐϯά

Slide 27

Slide 27 text

,.. iOS Android iOS-MPP ApiClient Protobuf core apiservice core repository service service
 interface domain mapper core
 domain usecase
 model usecase
 mapper groups apiservice groups repository groups usecase groups usecase I/F groups domain groupsͷartifactͷ؅ཧ #ca_ fl utter_kmm w HSPVQTYYYͷػೳ͝ͱͷ୯ҐͷTVCQSPKFDU w ࠨਤͷϞδϡʔϧΛ؅ཧ w ػೳ͝ͱʹಉ͡HSPVQ*EɾWFSTJPOͰBSUJGBDUΛఏڙ

Slide 28

Slide 28 text

#ca_ fl utter_kmm (JU)VC"1* (JU)VC $* HSPVQTGFBUVSFͷमਖ਼13ΛNBJOʹϚʔδ GFBUVSFYYYͷUBHΛ੾Δ GFBUVSFYYYͷSFMFBTFTΛ࡞੒ HSPVQTGFBUVSFͷ֤ϞδϡʔϧͷΈΛϏϧυ HSPVQTGFBUVSFͷ֤ϞδϡʔϧΛ HSPVQTGFBUVSFYYYYYYͷBSUJGBDUͱͯ͠ (JU)VC1BDLBHFTʹΞοϓϩʔυ ػೳ͝ͱͷartifactͷ഑෍ྫ

Slide 29

Slide 29 text

,.. service
 interface groups repository ApiClient Protobuf core apiservice core repository service domain mapper core
 domain usecase
 model usecase
 mapper groups apiservice groups usecase groups usecase I/F groups domain iOS Android iOS-MPP ֤ΞϓϦ͔Βͷࢀর #ca_ fl utter_kmm JNQMFNFOUBUJPO NZMJTUEPNBJO JNQMFNFOUBUJPO NZMJTUBQJTFSWJDF ʜ JNQMFNFOUBUJPO TFBSDIEPNBJO JNQMFNFOUBUJPO TFBSDIBQJTFSWJDF ʜ JNQMFNFOUBUJPO NZMJTUEPNBJO JNQMFNFOUBUJPO NZMJTUBQJTFSWJDF ʜ JNQMFNFOUBUJPO TFBSDIEPNBJO JNQMFNFOUBUJPO TFBSDIBQJTFSWJDF ʜ "OESPJEͱJ04͕ผϦϙδτϦͳͷͰɺػೳ։ൃͷ ਐḿʹࠩ෼͕͋ͬͯ΋ڐ༰Ͱ͖ΔΑ͏ʹ͢Δ

Slide 30

Slide 30 text

,.. iOS Android iOS-MPP ApiClient Protobuf groups apiservice groups repository groups usecase groups usecase I/F groups domain ڞ௨ͷ΋ͷΛ·ͱΊͨcore #ca_ fl utter_kmm core apiservice core repository service service
 interface domain mapper core
 domain usecase
 model usecase
 mapper w ڞ௨Ͱར༻͞ΕΔ΋ͷ͕·ͱ·ͬͨ୯ҰͷTVCQSPKFDU w ӈਤͷϞδϡʔϧΛ؅ཧ

Slide 31

Slide 31 text

,.. iOS Android iOS-MPP ApiClient Protobuf groups apiservice groups repository groups usecase groups usecase I/F groups domain ֤Ϟδϡʔϧͷ಺༰ #ca_ fl utter_kmm core apiservice core repository service service
 interface domain mapper core
 domain usecase
 model usecase
 mapper w EPNBJOPCKFDU w BQJTFSWJDFJOUFSGBDF w SFQPTJUPSZJOUFSGBDF w BQJTFSWJDFJOUFSGBDFͷ࣮૷ w SFQPTJUPSZJOUFSGBDFͷ࣮૷ w QSPUPCVG͔ΒEPNBJOPCKFDU΁ͷϚοϐϯά w TFSWJDFJOUFSGBDFͷ࣮૷ w EPNBJOPCKFDU͔ΒVTFDBTFNPEFM΁ͷϚοϐϯά w VTFDBTFͰڞ௨Ͱར༻͞ΕΔ΋ͷΛදݱͨ͠JOUFSGBDF w VTFDBTFNPEFM

Slide 32

Slide 32 text

,.. iOS Android iOS-MPP ApiClient Protobuf groups apiservice groups repository groups usecase groups usecase I/F groups domain coreͷartifactͷ؅ཧ #ca_ fl utter_kmm core apiservice core repository service service
 interface domain mapper core
 domain usecase
 model usecase
 mapper w ڞ௨Ͱར༻͞ΕΔ΋ͷ͕·ͱ·ͬͨ୯ҰͷTVCQSPKFDU w ӈਤͷϞδϡʔϧΛ؅ཧ w DPSF഑ԼΛಉ͡HSPVQ*EɾWFSTJPOͰBSUJGBDUΛఏڙ

Slide 33

Slide 33 text

,.. iOS Android iOS-MPP ApiClient Protobuf groups apiservice groups repository groups usecase groups usecase I/F groups domain groupsͷcore΁ͷґଘ #ca_ fl utter_kmm core apiservice core repository service service
 interface domain mapper core
 domain usecase
 model usecase
 mapper 'FBUVSF .ZMJTU 4FBSDI 4MPU(SPVQ FUD ֤ػೳ HSPVQ ͕ґଘ͍ͯ͠ΔͨΊ ޙํޓ׵Λอ࣮ͬͨ૷ʹ͢Δඞཁ͕͋Δ

Slide 34

Slide 34 text

,.. core repository service usecase
 model usecase
 mapper groups repository groups usecase service
 interface iOS Android iOS-MPP groups usecase I/F groups domain domain mapper core
 domain ApiClient Protobuf groups apiservice apiservice͕ଘࡏ͢Δཧ༝ #ca_ fl utter_kmm core apiservice ଞͷϓϥοτϑΥʔϜͰ΋"QJ$MJFOU͕ར༻Ͱ͖Δঢ়ଶʹ͢ΔͨΊ ϞόΠϧΞϓϦ޲͚ͷEPNBJOʹґଘͨ͠BQJTFSWJDFΛఆ͍ٛͯ͠Δ

Slide 35

Slide 35 text

#ca_ fl utter_kmm • AndroidͱiOSͷϦϙδτϦ͕෼͔Ε͍ͯΔ͜ͱʹ߹Θ͍ͤͯΔ • ্هʹ൐ͬͯɺҟͳΔόʔδϣϯΛࢀরͰ͖Δߏ੒Λઃܭ • ϞϊϨϙʹͳΔ౳Ͱɺߏ੒͕มΘΔՄೳੑ͸͋Δ ϓϩδΣΫτߏ੒ͱΞʔΩςΫνϟ

Slide 36

Slide 36 text

KMMΛར༻ͨ͠৽ػೳ։ൃ #ca_ fl utter_kmm

Slide 37

Slide 37 text

KMMΛར༻ͨ͠৽ػೳ։ൃ #ca_ fl utter_kmm • ϚΠϏσΦɾ௨஌༧໿ΛϚΠϦετʹू໿͢ΔϓϩδΣΫτ • KMMଆʹண໨ͨ͠։ൃମ੍ @marty_suzuki w ,..ͷج൫੔උ w ։ൃதʹ໰୊͕ൃੜͨ͠ࡍͷରԠ @ronnnnn_jp w ,..ͷج൫੔උ w "OESPJEͷ࣮૷୲౰ @akkyie w ϚΠϦετͷઃܭ w J04ͷ࣮૷୲౰ w 6*ͷରԠ w طଘͷमਖ਼౳ w 6*ͷରԠ w طଘͷमਖ਼౳

Slide 38

Slide 38 text

ج൫ଆͰࣄલʹରԠ༧ఆͩͬͨ΋ͷ #ca_ fl utter_kmm ΞϓϦଆͰطʹ࣮૷͞Ε͍ͯΔRepository౳ΛɺKMMͷ۩ମ࣮૷ͷ UseCase͔Βݺͼग़ͯ͠ར༻Ͱ͖ΔΑ͏ʹ͢Δ class SomeUseCaseImpl( private val userRepository: UserRepository ) { fun someFunction() { userRepository.observeUserId() } } KMM protocol UserRepository { var userID: Property { get } } iOS interface UserStore { val userId: StateFlow } Android

Slide 39

Slide 39 text

UserRepositoryΛAndroidͰద߹͢Δ #ca_ fl utter_kmm interface UserRepository { fun observeUserId(): Flow } KMM class UserRepositoryImpl( private val userStore: UserStore, ) : UserRepository { override fun observeUserId(): Flow { return userStore.userId .map { UserId(string = it) } } } Android ϦΞʔΩςΫνϟதͰ'MVYͷ࣮૷͕࢒͍ͬͯΔͨΊ 
 4UPSFΛϥοϓ͢ΔܗͰద߹͢Δ

Slide 40

Slide 40 text

UserRepositoryΛiOSͰద߹͢Δ #ca_ fl utter_kmm class UserRepository: KMM.UserRepository { let userID: Property func observeUserId() -> Kotlinx_coroutines_coreFlow { ... } } iOS interface UserRepository { fun observeUserId(): Flow } KMM طଘͷ6TFS3FQPTJUPSZͷ࣮૷ʹ,..ଆͷ 6TFS3FQPTJUPSZΛద߹͢Δ 'MPX͸JOUFSGBDF͕ͩɺ0CKFDUJWF$ͷQSPUPSPMͰ͸ܕύϥϝʔλʹ ରԠ͍ͯ͠ͳ͍ͨΊɺܕύϥϝʔλ͕ফࣦ͢ΔͷͰλΠϓΞϯηʔϑ

Slide 41

Slide 41 text

UserRepositoryΛiOSͰద߹ͤ͞ΔͨΊʹ #ca_ fl utter_kmm abstract class FlowCompat( protected open val base: Flow ) { open fun toFlow(): Flow = base } class MutableStateFlowCompat private constructor( override val base: MutableStateFlow ) : FlowCompat(base) { constructor(value: T) : this(MutableStateFlow(value)) override fun toFlow(): Flow = base.asStateFlow() fun send(value: T) { base.value = value } } KMM/iosMain DMBTTͰ͋Ε͹0CKFDUJWF$ͷ-JHIUXFJHIU(FOFSJDT͕ ར༻Ͱ͖ΔͨΊɺ'MPXΛϥοϓ͢Δ J04Ͱఆ͍ٛͯͨ͠1SPQFSUZ͸ঢ়ଶΛอ͍࣋ͯ͠ΔͨΊ'MPX$PNQBU ʹద߹ͨ͠4UBUF'MPXΛϥοϓͨ͠ΫϥεΛఆٛ

Slide 42

Slide 42 text

UserRepositoryΛiOSͰద߹ͤ͞ΔͨΊʹ #ca_ fl utter_kmm interface UserRepositoryInterface { fun observeUserId(): FlowCompat } class UserRepositoryTranslator( private val userRepository: UserRepositoryInterface ) : UserRepository { override fun observeUserId(): Flow { return userRepository.observeUserId().toFlow() } } KMM/iosMain 6TFS3FQPTJUPSZ*OUFSGBDFͷॲཧΛ6TFS3FQPTJUPSZ޲͚ʹ ม׵͢ΔΞμϓλΛఆٛ 'MPX5Ͱ͸ͳ͘ɺJ04޲͚ʹ'MPX$PNQBU5Λར༻͢ΔJOUFSGBDFΛ 
 6TFS3FQPTJUPSZͱಉҰͷཻ౓Ͱఆٛ

Slide 43

Slide 43 text

UserRepositoryΛiOSͰద߹ͤ͞ΔͨΊʹ #ca_ fl utter_kmm class UserRepository: KMM.UserRepositoryInterface { let userID: Property func observeUserId() -> FlowCompat { ... } } let usecase = KMM.SomeUseCaseImpl( userRepository: KMM.UserRepositoryTranslator( repository: UserRepository() ) ) iOS 6TFS*EܕͷΈΛड͚෇͚ΔΑ͏ʹͳͬͨͷͰλΠϓηʔϑʹ 6TFS3FQPTJUPSZ*OUFSGBDFʹద߹ͨ͠ΫϥεΛ6TFS3FQPTJUPSZ5SBOTMBUPSΛ ʹ౉ͯ͠ɺ಺෦ͷม׵ॲཧΛհ͢Δ͜ͱͰ,..ͷ6TFS3FQPTJUPSZʹద߹Ͱ͖Δ

Slide 44

Slide 44 text

class UserRepository: KMM.UserRepositoryInterface { let userID: Property func observeUserId() -> FlowCompat { ... } } let usecase = KMM.SomeUseCaseImpl( userRepository: KMM.UserRepositoryTranslator( repository: UserRepository() ) ) iOS UserRepositoryΛiOSͰద߹ͤ͞ΔͨΊʹ #ca_ fl utter_kmm ,..Ͱఏڙ͞ΕΔΦϒδΣΫτ͸ɺܕύϥϝʔλ͕"OZ0CKFDUͰ ͳ͚Ε͹͍͚ͳ͍͕ɺ4XJGUͷ0QUJPOBM͸FOVNͰ͋ΔͨΊফࣦ͢Δ

Slide 45

Slide 45 text

UserRepositoryΛiOSͰద߹ͤ͞ΔͨΊʹ #ca_ fl utter_kmm sealed class Nullable { class Null: Nullable() data class Nonnull(val value: T): Nullable() fun toDefault(): T? = when (this) { is Null -> null is Nonnull -> value } } KMM/iosMain /VMMBCMFΛJ04޲͚ͷ໌ࣔతͳܕͱͯ͠ఆٛ͠ ,..ଆͰ͸,PUMJOͷ/VMMBCMFʹ໭ͤΔΑ͏ʹ͢Δ

Slide 46

Slide 46 text

UserRepositoryΛiOSͰద߹ͤ͞ΔͨΊʹ #ca_ fl utter_kmm interface UserRepositoryInterface { fun observeUserId(): FlowCompat> } class UserRepositoryTranslator( private val userRepository: UserRepositoryInterface ) : UserRepository { override fun observeUserId(): Flow { return userRepository.observeUserId().toFlow() .map { it.toDefault() } } } KMM/iosMain 'MPX6TFS*E Λ'MPX$PNQBU/VMMBCMF6TFS*EͰఆٛ͠ ۩ମ࣮૷Ͱ͸UP%FGBVMU Λݺͼग़ͯ͠'MPX6TFS*E ʹ໭͢

Slide 47

Slide 47 text

UserRepositoryΛiOSͰద߹ͤ͞ΔͨΊʹ #ca_ fl utter_kmm class UserRepository: KMM.UserRepositoryInterface { let userID: Property private let mutableUserID = MutableStateFlowCompat>( value: NullableNull() ) init() { userID.asObservable() .subscribe(onNext: { [mutableUserID] id in let id = id.map { NullableNonnull(value: UserId(string: $0)) } ?? NullableNull() mutableUserID.send(value: id) }) .disposed(by: disposeBag) } func observeUserId() -> FlowCompat> { mutableUserID } } iOS J04Ͱ΋/VMMBCMFͱͯ͠,..ଆʹ౉ͤΔΑ͏ʹͳΔ

Slide 48

Slide 48 text

Ξμϓλ͢Δ΋ͷΛࣗಈੜ੒ #ca_ fl utter_kmm ΞμϓλΛࣗಈੜ੒͢ΔػߏΛ,PUMJO4ZNCPM1SPDFTTJOHΛ༻͍࣮ͯ૷͠ɺ಺੡ϥΠϒϥϦͰఏڙ

Slide 49

Slide 49 text

#ca_ fl utter_kmm • AndroidͰ͸໰୊ͳ͘ద߹͕Ͱ͖Δ • interfaceʹgenerics͕࢖ΘΕ͍ͯΔͱiOSͰ͸ܕύϥϝʔλ͕
 ফࣦ͢Δ • genericsͷܕύϥϝʔλͷNullable͸iOSͰ͸ফࣦ͢Δ • ΞμϓλΛࣗಈੜ੒͠ɺ্هͷ՝୊Λղܾ طଘͷRepository౳ΛKMMͷRepositoryʹద߹͢Δ

Slide 50

Slide 50 text

ܨ͗ࠐΈ࣌ʹ՝୊ʹͳͬͨ͜ͱ #ca_ fl utter_kmm interface SomeUseCase { fun display(): LoadableResult } sealed class LoadableResult { object Loading : LoadableResult() data class Loaded(val result: R) : LoadableResult() } KMM

Slide 51

Slide 51 text

Android͔Βݺͼग़͢৔߹ #ca_ fl utter_kmm val usecase: SomeUseCase = ... when (val loadableResult = usecase.display()) { LoadableResult.Loading -> { // handle loading } is LoadableResult.Loaded -> { loadableResult.result // handle loaded } } Android ໢ཏతʹ෼ذ͕Ͱ͖ɺͦΕͧΕͷॲཧ͕Ͱ͖Δ

Slide 52

Slide 52 text

iOS͔Βݺͼग़͢৔߹ #ca_ fl utter_kmm let usecase: SomeUseCase = ... let loadableResult = usecase.display() if loadableResult is LoadableResultLoading { // handle loading } else if let loaded = loadableResult as? LoadableResultLoaded { loaded.result // handle loaded } else { assertionFailure("might not reach this line") } iOS ໢ཏతʹ෼ذͰ͖ͳ͍ͨΊɺΠϨΪϡϥʔέʔεͷߟྀ͕ ίʔυ্ඞཁʹͳͬͯ͠·͏ ͨͩͷ-PEBCMF3FTVMUͷαϒΫϥεʹͳͬͯ͠·͏ͷͰ -PBEJOHͱ-PBEFEΛΩϟετͯ͠൑ఆ͢Δ͔͠ͳ͍

Slide 53

Slide 53 text

iOSͰ໢ཏతʹ෼ذͰ͖ΔΑ͏ʹ͢Δ #ca_ fl utter_kmm sealed class LoadableResult { object Loading : LoadableResult() data class Loaded(val result: R) : LoadableResult() fun fold( onLoading: (LoadableResult.Loading) -> T, onLoaded: (LoadableResult.Loaded) -> T ): T = when (this) { is LoadableResult.Loading -> onLoading(this) is LoadableResult.Loaded -> onLoaded(this) } } KMM/iosMain ,PUMJOͷ3FTVMUͰ࣮૷͞Ε͍ͯΔ4VDDFTTͱ'BJMVSFΛ ల։ͯ͠೚ҙͷܕʹม׵͢ΔGPMEؔ਺ͷΑ͏ͳରԠ https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-result/#extension-functions

Slide 54

Slide 54 text

#ca_ fl utter_kmm loadableResult.fold( onLoading: <#(LoadableResultLoading) -> Any?#>, onLoaded: <#(LoadableResultLoaded) -> Any?#> ) <# -> Any?#> iOS iOSͰ໢ཏతʹ෼ذͰ͖ΔΑ͏ʹ͢Δ 0CKFDUJWF$ͷ-JHIUXFJHIU(FOFSJDT͸ؔ਺ͷܕύϥϝʔλʹରԠ͍ͯ͠ͳ͍ ͷͰɺ,..ଆͰఆٛͯ͠΋J04Ͱ͸"OZʹͳͬͯ͠·͏

Slide 55

Slide 55 text

#ca_ fl utter_kmm class LoadableResultFold( value: LoadableResult, onLoading: (LoadableResult.Loading) -> T, onLoaded: (LoadableResult.Loaded) -> T ) { val result: T = when (value) { is LoadableResult.Loading -> onLoading(value) is LoadableResult.Loaded -> onLoaded(value) } } KMM/iosMain iOSͰ໢ཏతʹ෼ذͰ͖ΔΑ͏ʹ͢Δ 0CKFDUJWF$ͷ-JHIUXFJHIU(FOFSJDTͰΫϥεͷܕύϥϝʔλ͸ར༻Ͱ͖ΔͷͰ ໢ཏతʹ෼ذΛͯ͠ม׵͢ΔͨΊͷΫϥεΛఆٛ͢Δ

Slide 56

Slide 56 text

#ca_ fl utter_kmm final class Box { let value: T init(_ value: T) { self.value = value } } let value: SomeUseCaseModel? = LoadableResultFold( value: loadableResult, onLoading: { _ in Box(nil) }, onLoaded: { Box($0.result) } ).result.value iOS iOSͰ໢ཏతʹ෼ذͰ͖ΔΑ͏ʹ͢Δ ܕύϥϝʔλ͸"OZ0CKFDUͰͳ͚Ε͹͍͚ͳ͍ͨΊɺ#PYܕ౳ͰϥοϓΛͯ͠ 
 ,..Ͱఏڙ͞Ε͍ͯΔܕΛऔΓग़ͤΔΑ͏ʹ͢Δ

Slide 57

Slide 57 text

foldΛࣗಈੜ੒ #ca_ fl utter_kmm GPMEΛࣗಈੜ੒͢ΔػߏΛ,PUMJO4ZNCPM1SPDFTTJOHΛ༻͍࣮ͯ૷͠ɺ಺੡ϥΠϒϥϦͰఏڙ

Slide 58

Slide 58 text

#ca_ fl utter_kmm • iOSͰ͸sealed classΛ໢ཏతʹ෼ذͰ͖ͳ͍ • enumͰ΋ಉ༷ͷ͜ͱ͕ى͖Δ • Objective-CͷLightweight GenericsͰදݱͰ͖ΔൣғͰରԠ • foldΛࣗಈੜ੒͢Δ͜ͱͰɺ্هͷ໰୊Λղܾ ໢ཏతʹ෼ذ͢Δ

Slide 59

Slide 59 text

νʔϜ಺ͷiOS։ൃऀ޲͚ͷυΩϡϝϯτ #ca_ fl utter_kmm

Slide 60

Slide 60 text

ݱࡏͱࠓޙͷల๬ #ca_ fl utter_kmm

Slide 61

Slide 61 text

#ca_ fl utter_kmm ৽ػೳ։ൃޙͷKPT @marty_suzuki @ronnnnn_jp @akkyie ,15ͷ࣮ࢪ 5SZΛࠓظͷϚΠϧετʔϯʹ૊ࠐ

Slide 62

Slide 62 text

#ca_ fl utter_kmm νʔϜ಺ͷυΩϡϝϯτͷ੔උ @ronnnnn_jp Built with Docusaurus

Slide 63

Slide 63 text

#ca_ fl utter_kmm νʔϜ಺΁ͷڞ༗

Slide 64

Slide 64 text

ࠓޙͷల๬ #ca_ fl utter_kmm • MPEͷϛογϣϯ͸։ൃޮ཰Խ • ։ൃޮ཰͕ஶ͘͠མͪΔ͜ͱ͕͋Ε͹ɺKMM͔Βͷఫୀ΋ࢹ໺ʹೖΕ͍ͯΔ • ج൫͕੔͍ͬͯͳ͍ͷͰɺ·ͩKMMΛ׆༻ͨ͠։ൃ
 ޮ཰Λ࠷େԽͰ͖͍ͯͳ͍ • ࠓظͰج൫Λ੔͑ɺདྷظʹ൑அͰ͖Δঢ়ଶΛ໨ࢦ͢

Slide 65

Slide 65 text

One more thing… #ca_ fl utter_kmm

Slide 66

Slide 66 text

#ca_ fl utter_kmm KMMʹؔ͢Δొஃ @ronnnnn_jp 6݄຤ͷฐࣾΠϕϯτͰKMMʹ͍ͭͯͷొஃ༧ఆ

Slide 67

Slide 67 text

by Taiki Suzuki طଘͷϓϩδΣΫτʹ KMMΛಋೖ͢ΔͨΊͷରԠࡦ #ca_ fl utter_kmm ͝੩ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠