Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

Flutter 2021 ͷৼΓฦΓͱࠓޙͷΞϓϦ։ൃʹ޲͚ͯ 1. ΫϩεϓϥοτϑΥʔϜͷݱঢ়ͱ՝୊ 2. 2022೥΋ Flutter Λબ୒͢Δ͔Ͳ͏͔ 3. Flutter ͱ Dart ͷΞοϓσʔτ 4. Flutter ΞϓϦ։ൃͷࠓޙʹ޲͚ͯ 4.1. ΞϓϦͷΞʔΩςΫνϟ 4.2. React ͔Βֶͼ͍ͨ͜ͱ

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

ΫϩεϓϥοτϑΥʔϜͰ։ൃ͢Δલʹ஌͓ͬͯ͘΂͖͜ͱ • ΫϩεϓϥοτϑΥʔϜͰ։ൃ͢ΔҙຯΛߟ͑Δ 
 → ԿΛڞ௨Խ͍͔ͨ͠ʁ • ʮͱΓ͋͑ͣ Flutter ͕ྲྀߦͬͯΔΒ͍͔͠Β Flutter Ͱ΍ͬͱ͚ ͹͍͍ʯͰ͸ͳ͍ • ͜Ε·Ͱొ৔͖ͯͨ͠਺ଟͷΫϩεϓϥοτϑΥʔϜϑϨʔϜ ϫʔΫ͕ਁಁ͠ͳ͔ͬͨ͜ͱ اۀͱͯ͠औΓ૊Ή৔߹

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

ΫϩεϓϥοτϑΥʔϜͰ։ൃ͢ΔҙຯΛߟ͑Δ QɿԿΛڞ௨Խ͍͔ͨ͠ʁ A1ɿϩδοΫ͚ͩڞ௨Խ͢Δ A2ɿUI ΋ϩδοΫ΋ڞ௨Խ͢Δ A3ɿࠓ͸ϩδοΫ͚ͩͰকདྷతʹ͸ ɹɹ UI ΋ڞ௨Խ͢Δ UI ϩδοΫ UI + ϩδοΫ

Slide 9

Slide 9 text

ϝϦοτɾσϝϦοτ

Slide 10

Slide 10 text

ϝϦοτ • ΤϯδχΞͷϦιʔεઅ໿ • ਓ਺ɾ։ൃظؒ୹ॖ • ։ൃίϛϡχςΟͷٸ଎తͳ ֦େʢࠃ಺֎ɺFlutterKaigi ͳͲʣ • iOS/Android Ͱڞ௨ͷ UI 
 ʢྑ͘΋ʣ σϝϦοτ • ΞϓϦಈ࡞ͷ҆ఆੑ 
 ʢωΠςΟϒʹ͸ྼΔʣ • কདྷੑɺઌߦ͖ෆ҆ 
 ʢͲͷϑϨʔϜϫʔΫΛ࠾༻͢Δ͔ʣ • iOS/Android Ͱڞ௨ͷ UI 
 ʢѱ͘΋ʣ • iOS/Android ͷ৽ػೳ΁ͷ௥ ैͷ஗ΕΔ

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

ΤϯδχΞͷϦιʔεઅ໿ αʔόΤϯδχΞ iOS ΤϯδχΞ Web ΤϯδχΞ Android ΤϯδχΞ Ұൠతͳ Swift/Kotlin ΞϓϦͷΞαΠϯελΠϧ ϨϏϡʔ͞Εͳ͍ෆ҆

Slide 14

Slide 14 text

ΤϯδχΞͷϦιʔεઅ໿ ΫϩεϓϥοτϑΥʔϜͰͷΞαΠϯελΠϧ αʔόΤϯδχΞ ΞϓϦΤϯδχΞ Web ΤϯδχΞ ͱΓ͋͑ͣ1ਓҎ্͍Ε͹ iOS/ Android ΞϓϦ྆ํ։ൃՄೳ ίʔυϨϏϡʔͰ͖ͯ݁Ռͱͯ͠ ඼࣭޲্΋ɻ

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

Kotlin Multiplatform

Slide 20

Slide 20 text

Kotlin Multiplatform • JetBrains ʹΑͬͯ։ൃ • UI ͷڞ௨Խ͸ͤͣɺϏδωεϩ δοΫͷڞ௨ԽʹಛԽ͍ͯ͠Δ ʢೝূɺϩάͳͲͷڞ௨Խʣ • Kotlin Ͱ Backends for Frontends Kotlin/LLVM Kotlin/JVM Kotlin/JVM Kotlin/JS Common code

