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

Flutter 2021 の振り返りと今後のアプリ開発に向けて / Looking back on Flutter 2021 and for future app development.

Flutter 2021 の振り返りと今後のアプリ開発に向けて / Looking back on Flutter 2021 and for future app development.

6dd0483f1353a4a359e92633cfd65c64?s=128

Daichi Furiya (Wasabeef)

December 11, 2021
Tweet

More Decks by Daichi Furiya (Wasabeef)

Other Decks in Programming

Transcript

  1. Flutter 2021 ͷৼΓฦΓͱ 
 ࠓޙͷΞϓϦ։ൃʹ޲͚ͯ Daichi Furiya / Wasabeef CyberAgent,

    Inc. Tokyo, Japan
  2. Flutter 2021 ͷৼΓฦΓͱࠓޙͷΞϓϦ։ൃʹ޲͚ͯ 1. ΫϩεϓϥοτϑΥʔϜͷݱঢ়ͱ՝୊ 2. 2022೥΋ Flutter Λબ୒͢Δ͔Ͳ͏͔ 3.

    Flutter ͱ Dart ͷΞοϓσʔτ 4. Flutter ΞϓϦ։ൃͷࠓޙʹ޲͚ͯ 4.1. ΞϓϦͷΞʔΩςΫνϟ 4.2. React ͔Βֶͼ͍ͨ͜ͱ
  3. ΫϩεϓϥοτϑΥʔϜ ͷݱঢ়ͱ՝୊

  4. ΫϩεϓϥοτϑΥʔϜͷݱঢ়ͱ՝୊ 1. ΫϩεϓϥοτϑΥʔϜͰ։ൃ͢Δલʹ஌͓ͬͯ͘΂͖͜ͱ 1. ϝϦοτɾσϝϦοτ 2. Kotlin Multiplatform 3. Compose

    Multiplatform 2. Flutter ͷ࠾༻ࣄྫ
  5. ΫϩεϓϥοτϑΥʔϜͰ։ൃ͢Δલʹ஌͓ͬͯ͘΂͖͜ͱ

  6. ΫϩεϓϥοτϑΥʔϜͰ։ൃ͢Δલʹ஌͓ͬͯ͘΂͖͜ͱ • ΫϩεϓϥοτϑΥʔϜͰ։ൃ͢ΔҙຯΛߟ͑Δ 
 → ԿΛڞ௨Խ͍͔ͨ͠ʁ • ʮͱΓ͋͑ͣ Flutter ͕ྲྀߦͬͯΔΒ͍͔͠Β

    Flutter Ͱ΍ͬͱ͚ ͹͍͍ʯͰ͸ͳ͍ • ͜Ε·Ͱొ৔͖ͯͨ͠਺ଟͷΫϩεϓϥοτϑΥʔϜϑϨʔϜ ϫʔΫ͕ਁಁ͠ͳ͔ͬͨ͜ͱ اۀͱͯ͠औΓ૊Ή৔߹
  7. ΫϩεϓϥοτϑΥʔϜͰ։ൃ͢ΔҙຯΛߟ͑Δ QɿԿΛڞ௨Խ͍͔ͨ͠ʁ A1ɿϩδοΫ͚ͩڞ௨Խ͢Δ A2ɿUI ΋ϩδοΫ΋ڞ௨Խ͢Δ A3ɿࠓ͸ϩδοΫ͚ͩͰকདྷతʹ͸ ɹɹ UI ΋ڞ௨Խ͢Δ UI

    ϩδοΫ List Button Domain Label Nav Media Notification Sensors Business Logic Networking Database etc.. etc.. Log Utils
  8. ΫϩεϓϥοτϑΥʔϜͰ։ൃ͢ΔҙຯΛߟ͑Δ QɿԿΛڞ௨Խ͍͔ͨ͠ʁ A1ɿϩδοΫ͚ͩڞ௨Խ͢Δ A2ɿUI ΋ϩδοΫ΋ڞ௨Խ͢Δ A3ɿࠓ͸ϩδοΫ͚ͩͰকདྷతʹ͸ ɹɹ UI ΋ڞ௨Խ͢Δ UI

    ϩδοΫ UI + ϩδοΫ
  9. ϝϦοτɾσϝϦοτ

  10. ϝϦοτ • ΤϯδχΞͷϦιʔεઅ໿ • ਓ਺ɾ։ൃظؒ୹ॖ • ։ൃίϛϡχςΟͷٸ଎తͳ ֦େʢࠃ಺֎ɺFlutterKaigi ͳͲʣ •

    iOS/Android Ͱڞ௨ͷ UI 
 ʢྑ͘΋ʣ σϝϦοτ • ΞϓϦಈ࡞ͷ҆ఆੑ 
 ʢωΠςΟϒʹ͸ྼΔʣ • কདྷੑɺઌߦ͖ෆ҆ 
 ʢͲͷϑϨʔϜϫʔΫΛ࠾༻͢Δ͔ʣ • iOS/Android Ͱڞ௨ͷ UI 
 ʢѱ͘΋ʣ • iOS/Android ͷ৽ػೳ΁ͷ௥ ैͷ஗ΕΔ
  11. ΤϯδχΞͷϦιʔεઅ໿ αʔόΤϯδχΞ iOS ΤϯδχΞ Web ΤϯδχΞ Android ΤϯδχΞ Ұൠతͳ Swift/Kotlin

    ΞϓϦͷΞαΠϯελΠϧ
  12. ΤϯδχΞͷϦιʔεઅ໿ ΫϩεϓϥοτϑΥʔϜͰͷΞαΠϯελΠϧ ΞϓϦΤϯδχΞ ͱΓ͋͑ͣ1ਓҎ্͍Ε͹ iOS/ Android ΞϓϦ྆ํ։ൃՄೳ αʔόΤϯδχΞ Web ΤϯδχΞ

    ༨৒
  13. ΤϯδχΞͷϦιʔεઅ໿ αʔόΤϯδχΞ iOS ΤϯδχΞ Web ΤϯδχΞ Android ΤϯδχΞ Ұൠతͳ Swift/Kotlin

    ΞϓϦͷΞαΠϯελΠϧ ϨϏϡʔ͞Εͳ͍ෆ҆
  14. ΤϯδχΞͷϦιʔεઅ໿ ΫϩεϓϥοτϑΥʔϜͰͷΞαΠϯελΠϧ αʔόΤϯδχΞ ΞϓϦΤϯδχΞ Web ΤϯδχΞ ͱΓ͋͑ͣ1ਓҎ্͍Ε͹ iOS/ Android ΞϓϦ྆ํ։ൃՄೳ

    ίʔυϨϏϡʔͰ͖ͯ݁Ռͱͯ͠ ඼࣭޲্΋ɻ
  15. iOS/Android Ͱڞ௨ͷ UIʢѱ͘΋ʣ Flutter ͸ϚςϦΞϧσβΠϯΛ࠾༻͍ͯ͠ΔͷͰɺѱ͘ݴ͏ ͱ iOS ͬΆ͍σβΠϯ͕ଛͳΘΕ͍ͯͨΓ͢Δ͜ͱ͕͋Γ· ͢ɻͨͩɺͦΕ͸։ൃ଎౓ͷ޲্ͷͨΊʹσβΠϯγεςϜ ͸

    Flutterʢڞ௨ʣͱͯ͠ߟ͑ͨํ͍͍ͱͯ͠ࢥ͍ͬͯ·͢ɻ
  16. iOS/Android Ͱڞ௨ͷ UIʢѱ͘΋ʣ Cupertino widgets ΋͋Δఔ౓ଘࡏ͢Δ͕׬ᘳͰ͸ͳ͍ͷͰɺiOS Β͍͠σβΠϯʹ׬શʹ ౿ऻ͍ͨ͠৔߹͸ΫϩεϓϥοτϑΥʔϜʹ͸͠ͳ͍ͱ͍͏ͷબ୒ࢶ΋ࢹ໺ʹ͍Ε͍ͨ

  17. কདྷੑɺઌߦ͖ෆ҆ ։ൃݩͷاۀ͕͍͔ʹେ اۀͩΖ͏ͱΤϯδχΞ ίϛϡχςΟʹड͚͕ྑ ͘ͳ͍ͱྲྀߦΒͳ͍

  18. iOS/Android ͷ৽ػೳ΁ͷ௥ैͷ஗Εʁ ྫ͑͹ iOS 15ɺAndroid 12 ͷରԠ͕க໋తʹ஗Ε͍ͯͯ։ൃͰ͖ͳ͍ͱ͍͏ײ֮͸ͳ ͍͕ɺ֤ OS ͷ৽

    API ͷΠϯλʔϑΣʔεެ։͕ޙ௥͍ͰདྷΔͷ͸ࣄ࣮ͱͳΓ·͢
  19. Kotlin Multiplatform

  20. Kotlin Multiplatform • JetBrains ʹΑͬͯ։ൃ • UI ͷڞ௨Խ͸ͤͣɺϏδωεϩ δοΫͷڞ௨ԽʹಛԽ͍ͯ͠Δ ʢೝূɺϩάͳͲͷڞ௨Խʣ

    • Kotlin Ͱ Backends for Frontends Kotlin/LLVM Kotlin/JVM Kotlin/JVM Kotlin/JS Common code
  21. Compose Multiplatform

  22. Compose Multiplatform • 1.0.0 (Dec 2021) • Jetpack Compose ϕʔεͰ

    Jetbrains ʹΑΔ։ൃ • ݩʑ͸ Compose for Desktop ͩͬͨ΋ͷ • ݱࡏ͸ओʹ Desktop / Web ΞϓϦ޲͚ʢAndroid Ͱ΋ಈ͘ʣ • ݱஈ֊Ͱ͸ iOS ΁ͷެࣜαϙʔτ͸ൃද͞Ε͍ͯͳ͍ • άϥϑΟοΫΤϯδϯ͸ Skia Λར༻͍ͯ͠Δ
  23. Skia • άϥϑΟοΫϥΠϒϥϦ • Android, Chrome, Firefox, Blink, Flutter Ͱ࠾༻͞Ε͍ͯΔ

    • Skia ͸ Vulkan ΛόοΫΤϯυΤϯδϯͱͯ͠มߋՄೳ • Android 9 Ҏ߱ɺσϑΥϧτͷϨϯμϥʔ͸ Skia ʹͳ͍ͬͯΔ ʢ8 ͱ 9 ͰUI͕มΘͬͨͷ͸ͦͷͨΊʣɻFlutter ʹ͢ΔͱϨΠ Ϡʔ͕૿͑Δ΋ͷͷϨϯμϥʔ͸ಉ͡
  24. Skia • ΋ͪΖΜ iOS Ͱ΋ Windows Ͱ΋ಈ࡞͢Δ ରԠϓϥοτϑΥʔϜ • Windows

    7, 8, 8.1, 1 0 • macOS 10.10.5 or late r • iOS 8 or late r • Android 4.1 (JellyBean) or late r • Ubuntu 14.04+, Debian 8+, openSUSE 13.3+, or Fedora Linux 24+
  25. Flutter ͷ࠾༻ࣄྫ

  26. Flutter ͷ࠾༻ࣄྫ https://medium.com/flutter/announcing-flutter-2-8-31d2cb7e19f5 5݄ 200,000 ΞϓϦ ↓ 12݄ 375,000 ΞϓϦ

    ͜͜ 6 ϲ݄Ͱ 1.87 ഒ App Store
  27. 2022೥΋ Flutter Λબ୒ ͢Δ͔Ͳ͏͔

  28. 2022೥΋ Flutter Λબ୒͢Δ͔Ͳ͏͔ 1. ΫϩεϓϥοτϑΥʔϜ͔ʁ֤ϓϥοτϑΥʔϜ͔ʁ 1.1. ΞϓϦͷػೳཁ݅͸ʁ 1.2. ΤϯδχΞͷಘҙྖҬɺͦͷਓ਺ɺظؒ͸ʁ 2.

    React Native ͸ʁ.NET MAUI ͸ʁ 3. Compose Multiplatform ͷ୆಄͸ʁ
  29. ΫϩεϓϥοτϑΥʔϜ͔ʁ֤ϓϥοτϑΥʔϜʢiOS / Androidʣ͔ʁ ɹΫϩεϓϥοτϑΥʔϜɹ ɹ֤ϓϥοτϑΥʔϜʢiOS / Androidʣ • UI ΍ϏδωεϩδοΫ͕

    iOS / Android Ͱҧ͏ • ҆ఆͯ͠ΫΦϦςΟ͕ߴ͍΋ͷ࡞ Γ͍ͨ • iOS / Android ͷܦݧऀ͕͍Δ • εέδϡʔϧʹ༨༟͕͋Δ ྫ ྫ • UI ΍ϏδωεϩδοΫ͕ iOS / Android Ͱಉ͡ • ٕज़౤ࢿతͳνϟϨϯδΛ͍ͨ͠ • iOS / Android ͷܦݧऀ͕গͳ͍ 
 ʢΤϯδχΞͷ਺͕গͳ͍ʣ • εέδϡʔϧʹ༨༟͕ͳ͍
  30. ΞϓϦͷػೳཁ݅͸ʁ

  31. ΞϓϦͷػೳཁ݅͸ʁ • iOS ͱ Android Ͱ UI ͷମݧ͕શ͘ҧ͏ʁ 
 →

    Flutter ͸ཱͪҐஔ͕ UI ϑϨʔϜϫʔΫͳͷͰཁ͕݅ͦ΋ͦ΋͍͋ͬͯͳ͍͔΋ • ಈըͳͲͷίϯςϯπΛදࣔ͢Δͷʹ DRM ͕ඞཁʁ 
 → Flutter ͚ͩͰ࣮૷͢Δͷ͸ݱஈ֊Ͱ͸ FairPlay ରԠͨ͠ϥΠϒϥϦ͕ͳ͍ • οοΰϦοοΰϦͷΞχϝʔγϣϯ͕͋Δʁ 
 → ύϑΥʔϚϯε͕ωΠςΟϒΑΓྼΔͷͰཁݕূ
  32. ΤϯδχΞͷಘҙྖҬɺͦͷਓ਺ɺظؒ͸ʁ

  33. ΤϯδχΞͷಘҙྖҬɺͦͷਓ਺ɺظؒ͸ʁ αʔόΤϯδχΞ Web ΤϯδχΞ ਓΛ૿΍ͤͣʹͲ͏ʹ͔͠ͳ͍ͱ͍͚ͳ͍৔߹

  34. ΤϯδχΞͷಘҙྖҬɺͦͷਓ਺ɺظؒ͸ʁ αʔόΤϯδχΞ ΞϓϦΤϯδχΞ Web ΤϯδχΞ iOS / Android ஌͕ࣝ΄ͱΜͲͳ͍৔߹ʹ ผʑʹ࡞ͬͯ྆ํΛಉ࣌ʹϦϦʔε͢Δ

    ͷ͸ݱ࣮తʹ͸ෆՄೳ
  35. ΤϯδχΞͷಘҙྖҬɺͦͷਓ਺ɺظؒ͸ʁ αʔόΤϯδχΞ ΞϓϦΤϯδχΞ Web ΤϯδχΞ ͜ͷύλʔϯͰ͸࣮֬ʹΫϩεϓϥοτ ϑΥʔϜ͕༗ޮʹͳͬͯ͘Δ ·ͨɺFlutter ͕ෛ࠴ʹͳΔՄೳੑ΋͜Ε ·ͰͷΫϩεϓϥοτϑΥʔϜϑϨʔϜ

    ϫʔΫʹൺ΂Δͱ௿͍ʢͱࢥ͏ʣ
  36. React Native ͸ʁ.NET MAUI ͸ʁ

  37. React Native ͸ʁ • Web ํ໘ʹڧ͍ΤϯδχΞ͕͍Δ৔߹ͳͲͷબ୒ࢶ 
 → νʔϜͷಘҙྖҬ΍ٕज़ࢿ࢈ʹΑܾͬͯఆ •

    ϝϧΧϦ US ͕ React Native Ͱॻ͖௚ͨ͠Β͍͠ 
 → https://link.medium.com/SNFEPzc1Rlb • Facebook ΍ Coinbase ΍ Discord ΍ Tesla ͱ͍ͬͨ༗໊ͳاۀ΋࠾༻ 
 → https://reactnative.dev/showcase • npm ʹ͋Δࢿ࢈Λࢧ͑Δͷ͸ڧΈ 
 ʢ༨ஊɿϒϩοΫνΣʔϯؔ࿈ٕज़͸ React Native ޲͚ͷ SDK ʹ͔͠ରԠ͍ͯ͠ͳ͍৔߹͕ଟ͍ʣ
  38. .NET MAUI ʢچ Xamarin.Formsʣ͸ʁ • C# ํ໘ʹڧ͍ΤϯδχΞ͕͍Δ৔߹ͳͲͷબ୒ࢶ 
 → νʔϜͷಘҙྖҬ΍ٕज़ࢿ࢈ʹΑܾͬͯఆ

    • ৽ܕίϩφ΢Πϧε઀৮֬ೝΞϓϦ͸ Xamarin Λ࠾༻ • .NET MAUI ʹͳΔͱ XML ΛࣙΊએݴత UI Ͱॻ͚Δ • ࣄྫ͕ Flutter ΍ React Native ʹൺ΂Δͱগͳ͍
  39. Compose Multiplatform ͷ୆಄͸ʁ

  40. Compose Multiplatform ͷ୆಄͸ʁ • ୆಄͢Δ͔΋͠Εͳ͍͕ɺͦΕ͕ 2022 ೥ʹϞόΠϧ޲͚ ʹ Production Ready

    ʹͳΔՄೳੑ͸௿͍ 
 → ݱஈ֊Ͱ iOS ͷਖ਼ࣜαϙʔτ͕ೖ͍ͬͯͳ͍ • ͦͷ൑அ͕Ͱ͖Δͷ͕΋͏গ͠ઌʹͳΓͦ͏
  41. • ৽نϓϩδΣΫτ • গਓ਺ʢ1ਓʙʣ • গਓ਺Ͱ΋྆ϓϥοτϑΥʔ ϜͰϒϥϯσΟϯάͷҰ؏ੑ Λҡ͍࣋ͨ͠ • ͱʹ͔͘ૣ͘ϦϦʔε͍ͨ͠

    • ΑΓνϟϨϯδ͍ͨ͠ ྫ ɹFlutterɹ Flutter ͔ʁ Kotlin MPP ͔ʁ+ Compose Multiplatform ͔ʁ ɹKotlin MPPɹ • ৽ن / طଘϓϩδΣΫτ • େਓ਺ʢ10ਓʙʣ • iOS/AndroidΞϓϦ։ൃͷਫ਼ ௨͍ͯ͠Δ • ϦεΫΛ཈͍֤͑ͨϓϥοτ ϑΥʔϜͰ෼͚ͯσβΠϯΛ ߆Γ͍ͨ ྫ ɹ+ Compose Multiplatformɹ • ݕূʢ৽نʣϓϩδΣΫτ • গਓ਺Ͱ΋྆ϓϥοτ ϑΥʔϜͰϒϥϯσΟϯά ͷҰ؏ੑΛҡ͍࣋ͨ͠ • ͱʹ͔͘ૣ͘ϦϦʔεͨ͠ ͍ • কདྷ΁ͷٕज़౤ࢿΛ͍ͨ͠
  42. • UI ΋ϏδωεϩδοΫ΋ڞ ௨ԽͰ͖Δ • ࣄྫ͕ଟ͍ • Google Λ৴͍ͯ͡Δ ྫ

    ɹFlutterɹ Kotlin MPP + Compose ɹɹɹɹɹɹ Multiplatform • Web / React ϝϯόʔ͕ଟ͍ 
 ʢWeb ͷࢿ࢈Λ࢖͍͍ͨʣ • UI ΋ϏδωεϩδοΫ΋ڞ ௨ԽͰ͖Δ • ࣄྫ͕ଟ͍ʢ͕ࠃ಺ͷ੎͍͸ྼΔʣ • Facebook Λ৴͍ͯ͡Δ • Android / Kotlin ϝϯόʔ͕ ଟ͍ʢKotlin ͷࢿ࢈Λ࢖͍͍ͨʣ • ॳظஈ֊͸ϏδωεϩδοΫ ͚ͩڞ௨Խ͠ Compose Multiplatform ͕҆ఆͨ͠λ ΠϛϯάͰ UI Λॻ͖௚͢ύ λʔϯ • Jetbrains Λ৴͍ͯ͡Δ ྫ React Native ྫ 2022೥΋ Flutter Λબ୒͢Δ͔Ͳ͏͔
  43. Flutter ͱ Dart ͷ Ξοϓσʔτ

  44. Flutter 2.8

  45. Flutter 2.8 1. ύϑΥʔϚϯε޲্
 ʢGoogle Pay ͰىಈςετͰ 10 ʙ 50%

    ͷ޲্ʣ 2. Android systrace ʹ Flutter ͷύϑΥʔϚϯετϨʔεΛૹ৴͢ΔΑ͏ʹมߋ 3. Flutter DevTools ʹ Enhance Tracing ௥ՃʢUI δϟϯΫ਍அͳͲʹ༗ޮʣ 4. FirebaseʢFlutterFireʣPlugin ͷ҆ఆ൛ϦϦʔε 4.1. Firebase UI ʢೝূ΢ΟδΣοτʣͷϦϦʔε 5. Desktop ൛ͷߋ৽ʢ׽ࣈ IME αϙʔτͳͲʣ 6. Dev channel ͷഇࢭʢࠓޙ͸ master, beta, master Ͱӡ༻ʣ https://link.medium.com/a7Md15TNPlb
  46. Firebase UI https://link.medium.com/a7Md15TNPlb • ೝূը໘ͷ΢ΟδΣοτ • Firebase Auth Λར༻ •

    Email, Google, Meta, Twitter, Apple ʹରԠ
  47. Dart 2.15

  48. None
  49. Dart 2.15 1. Isolate class ͷػೳ޲্ 2. Constructor tear-off s

    3. enum ʹ API ௥Ճ 4. ϥΠϒϥϦ։ൃ޲͚Ͱ pub ʹػೳ௥Ճ https://link.medium.com/kZTQCmukPlb
  50. Isolate ͷػೳ޲্ લఏͱͯ͠ɿDart Ͱ 16ms Λ௒͑ͯϑϨʔϜϨʔτΛམͱ͢Α͏ͳॲཧΛ͢Δ ৔߹ʹ͸ Isolate Λར༻ͯ͠ Worker

    Isolate Ͱ࣮ߦ͢Δ͜ͱΛਪ঑͞Ε͍ͯΔ ʢωοτϫʔΫϨεϙϯεΛͨͩ଴͍ͬͯΔ͚ͩͷΑ͏ͳॲཧͷ৔߹ͦͷݶΓ Ͱ͸ͳ͍ʣ Dart 2.15Ͱ͸ Worker Isolate ͔ΒϝϞϦΛίϐʔͤͣʹ Isolate.exit() Ͱ݁ՌΛ ฦ͢͜ͱ͕Ͱ͖Δɻ Flutter ͷ compute Λطʹར༻͍ͯ͠Δ৔߹͸ Flutter 2.8 ͷΞοϓάϨʔυ͢Δ͜ͱͰࣗಈతʹύϑΥʔϚϯε͕޲্͢Δ https://link.medium.com/kZTQCmukPlb
  51. https://link.medium.com/kZTQCmukPlb // Isolate.spawn final p = ReceivePort(); await Isolate.spawn(_read, p.sendPort);

    await p.first; // Isolate.exit Future _read(SendPort p) async { final fileData = await File(filename).readAsString(); final jsonData = jsonDecode(fileData); Isolate.exit(p, jsonData); } final fileData = File(fileName); // compute compute(_read, jsonData); List<SearchResult> _read(File filename) { final fileData = await File(filename).readAsString(); final jsonData = jsonDecode(fileData); } Isolate ͷػೳ޲্ Flutter ͷ computeʢத਎͸ Dart ͷ Isolateʣ Dart ͷ Isolate
  52. Isolate ͷػೳ޲্ https://link.medium.com/kZTQCmukPlb void main() async { final jsonData =

    await _parseInBackground(); print('number of JSON keys = ${jsonData.length}'); } // Isolate.spawn Future<Map<String, dynamic>> _parseInBackground() async { final p = ReceivePort(); await Isolate.spawn(_readAndParseJson, p.sendPort); return await p.first; } // Isolate.exit Future _readAndParseJson(SendPort p) async { final fileData = await File(filename).readAsString(); final jsonData = jsonDecode(fileData); Isolate.exit(p, jsonData); }
  53. Constructor tear-offs https://link.medium.com/kZTQCmukPlb class Hoge { Hoge() { print(‘Called Hoge()’);

    } } void main() { const hoge = Hoge.new; hoge(); } // Lambda names.forEach((name) { print(name); }); // Tear-off names.forEach(print);
  54. Constructor tear-offs https://link.medium.com/kZTQCmukPlb class FruitWidget extends StatelessWidget { @override Widget

    build(BuildContext context) { return Column( children: ['Apple', 'Orange'].map((value) => Text(value)).toList()); } } class FruitWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Column( children: ['Apple', 'Orange'].map(Text.new).toList()); } } Ҏલ͸ .map ʹϥϜμΛ౉͍͕ͯͨ͠ ίϯετϥΫλͰ΋ tear-off Ͱ͖ΔΑ͏ʹͳͬͨ
  55. enum ʹ API ௥Ճ https://link.medium.com/kZTQCmukPlb enum MyEnum { one, two,

    three } void main() { // .name Ͱྻڍ໊ͷऔಘ -> "one" print(MyEnum.one.name); } / / .byName Ͱྻڍ஋ͷݕࡧ print(MyEnum.values.byName('two') == MyEnum.two); / / .asNameMap Ͱ໊ͱ஋ͷ Map Λऔಘ final map = MyEnum.values.asNameMap(); print(map['three'] == MyEnum.three);
  56. ϥΠϒϥϦ։ൃ޲͚Ͱ pub ʹػೳ௥Ճ https://link.medium.com/kZTQCmukPlb 1. ϦϦʔε࣌ʹҙਤ͠ͳ͍ Secrets ؚ͕·Εͯͳ͍͔νΣοΫ 2. ޡͬͯϦϦʔεͨ͠΋ͷΛ

    pub.dev ͔ΒఫճͰ͖ΔΑ͏ʹ
  57. ϦϦʔε࣌ʹҙਤ͠ͳ͍ Secrets ؚ͕·Εͯͳ͍͔νΣοΫ https://link.medium.com/kZTQCmukPlb Publishing my_package 1.0.0 to https://pub.dartlang.org: Package

    validation found the following errors: * line 1, column 1 of lib/key.pem: Potential leak of Private Key detected. ╷ 1 │ ┌ - - -BEGIN PRIVATE KEY - - - 2 │ │ H0M6xpM2q+53wmsN/eYLdgtjgBd3DBmHtPilCkiFICXyaA8z9LkJ 3 │ └ - - -END PRIVATE KEY - - - ╵ * line 2, column 23 of lib/my_package.dart: Potential leak of Google OAuth Refresh Token detected. ╷ 2 │ fi nal refreshToken = "1//042ys8uoFwZrkCgYIARAAGAQSNwF-L9IrXmFYE-sfKefSpoCnyqEcsHX97Y90KY- p8TPYPPnY2IPgRXdy0QeVw7URuF5u9oUeIF0"; false_secrets: - /lib/src/hardcoded_api_key.dart - /test/localhost_certi fi cates/*.pem ྫɿdart pub publish ࣌ͷνΣοΫ ςετσʔλͱͯ͠μϛʔΛஔ͍͍ͯΔ৔߹ͳͲ͸ pubspec.yaml ʹҎԼΛ௥Ճ
  58. pub.dev ͰϦϦʔεΛఫճ https://link.medium.com/kZTQCmukPlb

  59. DartPad

  60. DartPad • React CodeSandbox ͷΑ͏ʹ Web ্Ͱ Dart ΍ Flutter

    ͷಈ࡞؀ڥΛ؆୯ʹ༻ҙͰ͖ΔʢCodeSandbox ΄ͲߴػೳͰ͸ͳ͍ʣ • Ұ෦ͷطʹ༻ҙ͞Ε͍ͯΔ༗໊ͳύοέʔδ΋ར༻͢Δ ͜ͱ͕Ͱ͖ΔʢFirebaseɺhttpɺriverpodɺFlutter Hooks ͳͲʣ
  61. DartPad

  62. Flutter ΞϓϦ։ൃͷࠓޙ ʹ޲͚ͯʢݸਓࢹ఺ʣ

  63. Flutter ΞϓϦ։ൃͷࠓޙʹ޲͚ͯʢݸਓࢹ఺ʣ 1. ΞϓϦͷΞʔΩςΫνϟ 2. React ͔Βֶͼ͍ͨ͜ͱ 2.1. React Hooks

    2.2. React ͷΞʔΩςΫνϟ
  64. ΞϓϦͷΞʔΩςΫνϟ

  65. ΞϓϦͷΞʔΩςΫνϟ MVVM Bloc Redux ELM/MVU

  66. Android ΤϯδχΞʹ͸ೃ છΈͷਂ͍Ͱ͋Ζ͏ MVVM + Repository Ͱ΋ Flutter ͰͦΕ͕࠷దղͱ ͸ݶΒͳ͍

    View Repository ViewModel Local Source Remote Data Source MVVM Repository MVVM + Repository
  67. ͜ͷϘλϯͷঢ়ଶ؅ཧ͸Ͳ͏͢Δʁ ςΩετϑΟʔϧυʹԿ͔ ͕ೖྗ͞ΕΔ·ͰϘλϯ͸ ඇ׆ੑʹ͍ͨ͠

  68. ViewModel Λ࡞ͬͯ؅ཧ͢Δʁ ίϯϙʔωϯτͷ୯ҐΛࡉ͔͘͢Ε ͹ͦͷ෼͚ͩରʹͳΔViewModel ΋ ૿͑Δʁ ͜ͷϘλϯͷঢ়ଶ؅ཧ͸Ͳ͏͢Δʁ class ChatViewModel {

    String text = ''; bool enabled = false; } class ChatWidget extends HookConsumerWidget { const ChatWidget({Key? key}) : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { final viewModel = ref.watch(chatViewModelProvider); return Column( children: [ TextFormField( onChanged: (value) => viewModel.enabled = value.isNotEmpty, ), ElevatedButton( onPressed: viewModel.enabled ? () {/** Submit **/} : null, child: Text('Submit'), ), ], ); } }
  69. ίϯϙʔωϯτ਺ ≒ ViewModel਺ʁ • XML ࣌୅ͷ Android ͩͱϨΠΞ΢τͷ୯Ґ͕େ͖͔ͬͨ • Flutter

    Ͱ͸Ͱ͖Δ͚ͩίϯϙʔωϯτΛখ͘͞׬݁ʹ࡞ Γ͍ͨ • ϑΝΠϧ਺૿͑͗͢ΔͷͰίϯϙʔωϯτΛࡉ͔͘͢͠ ͗ͳ͍Α͏ʹ͢Δ͔ʁʢͦͷԘക͕೉͍͠ʣ
  70. class DetailViewModel { DetailData data; bool isLoading; String chatText =

    ''; bool submitButtonEnabled = false; Future<> fetchData(){ } Future<> postData() { } } class ChatWidget extends HookConsumerWidget { const ChatWidget({Key? key}) : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { final viewModel = ref.watch(chatViewModelProvider); return ... // TextField, Button } } ChatWidget ͸ςΩετϑΟʔϧυͱϘλϯ͔͠ͳ͍ͷʹɺ ຊདྷ͢Δඞཁͷͳ͍΋ͷ·Ͱ·Ͱ஌Δ͜ͱ͕Ͱ͖ͯ͠·͏ DetailViewModel ͸ ChatWidget Ͱ͸࢖ Θͳ͍σʔλऔಘ΍ϩʔσΟϯάঢ়ଶͳ Ͳ΋΋͍ͬͯΔ ViewModel ͷൣғΛগ͠େ͖ͯ͘͠ΈΔʁ
  71. ؆୯ͳঢ়ଶ͸ίϯϙʔωϯτଆͰ͍࣋ͪͨ ʴ ؆୯ʹॻ͖͍ͨ class CountPage extends StatefulWidget { @override State

    createState() => _CountState(); } class _CountState extends State<CountPage> { int count = 0; @override void initState() { /** ॳظԽ **/ } @override void dispose() { /** ഁغ **/ } void setCount(int value) => setState(() => count = value); @override Widget build(BuildContext context) { return TextButton( child: Text(“Count: $count"), onPressed: () => setCount(count + 1), ); } } Flutter Hooks Ͱॻ͘ class CountPage extends HookWidget { @override Widget build(BuildContext context) { final count = useState(0); return TextButton( child: Text("Count: ${count.value}"), onPressed: () => count.value++, ); } }
  72. Flutter Hooks

  73. LaunchedEffect(id) { // ID ͕มߋ͞ΕΔͨͼ } SideEffect { // ຖճ

    } LaunchedEffect(Unit) { // ࠷ॳͷҰճ } 73 useEffect useEffect(() => { // ID ͕มߋ͞ΕΔͨͼ }, [id]); useEffect(() => { // ຖճ }); useEffect(() => { // ࠷ॳͷҰճ }, const []); Flutter Hooks Jetpack Compose
  74. ViewModel ͔ΒϘλϯͳͲͷঢ়ଶ؅ཧΛࠩ͠Ҿ͍͍ͯ͘ͱ ViewModel ͡Όͳ͍͍͔ͯ͘΋͠Εͳ͍ ↓ MVVM ͡Όͳ͍͔΋… 
 ʢ࣮ࡍʹ͸ଞʹ΋৭ʑΉͣᙱ͍ͱ͜Ζ͕͋Δʣ ΞʔΩςΫνϟΛߟ͑௚͢

  75. ࠷ۙ͸ϨΠϠʔଟ͗͢Δ΋ͬͱݮΒ͍͖͍ͯͨ͠ ↓ Flutter ΞϓϦք۾ͷઃܭ͕ఆ·ͬͯͳ͍͔ΒReact ͔ΒֶͿ͔ ΞʔΩςΫνϟΛߟ͑௚͢

  76. React ͔Βֶͼ͍ͨ͜ͱ

  77. React ͔Βֶͼ͍ͨ͜ͱʢݸਓࢹ఺ʣ 1. React App ͷΞʔΩςΫνϟ 2. React Hooks ͷ࢖͍Ͳ͜Ζ

    3. ίϯϙʔωϯτ୯ҐͰͷςετ
  78. • Redux • Recoil • + React Query / SWR

    React App ͷΞʔΩςΫνϟ
  79. • React Hook ࢖ͬͯσʔλऔಘ͢Δ ͨΊͷϥΠϒϥϦ • ίϯϙʔωϯτଆͰ API ͷωοτ ϫʔΫϦΫΤετΛ͢Δ

    • Ωϟογϡ΍ϦΫΤετͷॏෳഉ আͳͲ͸ϥΠϒϥϦଆ͕ߦ͏ React Query / SWR import useSWR from 'swr' function Profile() { const { data, error } = useSWR('/api/user', fetcher) if (error) return <div>failed to load</div> if (!data) return <div>loading...</div> return <div>hello {data.name}!</div> }
  80. • react-use ΍ react-hooks-testing-library ͔Β Ϣʔεέʔε΍ͦͷςετํ๏ͳͲΛֶΜͰ Flutter ք۾ʹ൓ө͢Δ React Hooks

    ͷ࢖͍Ͳ͜Ζ
  81. react-use • ศརͳ Custom Hooks ͕ͨ͘͞Μؚ·Ε͍ͯΔ ϥΠϒϥϦ • npm i

    react-use ͯ͠࢖ͬͯ΋͍͍͠ɺ Unlicense ͳͷͰҰ෦Λίϐϖͯ͠࢖ͬͯ΋͍͍
  82. react-use

  83. import { useNetworkState } from 'react-use'; const Demo = ()

    => { const state = useNetworkState(); return ( <pre> {JSON.stringify(state, null, 2)} </pre> ); }; ྫ͑͹ useNetworkState Λ࢖͏ͱ୺ ຤ͷωοτϫʔΫঢ়ଶΛ؂ࢹͯ͠ঢ় ଶ͕มΘͬͨΒϦϏϧυͯ͠஋Λऔ ಘͰ͖ΔΑ͏ʹ͢Δ react-use
  84. react-hooks-testing-library test('should increment counter', () => { const { result

    } = renderHook(() => useCounter()) act(() => { result.current.increment() }) expect(result.current.count).toBe(1) }) ࣗ࡞ Hooks ͷςετΛॻ͘ʹ͸ίϯ ϙʔωϯτΛߋ৽͢ΔͨΊͷτϦ ΨʔΛॻ͍ͯ࠶ϨϯμϦϯάͤͨ͞ Γɺ஋Λߋ৽͢ΔͨΊͷίʔυΛॻ ͍ͨΓ͠ͳ͚Ε͹͍͚ͳ͔ͬͨ΋ͷ Λ؆୯ʹ͔͚ΔΑ͏ʹ͢Δ
  85. react-hooks-testing-library testWidgets('debugFillProperties', (tester) async { await tester.pumpWidget( HookBuilder(builder: (context) {

    usePrevious(42); return const SizedBox(); }), ); await tester.pumpWidget( HookBuilder(builder: (context) { usePrevious(21); return const SizedBox(); }), ); final element = tester.element(find.byType(HookBuilder)); expect( element .toDiagnosticsNode(style: DiagnosticsTreeStyle.offstage) .toStringDeep(), equalsIgnoringHashCodes( 'HookBuilder\n' ' │ usePrevious: 42\n' ' └SizedBox(renderObject: RenderConstrainedBox#00000)\n', ), ); }); ࢀߟίʔυͱͯ͠ Flutter Hooks ͔Β ͖࣋ͬͯͨ usePrevious ͷςετίʔ υ͕ͪ͜ΒʹͳΓ·͢ ᶃ Ͱ 42 Λ usePrevious ʹ౉͢ ᶄ Ͱ 21 Λ usePrevious ʹ౉͢ ᶅ Ͱ usePrevious ͷঢ়ଶΛ֬ೝ͢Δ ᶃ ᶄ ᶅ
  86. react-hooks-testing-library testWidgets('debugFillProperties', (tester) async { final result = await buildHook(

    (value) => usePrevious(value), initialProps: 42, ); await result.rebuild(21); expect(result.current, 42); }); ΋͠Ծʹ Flutter Ͱಉ͡Α͏ͳ͜ͱ͕Ͱ͖ ͨͱͨ͠Βɺ͜Ε͘Β͍ͷίʔυྔͰ͢ react-hooks-testing-library ͸ͦΕ͘Β͍ ϘΠϥʔίʔυΛ࡟ݮͰ͖ΔϥΠϒϥϦ ᶃ ᶄ ᶅ
  87. flutter_use ͱ flutter_hooks_testing

  88. ·ͱΊ

  89. ·ͱΊ • ΫϥΠΞϯταΠυ͕શͯએݴత UI ͷํ޲ʹͳͬͯ͘Ε͓ͨ ͔͛Ͱ Flutter Ͱ࡞Δʹͯ͠΋ React ͔Βֶ΂ͯ

    Jetpack Compose Ͱ࡞Δʹͯ͠΋ࢀߟʹͳΔ΋ͷ͕ΰϩΰϩͱస ͕͍ͬͯΔ • ֤ݴޠͷҧ͍ͳΜͯࠣࡉͳ΋ͷͰ UI ϑϨʔϜϫʔΫΛͦΕͧ ΕֶͿͷ͕େม͚ͩͬͨͲɺ༏͍͠ੈքʹͳ͖ͬͯͨ
  90. Google Developers Expert @wasabeef_jp wasabeef CyberAgent, Inc.