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.

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

    View full-size slide

  2. Flutter 2021 ͷৼΓฦΓͱࠓޙͷΞϓϦ։ൃʹ޲͚ͯ
    1. ΫϩεϓϥοτϑΥʔϜͷݱঢ়ͱ՝୊


    2. 2022೥΋ Flutter Λબ୒͢Δ͔Ͳ͏͔


    3. Flutter ͱ Dart ͷΞοϓσʔτ


    4. Flutter ΞϓϦ։ൃͷࠓޙʹ޲͚ͯ


    4.1. ΞϓϦͷΞʔΩςΫνϟ


    4.2. React ͔Βֶͼ͍ͨ͜ͱ

    View full-size slide

  3. ΫϩεϓϥοτϑΥʔϜ
    ͷݱঢ়ͱ՝୊

    View full-size slide

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


    1. ϝϦοτɾσϝϦοτ


    2. Kotlin Multiplatform


    3. Compose Multiplatform


    2. Flutter ͷ࠾༻ࣄྫ

    View full-size slide

  5. ΫϩεϓϥοτϑΥʔϜͰ։ൃ͢Δલʹ஌͓ͬͯ͘΂͖͜ͱ

    View full-size slide

  6. ΫϩεϓϥοτϑΥʔϜͰ։ൃ͢Δલʹ஌͓ͬͯ͘΂͖͜ͱ
    • ΫϩεϓϥοτϑΥʔϜͰ։ൃ͢ΔҙຯΛߟ͑Δ

    → ԿΛڞ௨Խ͍͔ͨ͠ʁ


    • ʮͱΓ͋͑ͣ Flutter ͕ྲྀߦͬͯΔΒ͍͔͠Β Flutter Ͱ΍ͬͱ͚
    ͹͍͍ʯͰ͸ͳ͍


    • ͜Ε·Ͱొ৔͖ͯͨ͠਺ଟͷΫϩεϓϥοτϑΥʔϜϑϨʔϜ
    ϫʔΫ͕ਁಁ͠ͳ͔ͬͨ͜ͱ
    اۀͱͯ͠औΓ૊Ή৔߹

    View full-size slide

  7. ΫϩεϓϥοτϑΥʔϜͰ։ൃ͢ΔҙຯΛߟ͑Δ
    QɿԿΛڞ௨Խ͍͔ͨ͠ʁ
    A1ɿϩδοΫ͚ͩڞ௨Խ͢Δ


    A2ɿUI ΋ϩδοΫ΋ڞ௨Խ͢Δ


    A3ɿࠓ͸ϩδοΫ͚ͩͰকདྷతʹ͸


    ɹɹ UI ΋ڞ௨Խ͢Δ
    UI
    ϩδοΫ
    List Button
    Domain
    Label Nav
    Media Notification Sensors
    Business Logic
    Networking Database
    etc..
    etc..
    Log Utils

    View full-size slide

  8. ΫϩεϓϥοτϑΥʔϜͰ։ൃ͢ΔҙຯΛߟ͑Δ
    QɿԿΛڞ௨Խ͍͔ͨ͠ʁ
    A1ɿϩδοΫ͚ͩڞ௨Խ͢Δ


    A2ɿUI ΋ϩδοΫ΋ڞ௨Խ͢Δ


    A3ɿࠓ͸ϩδοΫ͚ͩͰকདྷతʹ͸


    ɹɹ UI ΋ڞ௨Խ͢Δ
    UI
    ϩδοΫ
    UI + ϩδοΫ

    View full-size slide

  9. ϝϦοτɾσϝϦοτ

    View full-size slide

  10. ϝϦοτ
    • ΤϯδχΞͷϦιʔεઅ໿


    • ਓ਺ɾ։ൃظؒ୹ॖ


    • ։ൃίϛϡχςΟͷٸ଎తͳ
    ֦େʢࠃ಺֎ɺFlutterKaigi ͳͲʣ


    • iOS/Android Ͱڞ௨ͷ UI

    ʢྑ͘΋ʣ
    σϝϦοτ
    • ΞϓϦಈ࡞ͷ҆ఆੑ

    ʢωΠςΟϒʹ͸ྼΔʣ


    • কདྷੑɺઌߦ͖ෆ҆

    ʢͲͷϑϨʔϜϫʔΫΛ࠾༻͢Δ͔ʣ


    • iOS/Android Ͱڞ௨ͷ UI

    ʢѱ͘΋ʣ


    • iOS/Android ͷ৽ػೳ΁ͷ௥
    ैͷ஗ΕΔ

    View full-size slide

  11. ΤϯδχΞͷϦιʔεઅ໿
    αʔόΤϯδχΞ
    iOS ΤϯδχΞ
    Web ΤϯδχΞ
    Android ΤϯδχΞ
    Ұൠతͳ Swift/Kotlin ΞϓϦͷΞαΠϯελΠϧ


    View full-size slide

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

    View full-size slide

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


    ϨϏϡʔ͞Εͳ͍ෆ҆

    View full-size slide

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


    ίʔυϨϏϡʔͰ͖ͯ݁Ռͱͯ͠
    ඼࣭޲্΋ɻ

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  18. iOS/Android ͷ৽ػೳ΁ͷ௥ैͷ஗Εʁ
    ྫ͑͹ iOS 15ɺAndroid 12 ͷରԠ͕க໋తʹ஗Ε͍ͯͯ։ൃͰ͖ͳ͍ͱ͍͏ײ֮͸ͳ
    ͍͕ɺ֤ OS ͷ৽ API ͷΠϯλʔϑΣʔεެ։͕ޙ௥͍ͰདྷΔͷ͸ࣄ࣮ͱͳΓ·͢

    View full-size slide

  19. Kotlin Multiplatform

    View full-size slide

  20. Kotlin Multiplatform
    • JetBrains ʹΑͬͯ։ൃ


    • UI ͷڞ௨Խ͸ͤͣɺϏδωεϩ
    δοΫͷڞ௨ԽʹಛԽ͍ͯ͠Δ
    ʢೝূɺϩάͳͲͷڞ௨Խʣ


    • Kotlin Ͱ Backends for
    Frontends
    Kotlin/LLVM
    Kotlin/JVM Kotlin/JVM
    Kotlin/JS
    Common code

    View full-size slide

  21. Compose Multiplatform

    View full-size slide

  22. Compose Multiplatform
    • 1.0.0 (Dec 2021)


    • Jetpack Compose ϕʔεͰ Jetbrains ʹΑΔ։ൃ


    • ݩʑ͸ Compose for Desktop ͩͬͨ΋ͷ


    • ݱࡏ͸ओʹ Desktop / Web ΞϓϦ޲͚ʢAndroid Ͱ΋ಈ͘ʣ


    • ݱஈ֊Ͱ͸ iOS ΁ͷެࣜαϙʔτ͸ൃද͞Ε͍ͯͳ͍


    • άϥϑΟοΫΤϯδϯ͸ Skia Λར༻͍ͯ͠Δ

    View full-size slide

  23. Skia
    • άϥϑΟοΫϥΠϒϥϦ
    • Android, Chrome, Firefox, Blink, Flutter Ͱ࠾༻͞Ε͍ͯΔ
    • Skia ͸ Vulkan ΛόοΫΤϯυΤϯδϯͱͯ͠มߋՄೳ
    • Android 9 Ҏ߱ɺσϑΥϧτͷϨϯμϥʔ͸ Skia ʹͳ͍ͬͯΔ
    ʢ8 ͱ 9 ͰUI͕มΘͬͨͷ͸ͦͷͨΊʣɻFlutter ʹ͢ΔͱϨΠ
    Ϡʔ͕૿͑Δ΋ͷͷϨϯμϥʔ͸ಉ͡

    View full-size slide

  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+

    View full-size slide

  25. Flutter ͷ࠾༻ࣄྫ

    View full-size slide

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





    12݄ 375,000 ΞϓϦ


    ͜͜ 6 ϲ݄Ͱ 1.87 ഒ
    App Store

    View full-size slide

  27. 2022೥΋ Flutter Λબ୒
    ͢Δ͔Ͳ͏͔

    View full-size slide

  28. 2022೥΋ Flutter Λબ୒͢Δ͔Ͳ͏͔
    1. ΫϩεϓϥοτϑΥʔϜ͔ʁ֤ϓϥοτϑΥʔϜ͔ʁ


    1.1. ΞϓϦͷػೳཁ݅͸ʁ


    1.2. ΤϯδχΞͷಘҙྖҬɺͦͷਓ਺ɺظؒ͸ʁ


    2. React Native ͸ʁ.NET MAUI ͸ʁ


    3. Compose Multiplatform ͷ୆಄͸ʁ

    View full-size slide

  29. ΫϩεϓϥοτϑΥʔϜ͔ʁ֤ϓϥοτϑΥʔϜʢiOS / Androidʣ͔ʁ
    ɹΫϩεϓϥοτϑΥʔϜɹ ɹ֤ϓϥοτϑΥʔϜʢiOS / Androidʣ
    • UI ΍ϏδωεϩδοΫ͕ iOS /
    Android Ͱҧ͏


    • ҆ఆͯ͠ΫΦϦςΟ͕ߴ͍΋ͷ࡞
    Γ͍ͨ


    • iOS / Android ͷܦݧऀ͕͍Δ


    • εέδϡʔϧʹ༨༟͕͋Δ
    ྫ ྫ
    • UI ΍ϏδωεϩδοΫ͕ iOS /
    Android Ͱಉ͡


    • ٕज़౤ࢿతͳνϟϨϯδΛ͍ͨ͠


    • iOS / Android ͷܦݧऀ͕গͳ͍

    ʢΤϯδχΞͷ਺͕গͳ͍ʣ


    • εέδϡʔϧʹ༨༟͕ͳ͍


    View full-size slide

  30. ΞϓϦͷػೳཁ݅͸ʁ

    View full-size slide

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

    → Flutter ͸ཱͪҐஔ͕ UI ϑϨʔϜϫʔΫͳͷͰཁ͕݅ͦ΋ͦ΋͍͋ͬͯͳ͍͔΋


    • ಈըͳͲͷίϯςϯπΛදࣔ͢Δͷʹ DRM ͕ඞཁʁ

    → Flutter ͚ͩͰ࣮૷͢Δͷ͸ݱஈ֊Ͱ͸ FairPlay ରԠͨ͠ϥΠϒϥϦ͕ͳ͍


    • οοΰϦοοΰϦͷΞχϝʔγϣϯ͕͋Δʁ

    → ύϑΥʔϚϯε͕ωΠςΟϒΑΓྼΔͷͰཁݕূ

    View full-size slide

  32. ΤϯδχΞͷಘҙྖҬɺͦͷਓ਺ɺظؒ͸ʁ

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  35. ΤϯδχΞͷಘҙྖҬɺͦͷਓ਺ɺظؒ͸ʁ
    αʔόΤϯδχΞ
    ΞϓϦΤϯδχΞ
    Web ΤϯδχΞ
    ͜ͷύλʔϯͰ͸࣮֬ʹΫϩεϓϥοτ
    ϑΥʔϜ͕༗ޮʹͳͬͯ͘Δ


    ·ͨɺFlutter ͕ෛ࠴ʹͳΔՄೳੑ΋͜Ε
    ·ͰͷΫϩεϓϥοτϑΥʔϜϑϨʔϜ
    ϫʔΫʹൺ΂Δͱ௿͍ʢͱࢥ͏ʣ

    View full-size slide

  36. React Native ͸ʁ.NET MAUI ͸ʁ

    View full-size slide

  37. React Native ͸ʁ
    • Web ํ໘ʹڧ͍ΤϯδχΞ͕͍Δ৔߹ͳͲͷબ୒ࢶ

    → νʔϜͷಘҙྖҬ΍ٕज़ࢿ࢈ʹΑܾͬͯఆ


    • ϝϧΧϦ US ͕ React Native Ͱॻ͖௚ͨ͠Β͍͠

    → https://link.medium.com/SNFEPzc1Rlb


    • Facebook ΍ Coinbase ΍ Discord ΍ Tesla ͱ͍ͬͨ༗໊ͳاۀ΋࠾༻

    → https://reactnative.dev/showcase


    • npm ʹ͋Δࢿ࢈Λࢧ͑Δͷ͸ڧΈ

    ʢ༨ஊɿϒϩοΫνΣʔϯؔ࿈ٕज़͸ React Native ޲͚ͷ SDK ʹ͔͠ରԠ͍ͯ͠ͳ͍৔߹͕ଟ͍ʣ

    View full-size slide

  38. .NET MAUI ʢچ Xamarin.Formsʣ͸ʁ
    • C# ํ໘ʹڧ͍ΤϯδχΞ͕͍Δ৔߹ͳͲͷબ୒ࢶ

    → νʔϜͷಘҙྖҬ΍ٕज़ࢿ࢈ʹΑܾͬͯఆ


    • ৽ܕίϩφ΢Πϧε઀৮֬ೝΞϓϦ͸ Xamarin Λ࠾༻


    • .NET MAUI ʹͳΔͱ XML ΛࣙΊએݴత UI Ͱॻ͚Δ


    • ࣄྫ͕ Flutter ΍ React Native ʹൺ΂Δͱগͳ͍

    View full-size slide

  39. Compose Multiplatform ͷ୆಄͸ʁ

    View full-size slide

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

    → ݱஈ֊Ͱ iOS ͷਖ਼ࣜαϙʔτ͕ೖ͍ͬͯͳ͍


    • ͦͷ൑அ͕Ͱ͖Δͷ͕΋͏গ͠ઌʹͳΓͦ͏

    View full-size slide

  41. • ৽نϓϩδΣΫτ


    • গਓ਺ʢ1ਓʙʣ


    • গਓ਺Ͱ΋྆ϓϥοτϑΥʔ
    ϜͰϒϥϯσΟϯάͷҰ؏ੑ
    Λҡ͍࣋ͨ͠


    • ͱʹ͔͘ૣ͘ϦϦʔε͍ͨ͠


    • ΑΓνϟϨϯδ͍ͨ͠

    ɹFlutterɹ
    Flutter ͔ʁ Kotlin MPP ͔ʁ+ Compose Multiplatform ͔ʁ
    ɹKotlin MPPɹ
    • ৽ن / طଘϓϩδΣΫτ


    • େਓ਺ʢ10ਓʙʣ


    • iOS/AndroidΞϓϦ։ൃͷਫ਼
    ௨͍ͯ͠Δ


    • ϦεΫΛ཈͍֤͑ͨϓϥοτ
    ϑΥʔϜͰ෼͚ͯσβΠϯΛ
    ߆Γ͍ͨ

    ɹ+ Compose Multiplatformɹ
    • ݕূʢ৽نʣϓϩδΣΫτ


    • গਓ਺Ͱ΋྆ϓϥοτ
    ϑΥʔϜͰϒϥϯσΟϯά
    ͷҰ؏ੑΛҡ͍࣋ͨ͠


    • ͱʹ͔͘ૣ͘ϦϦʔεͨ͠
    ͍


    • কདྷ΁ͷٕज़౤ࢿΛ͍ͨ͠

    View full-size slide

  42. • UI ΋ϏδωεϩδοΫ΋ڞ
    ௨ԽͰ͖Δ


    • ࣄྫ͕ଟ͍


    • Google Λ৴͍ͯ͡Δ



    ɹFlutterɹ Kotlin MPP + Compose


    ɹɹɹɹɹɹ Multiplatform
    • Web / React ϝϯόʔ͕ଟ͍

    ʢWeb ͷࢿ࢈Λ࢖͍͍ͨʣ


    • UI ΋ϏδωεϩδοΫ΋ڞ
    ௨ԽͰ͖Δ


    • ࣄྫ͕ଟ͍ʢ͕ࠃ಺ͷ੎͍͸ྼΔʣ


    • Facebook Λ৴͍ͯ͡Δ


    • Android / Kotlin ϝϯόʔ͕
    ଟ͍ʢKotlin ͷࢿ࢈Λ࢖͍͍ͨʣ


    • ॳظஈ֊͸ϏδωεϩδοΫ
    ͚ͩڞ௨Խ͠ Compose
    Multiplatform ͕҆ఆͨ͠λ
    ΠϛϯάͰ UI Λॻ͖௚͢ύ
    λʔϯ


    • Jetbrains Λ৴͍ͯ͡Δ



    React Native

    2022೥΋ Flutter Λબ୒͢Δ͔Ͳ͏͔

    View full-size slide

  43. Flutter ͱ Dart ͷ


    Ξοϓσʔτ

    View full-size slide

  44. 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

    View full-size slide

  45. Firebase UI
    https://link.medium.com/a7Md15TNPlb
    • ೝূը໘ͷ΢ΟδΣοτ


    • Firebase Auth Λར༻


    • Email, Google, Meta,
    Twitter, Apple ʹରԠ

    View full-size slide

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

    3. enum ʹ API ௥Ճ
    4. ϥΠϒϥϦ։ൃ޲͚Ͱ pub ʹػೳ௥Ճ
    https://link.medium.com/kZTQCmukPlb

    View full-size slide

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

    View full-size slide

  48. 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 _read(File filename) {


    final fileData =


    await File(filename).readAsString();


    final jsonData = jsonDecode(fileData);


    }


    Isolate ͷػೳ޲্
    Flutter ͷ computeʢத਎͸ Dart ͷ Isolateʣ
    Dart ͷ Isolate

    View full-size slide

  49. Isolate ͷػೳ޲্
    https://link.medium.com/kZTQCmukPlb
    void main() async {


    final jsonData = await _parseInBackground();


    print('number of JSON keys = ${jsonData.length}');


    }


    // Isolate.spawn


    Future> _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);


    }

    View full-size slide

  50. 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);


    View full-size slide

  51. 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 Ͱ͖ΔΑ͏ʹͳͬͨ

    View full-size slide

  52. 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);

    View full-size slide

  53. ϥΠϒϥϦ։ൃ޲͚Ͱ pub ʹػೳ௥Ճ
    https://link.medium.com/kZTQCmukPlb
    1. ϦϦʔε࣌ʹҙਤ͠ͳ͍ Secrets ؚ͕·Εͯͳ͍͔νΣοΫ
    2. ޡͬͯϦϦʔεͨ͠΋ͷΛ pub.dev ͔ΒఫճͰ͖ΔΑ͏ʹ

    View full-size slide

  54. ϦϦʔε࣌ʹҙਤ͠ͳ͍ 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 ʹҎԼΛ௥Ճ

    View full-size slide

  55. pub.dev ͰϦϦʔεΛఫճ
    https://link.medium.com/kZTQCmukPlb

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  58. Flutter ΞϓϦ։ൃͷࠓޙʹ޲͚ͯʢݸਓࢹ఺ʣ
    1. ΞϓϦͷΞʔΩςΫνϟ


    2. React ͔Βֶͼ͍ͨ͜ͱ


    2.1. React Hooks


    2.2. React ͷΞʔΩςΫνϟ

    View full-size slide

  59. ΞϓϦͷΞʔΩςΫνϟ

    View full-size slide

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

    View full-size slide

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


    Repository


    ViewModel
    Local Source Remote Data Source
    MVVM
    Repository
    MVVM + Repository

    View full-size slide

  62. ͜ͷϘλϯͷঢ়ଶ؅ཧ͸Ͳ͏͢Δʁ
    ςΩετϑΟʔϧυʹԿ͔
    ͕ೖྗ͞ΕΔ·ͰϘλϯ͸
    ඇ׆ੑʹ͍ͨ͠

    View full-size slide

  63. 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'),


    ),


    ],


    );


    }


    }

    View full-size slide

  64. ίϯϙʔωϯτ਺ ≒ ViewModel਺ʁ
    • XML ࣌୅ͷ Android ͩͱϨΠΞ΢τͷ୯Ґ͕େ͖͔ͬͨ


    • Flutter Ͱ͸Ͱ͖Δ͚ͩίϯϙʔωϯτΛখ͘͞׬݁ʹ࡞
    Γ͍ͨ


    • ϑΝΠϧ਺૿͑͗͢ΔͷͰίϯϙʔωϯτΛࡉ͔͘͢͠
    ͗ͳ͍Α͏ʹ͢Δ͔ʁʢͦͷԘക͕೉͍͠ʣ

    View full-size slide

  65. 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 ͷൣғΛগ͠େ͖ͯ͘͠ΈΔʁ

    View full-size slide

  66. ؆୯ͳঢ়ଶ͸ίϯϙʔωϯτଆͰ͍࣋ͪͨ ʴ ؆୯ʹॻ͖͍ͨ
    class CountPage extends StatefulWidget {


    @override


    State createState() => _CountState();


    }


    class _CountState extends State {


    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++,


    );


    }


    }


    View full-size slide

  67. Flutter Hooks

    View full-size slide

  68. LaunchedEffect(id) {


    //
    ID ͕มߋ͞ΕΔͨͼ


    }


    SideEffect {


    //
    ຖճ


    }


    LaunchedEffect(Unit) {


    //
    ࠷ॳͷҰճ


    }


    73
    useEffect
    useEffect(()
    =>
    {


    //
    ID ͕มߋ͞ΕΔͨͼ


    }, [id]);


    useEffect(()
    =>
    {


    //
    ຖճ


    });


    useEffect(()
    =>
    {


    //
    ࠷ॳͷҰճ


    }, const []);


    Flutter Hooks Jetpack Compose

    View full-size slide

  69. ViewModel ͔ΒϘλϯͳͲͷঢ়ଶ؅ཧΛࠩ͠Ҿ͍͍ͯ͘ͱ
    ViewModel ͡Όͳ͍͍͔ͯ͘΋͠Εͳ͍





    MVVM ͡Όͳ͍͔΋…

    ʢ࣮ࡍʹ͸ଞʹ΋৭ʑΉͣᙱ͍ͱ͜Ζ͕͋Δʣ
    ΞʔΩςΫνϟΛߟ͑௚͢

    View full-size slide

  70. ࠷ۙ͸ϨΠϠʔଟ͗͢Δ΋ͬͱݮΒ͍͖͍ͯͨ͠





    Flutter ΞϓϦք۾ͷઃܭ͕ఆ·ͬͯͳ͍͔ΒReact ͔ΒֶͿ͔
    ΞʔΩςΫνϟΛߟ͑௚͢

    View full-size slide

  71. React ͔Βֶͼ͍ͨ͜ͱ

    View full-size slide

  72. React ͔Βֶͼ͍ͨ͜ͱʢݸਓࢹ఺ʣ
    1. React App ͷΞʔΩςΫνϟ
    2. React Hooks ͷ࢖͍Ͳ͜Ζ
    3. ίϯϙʔωϯτ୯ҐͰͷςετ

    View full-size slide

  73. • Redux


    • Recoil


    • + React Query / SWR
    React App ͷΞʔΩςΫνϟ

    View full-size slide

  74. • React Hook ࢖ͬͯσʔλऔಘ͢Δ
    ͨΊͷϥΠϒϥϦ


    • ίϯϙʔωϯτଆͰ API ͷωοτ
    ϫʔΫϦΫΤετΛ͢Δ


    • Ωϟογϡ΍ϦΫΤετͷॏෳഉ
    আͳͲ͸ϥΠϒϥϦଆ͕ߦ͏
    React Query / SWR
    import useSWR from 'swr'


    function Profile() {


    const { data, error } = useSWR('/api/user', fetcher)


    if (error) return failed to load


    if (!data) return loading...


    return hello {data.name}!


    }


    View full-size slide

  75. • react-use ΍ react-hooks-testing-library ͔Β
    Ϣʔεέʔε΍ͦͷςετํ๏ͳͲΛֶΜͰ
    Flutter ք۾ʹ൓ө͢Δ
    React Hooks ͷ࢖͍Ͳ͜Ζ

    View full-size slide

  76. react-use
    • ศརͳ Custom Hooks ͕ͨ͘͞Μؚ·Ε͍ͯΔ
    ϥΠϒϥϦ


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

    View full-size slide

  77. import { useNetworkState } from 'react-use';


    const Demo = () => {


    const state = useNetworkState();


    return (





    {JSON.stringify(state, null, 2)}





    );


    };
    ྫ͑͹ useNetworkState Λ࢖͏ͱ୺
    ຤ͷωοτϫʔΫঢ়ଶΛ؂ࢹͯ͠ঢ়
    ଶ͕มΘͬͨΒϦϏϧυͯ͠஋Λऔ
    ಘͰ͖ΔΑ͏ʹ͢Δ
    react-use

    View full-size slide

  78. react-hooks-testing-library
    test('should increment counter', () => {


    const { result } = renderHook(() => useCounter())


    act(() => {


    result.current.increment()


    })


    expect(result.current.count).toBe(1)


    })


    ࣗ࡞ Hooks ͷςετΛॻ͘ʹ͸ίϯ
    ϙʔωϯτΛߋ৽͢ΔͨΊͷτϦ
    ΨʔΛॻ͍ͯ࠶ϨϯμϦϯάͤͨ͞
    Γɺ஋Λߋ৽͢ΔͨΊͷίʔυΛॻ
    ͍ͨΓ͠ͳ͚Ε͹͍͚ͳ͔ͬͨ΋ͷ
    Λ؆୯ʹ͔͚ΔΑ͏ʹ͢Δ

    View full-size slide

  79. 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 ͷঢ়ଶΛ֬ೝ͢Δ





    View full-size slide

  80. 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 ͸ͦΕ͘Β͍
    ϘΠϥʔίʔυΛ࡟ݮͰ͖ΔϥΠϒϥϦ



    View full-size slide

  81. flutter_use ͱ flutter_hooks_testing

    View full-size slide

  82. ·ͱΊ
    • ΫϥΠΞϯταΠυ͕શͯએݴత UI ͷํ޲ʹͳͬͯ͘Ε͓ͨ
    ͔͛Ͱ Flutter Ͱ࡞Δʹͯ͠΋ React ͔Βֶ΂ͯ Jetpack
    Compose Ͱ࡞Δʹͯ͠΋ࢀߟʹͳΔ΋ͷ͕ΰϩΰϩͱస
    ͕͍ͬͯΔ
    • ֤ݴޠͷҧ͍ͳΜͯࠣࡉͳ΋ͷͰ UI ϑϨʔϜϫʔΫΛͦΕͧ
    ΕֶͿͷ͕େม͚ͩͬͨͲɺ༏͍͠ੈքʹͳ͖ͬͯͨ

    View full-size slide

  83. Google Developers Expert
    @wasabeef_jp
    wasabeef
    CyberAgent, Inc.

    View full-size slide