Slide 21

Slide 21 text

Compose Multiplatform

Slide 22

Slide 22 text

Compose Multiplatform • 1.0.0 (Dec 2021) • Jetpack Compose ϕʔεͰ Jetbrains ʹΑΔ։ൃ • ݩʑ͸ Compose for Desktop ͩͬͨ΋ͷ • ݱࡏ͸ओʹ Desktop / Web ΞϓϦ޲͚ʢAndroid Ͱ΋ಈ͘ʣ • ݱஈ֊Ͱ͸ iOS ΁ͷެࣜαϙʔτ͸ൃද͞Ε͍ͯͳ͍ • άϥϑΟοΫΤϯδϯ͸ Skia Λར༻͍ͯ͠Δ

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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+

Slide 25

Slide 25 text

Flutter ͷ࠾༻ࣄྫ

Slide 26

Slide 26 text

Flutter ͷ࠾༻ࣄྫ https://medium.com/flutter/announcing-flutter-2-8-31d2cb7e19f5 5݄ 200,000 ΞϓϦ ↓ 12݄ 375,000 ΞϓϦ ͜͜ 6 ϲ݄Ͱ 1.87 ഒ App Store

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

ΞϓϦͷػೳཁ݅͸ʁ

Slide 31

Slide 31 text

ΞϓϦͷػೳཁ݅͸ʁ • iOS ͱ Android Ͱ UI ͷମݧ͕શ͘ҧ͏ʁ 
 → Flutter ͸ཱͪҐஔ͕ UI ϑϨʔϜϫʔΫͳͷͰཁ͕݅ͦ΋ͦ΋͍͋ͬͯͳ͍͔΋ • ಈըͳͲͷίϯςϯπΛදࣔ͢Δͷʹ DRM ͕ඞཁʁ 
 → Flutter ͚ͩͰ࣮૷͢Δͷ͸ݱஈ֊Ͱ͸ FairPlay ରԠͨ͠ϥΠϒϥϦ͕ͳ͍ • οοΰϦοοΰϦͷΞχϝʔγϣϯ͕͋Δʁ 
 → ύϑΥʔϚϯε͕ωΠςΟϒΑΓྼΔͷͰཁݕূ

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

ΤϯδχΞͷಘҙྖҬɺͦͷਓ਺ɺظؒ͸ʁ αʔόΤϯδχΞ ΞϓϦΤϯδχΞ Web ΤϯδχΞ ͜ͷύλʔϯͰ͸࣮֬ʹΫϩεϓϥοτ ϑΥʔϜ͕༗ޮʹͳͬͯ͘Δ ·ͨɺFlutter ͕ෛ࠴ʹͳΔՄೳੑ΋͜Ε ·ͰͷΫϩεϓϥοτϑΥʔϜϑϨʔϜ ϫʔΫʹൺ΂Δͱ௿͍ʢͱࢥ͏ʣ

Slide 36

Slide 36 text

React Native ͸ʁ.NET MAUI ͸ʁ

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

.NET MAUI ʢچ Xamarin.Formsʣ͸ʁ • C# ํ໘ʹڧ͍ΤϯδχΞ͕͍Δ৔߹ͳͲͷબ୒ࢶ 
 → νʔϜͷಘҙྖҬ΍ٕज़ࢿ࢈ʹΑܾͬͯఆ • ৽ܕίϩφ΢Πϧε઀৮֬ೝΞϓϦ͸ Xamarin Λ࠾༻ • .NET MAUI ʹͳΔͱ XML ΛࣙΊએݴత UI Ͱॻ͚Δ • ࣄྫ͕ Flutter ΍ React Native ʹൺ΂Δͱগͳ͍

Slide 39

Slide 39 text

Compose Multiplatform ͷ୆಄͸ʁ

Slide 40

Slide 40 text

Compose Multiplatform ͷ୆಄͸ʁ • ୆಄͢Δ͔΋͠Εͳ͍͕ɺͦΕ͕ 2022 ೥ʹϞόΠϧ޲͚ ʹ Production Ready ʹͳΔՄೳੑ͸௿͍ 
 → ݱஈ֊Ͱ iOS ͷਖ਼ࣜαϙʔτ͕ೖ͍ͬͯͳ͍ • ͦͷ൑அ͕Ͱ͖Δͷ͕΋͏গ͠ઌʹͳΓͦ͏

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

