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

既存のプロジェクトにKMMを導入するための対応策

 既存のプロジェクトにKMMを導入するための対応策

Flutter × Kotlin Multiplatform by CyberAgent #6
https://cyberagent.connpass.com/event/243404/

Youtube
https://youtu.be/baP7shKzEEE?t=3420

Twitter
#ca_flutter_kmm

Ae276805027a01983503c3edafbdb6b2?s=128

Taiki Suzuki

April 27, 2022
Tweet

More Decks by Taiki Suzuki

Other Decks in Programming

Transcript

  1. Flutter × Kotlin Multiplatform by 2022/04/27 #6 #ca_ fl utter_kmm

    by Taiki Suzuki طଘͷϓϩδΣΫτʹ KMMΛಋೖ͢ΔͨΊͷରԠࡦ
  2. ࣗݾ঺հ #ca_ fl utter_kmm marty_suzuki marty-suzuki Taiki Suzuki

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

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

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

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

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

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

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

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

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

    ɹɹ"QJ$MJFOUΛຊ൪؀ڥͰϦϦʔε +VM ɹɹ.1&νʔϜൃ଍ ɹɹɹɹ .VMUJQMBUGPSN&OHJOFFSJOH /BUJWFνʔϜͰ "QJ$MJFOUͷΈΛӡ༻ "OESPJEɾJ04ͰΞϓϦϦχϡʔΞϧϓϩδΣΫτ
  12. Multiplatform EngineeringνʔϜൃ଍ #ca_ fl utter_kmm @ronnnnn_jp @marty_suzuki ΤϯυϢʔβʔͷମݧͱ։ൃޮ཰ΛଛͳΘͣʹγεςϜΛڞ௨Խ͢Δɻ ͦͯ͠ɺશϓϥοτϑΥʔϜʹ͓͚Δ"#&."ΞϓϦͷσϦόϦʔΛՃ଎ͤ͞Δɻ ϛογϣϯ

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

    ɹɹ"QJ$MJFOUΛຊ൪؀ڥͰϦϦʔε +VM ɹɹ.1&νʔϜൃ଍ ɹɹɹɹ .VMUJQMBUGPSN&OHJOFFSJOH 4FQ ɹɹϓϩδΣΫτߏ੒ͱ ɹɹɹɹΞʔΩςΫνϟͷઃܭ։࢝ /BUJWFνʔϜͰ "QJ$MJFOUͷΈΛӡ༻ "OESPJEɾJ04ͰΞϓϦϦχϡʔΞϧϓϩδΣΫτ
  14. ϓϩδΣΫτߏ੒ͱΞʔΩςΫνϟ #ca_ fl utter_kmm https://developer.abema.io/2021/sessions/bvjpwJEoGP/

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

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

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

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

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

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

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

    fl utter_kmm w $PDPB1PETܦ༝ͰYDGSBNFXPSLΛར༻
  23. ϓϩδΣΫτߏ੒ͱΞʔΩςΫνϟ (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 ,..
  24. ,.. 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
  25. ,.. 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 
 ์ૹ࿮άϧʔϓ
  26. ,.. 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΁ͷϚοϐϯά
  27. ,.. 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Λఏڙ
  28. #ca_ fl utter_kmm (JU)VC"1* (JU)VC $* HSPVQTGFBUVSFͷमਖ਼13ΛNBJOʹϚʔδ GFBUVSFYYYͷUBHΛ੾Δ GFBUVSFYYYͷSFMFBTFTΛ࡞੒ HSPVQTGFBUVSFͷ֤ϞδϡʔϧͷΈΛϏϧυ

    HSPVQTGFBUVSFͷ֤ϞδϡʔϧΛ HSPVQTGFBUVSFYYYYYYͷBSUJGBDUͱͯ͠ (JU)VC1BDLBHFTʹΞοϓϩʔυ ػೳ͝ͱͷartifactͷ഑෍ྫ
  29. ,.. 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͕ผϦϙδτϦͳͷͰɺػೳ։ൃͷ ਐḿʹࠩ෼͕͋ͬͯ΋ڐ༰Ͱ͖ΔΑ͏ʹ͢Δ
  30. ,.. 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 ӈਤͷϞδϡʔϧΛ؅ཧ
  31. ,.. 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
  32. ,.. 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Λఏڙ
  33. ,.. 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 ͕ґଘ͍ͯ͠ΔͨΊ ޙํޓ׵Λอ࣮ͬͨ૷ʹ͢Δඞཁ͕͋Δ
  34. ,.. 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Λఆ͍ٛͯ͠Δ
  35. #ca_ fl utter_kmm • AndroidͱiOSͷϦϙδτϦ͕෼͔Ε͍ͯΔ͜ͱʹ߹Θ͍ͤͯΔ • ্هʹ൐ͬͯɺҟͳΔόʔδϣϯΛࢀরͰ͖Δߏ੒Λઃܭ • ϞϊϨϙʹͳΔ౳Ͱɺߏ੒͕มΘΔՄೳੑ͸͋Δ ϓϩδΣΫτߏ੒ͱΞʔΩςΫνϟ

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

  37. 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 طଘͷमਖ਼౳
  38. ج൫ଆͰࣄલʹରԠ༧ఆͩͬͨ΋ͷ #ca_ fl utter_kmm ΞϓϦଆͰطʹ࣮૷͞Ε͍ͯΔRepository౳ΛɺKMMͷ۩ମ࣮૷ͷ UseCase͔Βݺͼग़ͯ͠ར༻Ͱ͖ΔΑ͏ʹ͢Δ class SomeUseCaseImpl( private val

    userRepository: UserRepository ) { fun someFunction() { userRepository.observeUserId() } } KMM protocol UserRepository { var userID: Property<User.ID?> { get } } iOS interface UserStore { val userId: StateFlow<String> } Android
  39. UserRepositoryΛAndroidͰద߹͢Δ #ca_ fl utter_kmm interface UserRepository { fun observeUserId(): Flow<UserId?>

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

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

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

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

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

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

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

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

    Property<User.ID> private let mutableUserID = MutableStateFlowCompat<Nullable<UserId>>( 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<Nullable<UserId>> { mutableUserID } } iOS J04Ͱ΋/VMMBCMFͱͯ͠,..ଆʹ౉ͤΔΑ͏ʹͳΔ
  48. Ξμϓλ͢Δ΋ͷΛࣗಈੜ੒ #ca_ fl utter_kmm ΞμϓλΛࣗಈੜ੒͢ΔػߏΛ,PUMJO4ZNCPM1SPDFTTJOHΛ༻͍࣮ͯ૷͠ɺ಺੡ϥΠϒϥϦͰఏڙ

  49. #ca_ fl utter_kmm • AndroidͰ͸໰୊ͳ͘ద߹͕Ͱ͖Δ • interfaceʹgenerics͕࢖ΘΕ͍ͯΔͱiOSͰ͸ܕύϥϝʔλ͕
 ফࣦ͢Δ • genericsͷܕύϥϝʔλͷNullable͸iOSͰ͸ফࣦ͢Δ

    • ΞμϓλΛࣗಈੜ੒͠ɺ্هͷ՝୊Λղܾ طଘͷRepository౳ΛKMMͷRepositoryʹద߹͢Δ
  50. ܨ͗ࠐΈ࣌ʹ՝୊ʹͳͬͨ͜ͱ #ca_ fl utter_kmm interface SomeUseCase { fun display(): LoadableResult<SomeUseCaseModel>

    } sealed class LoadableResult<out R> { object Loading : LoadableResult<Nothing>() data class Loaded<R>(val result: R) : LoadableResult<R>() } KMM
  51. Android͔Βݺͼग़͢৔߹ #ca_ fl utter_kmm val usecase: SomeUseCase = ... when

    (val loadableResult = usecase.display()) { LoadableResult.Loading -> { // handle loading } is LoadableResult.Loaded<SomeUseCaseModel> -> { loadableResult.result // handle loaded } } Android ໢ཏతʹ෼ذ͕Ͱ͖ɺͦΕͧΕͷॲཧ͕Ͱ͖Δ
  52. 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ΛΩϟετͯ͠൑ఆ͢Δ͔͠ͳ͍
  53. iOSͰ໢ཏతʹ෼ذͰ͖ΔΑ͏ʹ͢Δ #ca_ fl utter_kmm sealed class LoadableResult<out R> { object

    Loading : LoadableResult<Nothing>() data class Loaded<R>(val result: R) : LoadableResult<R>() fun <T> fold( onLoading: (LoadableResult.Loading) -> T, onLoaded: (LoadableResult.Loaded<out R>) -> 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
  54. #ca_ fl utter_kmm loadableResult.fold( onLoading: <#(LoadableResultLoading) -> Any?#>, onLoaded: <#(LoadableResultLoaded<SomeUseCaseModel>)

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

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

    init(_ value: T) { self.value = value } } let value: SomeUseCaseModel? = LoadableResultFold( value: loadableResult, onLoading: { _ in Box<SomeUseCaseModel?>(nil) }, onLoaded: { Box<SomeUseCaseModel?>($0.result) } ).result.value iOS iOSͰ໢ཏతʹ෼ذͰ͖ΔΑ͏ʹ͢Δ ܕύϥϝʔλ͸"OZ0CKFDUͰͳ͚Ε͹͍͚ͳ͍ͨΊɺ#PYܕ౳ͰϥοϓΛͯ͠ 
 ,..Ͱఏڙ͞Ε͍ͯΔܕΛऔΓग़ͤΔΑ͏ʹ͢Δ
  57. foldΛࣗಈੜ੒ #ca_ fl utter_kmm GPMEΛࣗಈੜ੒͢ΔػߏΛ,PUMJO4ZNCPM1SPDFTTJOHΛ༻͍࣮ͯ૷͠ɺ಺੡ϥΠϒϥϦͰఏڙ

  58. #ca_ fl utter_kmm • iOSͰ͸sealed classΛ໢ཏతʹ෼ذͰ͖ͳ͍ • enumͰ΋ಉ༷ͷ͜ͱ͕ى͖Δ • Objective-CͷLightweight

    GenericsͰදݱͰ͖ΔൣғͰରԠ • foldΛࣗಈੜ੒͢Δ͜ͱͰɺ্هͷ໰୊Λղܾ ໢ཏతʹ෼ذ͢Δ
  59. νʔϜ಺ͷiOS։ൃऀ޲͚ͷυΩϡϝϯτ #ca_ fl utter_kmm

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

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

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

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

  64. ࠓޙͷల๬ #ca_ fl utter_kmm • MPEͷϛογϣϯ͸։ൃޮ཰Խ • ։ൃޮ཰͕ஶ͘͠མͪΔ͜ͱ͕͋Ε͹ɺKMM͔Βͷఫୀ΋ࢹ໺ʹೖΕ͍ͯΔ • ج൫͕੔͍ͬͯͳ͍ͷͰɺ·ͩKMMΛ׆༻ͨ͠։ൃ


    ޮ཰Λ࠷େԽͰ͖͍ͯͳ͍ • ࠓظͰج൫Λ੔͑ɺདྷظʹ൑அͰ͖Δঢ়ଶΛ໨ࢦ͢
  65. One more thing… #ca_ fl utter_kmm

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

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