Flutter ͱ Dart ͷ Ξοϓσʔτ

Slide 44

Slide 44 text

Flutter 2.8

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

Firebase UI https://link.medium.com/a7Md15TNPlb • ೝূը໘ͷ΢ΟδΣοτ • Firebase Auth Λར༻ • Email, Google, Meta, Twitter, Apple ʹରԠ

Slide 47

Slide 47 text

Dart 2.15

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

Dart 2.15 1. Isolate class ͷػೳ޲্ 2. Constructor tear-off s 3. enum ʹ API ௥Ճ 4. ϥΠϒϥϦ։ൃ޲͚Ͱ pub ʹػೳ௥Ճ https://link.medium.com/kZTQCmukPlb

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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); }

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

DartPad

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

DartPad

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

ΞϓϦͷΞʔΩςΫνϟ

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

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'), ), ], ); } }

Slide 69

Slide 69 text

ίϯϙʔωϯτ਺ ≒ ViewModel਺ʁ • XML ࣌୅ͷ Android ͩͱϨΠΞ΢τͷ୯Ґ͕େ͖͔ͬͨ • Flutter Ͱ͸Ͱ͖Δ͚ͩίϯϙʔωϯτΛখ͘͞׬݁ʹ࡞ Γ͍ͨ • ϑΝΠϧ਺૿͑͗͢ΔͷͰίϯϙʔωϯτΛࡉ͔͘͢͠ ͗ͳ͍Α͏ʹ͢Δ͔ʁʢͦͷԘക͕೉͍͠ʣ

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

؆୯ͳঢ়ଶ͸ίϯϙʔωϯτଆͰ͍࣋ͪͨ ʴ ؆୯ʹॻ͖͍ͨ 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++, ); } }

Slide 72

Slide 72 text

Flutter Hooks

Slide 73

Slide 73 text

LaunchedEffect(id) { // ID ͕มߋ͞ΕΔͨͼ } SideEffect { // ຖճ } LaunchedEffect(Unit) { // ࠷ॳͷҰճ } 73 useEffect useEffect(() => { // ID ͕มߋ͞ΕΔͨͼ }, [id]); useEffect(() => { // ຖճ }); useEffect(() => { // ࠷ॳͷҰճ }, const []); Flutter Hooks Jetpack Compose

Slide 74

Slide 74 text

ViewModel ͔ΒϘλϯͳͲͷঢ়ଶ؅ཧΛࠩ͠Ҿ͍͍ͯ͘ͱ ViewModel ͡Όͳ͍͍͔ͯ͘΋͠Εͳ͍ ↓ MVVM ͡Όͳ͍͔΋… 
 ʢ࣮ࡍʹ͸ଞʹ΋৭ʑΉͣᙱ͍ͱ͜Ζ͕͋Δʣ ΞʔΩςΫνϟΛߟ͑௚͢

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

React ͔Βֶͼ͍ͨ͜ͱ

Slide 77

Slide 77 text

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

Slide 78

Slide 78 text

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

Slide 79

Slide 79 text

• 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}!
}

Slide 80

Slide 80 text

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

Slide 81

Slide 81 text

react-use • ศརͳ Custom Hooks ͕ͨ͘͞Μؚ·Ε͍ͯΔ ϥΠϒϥϦ • npm i react-use ͯ͠࢖ͬͯ΋͍͍͠ɺ Unlicense ͳͷͰҰ෦Λίϐϖͯ͠࢖ͬͯ΋͍͍

Slide 82

Slide 82 text

react-use

Slide 83

Slide 83 text

import { useNetworkState } from 'react-use'; const Demo = () => { const state = useNetworkState(); return (


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


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

Slide 84

Slide 84 text

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

Slide 85

Slide 85 text

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 ͷঢ়ଶΛ֬ೝ͢Δ ᶃ ᶄ ᶅ

Slide 86

Slide 86 text

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

Slide 87

Slide 87 text

flutter_use ͱ flutter_hooks_testing

Slide 88

Slide 88 text

·ͱΊ

Slide 89

Slide 89 text

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

Slide 90

Slide 90 text

Google Developers Expert @wasabeef_jp wasabeef CyberAgent, Inc.