Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Flutter 2021 の振り返りと今後のアプリ開発に向けて / Looking back ...
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Daichi Furiya (Wasabeef)
December 11, 2021
Programming
2.3k
4
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Flutter 2021 の振り返りと今後のアプリ開発に向けて / Looking back on Flutter 2021 and for future app development.
Daichi Furiya (Wasabeef)
December 11, 2021
More Decks by Daichi Furiya (Wasabeef)
See All by Daichi Furiya (Wasabeef)
DevFest Tokyo 2025 - Flutter のアプリアーキテクチャ現在地点
wasabeef
6
2.9k
About Flutter Architecture
wasabeef
1
340
2023 Flutter/Dart Summary
wasabeef
0
140
I/O Extended 2023 - Dart と Flutter の新機能
wasabeef
0
250
I/O Extended 2023 - Flutter 活用事例
wasabeef
10
3.1k
What it Takes to be a Flutter Developer
wasabeef
0
270
FlutterKaigi 2022 Keynote
wasabeef
1
760
Flutter Hooks を使ったアプリ開発 / App Development with the Flutter Hooks
wasabeef
2
1.6k
Flutter Hooks, sometimes Jetpack Compose
wasabeef
3
1.9k
Other Decks in Programming
See All in Programming
[ハンズオン]AIへの指示だけで「五目並べ」を作ってみよう
satoshi256kbyte
1
300
JAWS-UG 東京支部が始める、JAWS-UG支部コラボ / JAWS-UG lunchtime LT Collaboration
y0hgi
0
170
モジュールの視点からSwiftを読み解く #iosdc
s_shimotori
0
270
TiDB Cloudのカスタムコントローラーによるオートスケール対応
takaidohigasi
0
140
Ghostty + Neovimで作る 透明でカッコ良い開発環境
j341nono
0
150
Embedded Swiftで作る自作USBデバイス によるiOSデバイスの自動テスト / iOSDC Japan 2026 glassfiber
glassfiber
0
150
Starting & Sustaining Code-Based E2E Testing for Non-Coding QA Teams( #jasstniigata )
teyamagu
PRO
1
770
iOSDC2026登壇資料.pdf
riofujimon
0
200
KiroのSpecで「五目並べ」を作ってみる
satoshi256kbyte
1
310
GitHubハンズオン講座 — 実務レベルのチーム開発のフローを身につけよう
junhat6
0
110
MVNOの申込からeSIM開通までをiOSアプリでつなぐ- 本人確認・MNP・通信事業者基盤をまたぐ実装
satotakeshi
0
510
AI Agent時代のリアーキテクチャ戦略と実践
hokaccha
9
5.2k
Featured
See All Featured
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.4k
Site-Speed That Sticks
csswizardry
13
1.5k
Digital Projects Gone Horribly Wrong (And the UX Pros Who Still Save the Day) - Dean Schuster
uxyall
1
3.2k
Fantastic passwords and where to find them - at NoRuKo
philnash
52
3.9k
Bootstrapping a Software Product
garrettdimon
PRO
306
120k
A better future with KSS
kneath
240
18k
Unsuck your backbone
ammeep
672
58k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
11
1k
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
Building an army of robots
kneath
307
47k
Typedesign – Prime Four
hannesfritz
42
3.2k
How to make the Groovebox
asonas
2
2.5k
Transcript
Flutter 2021 ͷৼΓฦΓͱ ࠓޙͷΞϓϦ։ൃʹ͚ͯ Daichi Furiya / Wasabeef CyberAgent,
Inc. Tokyo, Japan
Flutter 2021 ͷৼΓฦΓͱࠓޙͷΞϓϦ։ൃʹ͚ͯ 1. ΫϩεϓϥοτϑΥʔϜͷݱঢ়ͱ՝ 2. 2022 Flutter Λબ͢Δ͔Ͳ͏͔ 3.
Flutter ͱ Dart ͷΞοϓσʔτ 4. Flutter ΞϓϦ։ൃͷࠓޙʹ͚ͯ 4.1. ΞϓϦͷΞʔΩςΫνϟ 4.2. React ͔Βֶͼ͍ͨ͜ͱ
ΫϩεϓϥοτϑΥʔϜ ͷݱঢ়ͱ՝
ΫϩεϓϥοτϑΥʔϜͷݱঢ়ͱ՝ 1. ΫϩεϓϥοτϑΥʔϜͰ։ൃ͢Δલʹ͓͖ͬͯ͘͜ͱ 1. ϝϦοτɾσϝϦοτ 2. Kotlin Multiplatform 3. Compose
Multiplatform 2. Flutter ͷ࠾༻ࣄྫ
ΫϩεϓϥοτϑΥʔϜͰ։ൃ͢Δલʹ͓͖ͬͯ͘͜ͱ
ΫϩεϓϥοτϑΥʔϜͰ։ൃ͢Δલʹ͓͖ͬͯ͘͜ͱ • ΫϩεϓϥοτϑΥʔϜͰ։ൃ͢ΔҙຯΛߟ͑Δ → ԿΛڞ௨Խ͍͔ͨ͠ʁ • ʮͱΓ͋͑ͣ Flutter ͕ྲྀߦͬͯΔΒ͍͔͠Β
Flutter Ͱͬͱ͚ ͍͍ʯͰͳ͍ • ͜Ε·Ͱొ͖ͯͨ͠ଟͷΫϩεϓϥοτϑΥʔϜϑϨʔϜ ϫʔΫ͕ਁಁ͠ͳ͔ͬͨ͜ͱ اۀͱͯ͠औΓΉ߹
ΫϩεϓϥοτϑΥʔϜͰ։ൃ͢ΔҙຯΛߟ͑Δ QɿԿΛڞ௨Խ͍͔ͨ͠ʁ A1ɿϩδοΫ͚ͩڞ௨Խ͢Δ A2ɿUI ϩδοΫڞ௨Խ͢Δ A3ɿࠓϩδοΫ͚ͩͰকདྷతʹ ɹɹ UI ڞ௨Խ͢Δ UI
ϩδοΫ List Button Domain Label Nav Media Notification Sensors Business Logic Networking Database etc.. etc.. Log Utils
ΫϩεϓϥοτϑΥʔϜͰ։ൃ͢ΔҙຯΛߟ͑Δ QɿԿΛڞ௨Խ͍͔ͨ͠ʁ A1ɿϩδοΫ͚ͩڞ௨Խ͢Δ A2ɿUI ϩδοΫڞ௨Խ͢Δ A3ɿࠓϩδοΫ͚ͩͰকདྷతʹ ɹɹ UI ڞ௨Խ͢Δ UI
ϩδοΫ UI + ϩδοΫ
ϝϦοτɾσϝϦοτ
ϝϦοτ • ΤϯδχΞͷϦιʔεઅ • ਓɾ։ൃظؒॖ • ։ൃίϛϡχςΟͷٸతͳ ֦େʢࠃ֎ɺFlutterKaigi ͳͲʣ •
iOS/Android Ͱڞ௨ͷ UI ʢྑ͘ʣ σϝϦοτ • ΞϓϦಈ࡞ͷ҆ఆੑ ʢωΠςΟϒʹྼΔʣ • কདྷੑɺઌߦ͖ෆ҆ ʢͲͷϑϨʔϜϫʔΫΛ࠾༻͢Δ͔ʣ • iOS/Android Ͱڞ௨ͷ UI ʢѱ͘ʣ • iOS/Android ͷ৽ػೳͷ ैͷΕΔ
ΤϯδχΞͷϦιʔεઅ αʔόΤϯδχΞ iOS ΤϯδχΞ Web ΤϯδχΞ Android ΤϯδχΞ Ұൠతͳ Swift/Kotlin
ΞϓϦͷΞαΠϯελΠϧ
ΤϯδχΞͷϦιʔεઅ ΫϩεϓϥοτϑΥʔϜͰͷΞαΠϯελΠϧ ΞϓϦΤϯδχΞ ͱΓ͋͑ͣ1ਓҎ্͍Ε iOS/ Android ΞϓϦ྆ํ։ൃՄೳ αʔόΤϯδχΞ Web ΤϯδχΞ
༨
ΤϯδχΞͷϦιʔεઅ αʔόΤϯδχΞ iOS ΤϯδχΞ Web ΤϯδχΞ Android ΤϯδχΞ Ұൠతͳ Swift/Kotlin
ΞϓϦͷΞαΠϯελΠϧ ϨϏϡʔ͞Εͳ͍ෆ҆
ΤϯδχΞͷϦιʔεઅ ΫϩεϓϥοτϑΥʔϜͰͷΞαΠϯελΠϧ αʔόΤϯδχΞ ΞϓϦΤϯδχΞ Web ΤϯδχΞ ͱΓ͋͑ͣ1ਓҎ্͍Ε iOS/ Android ΞϓϦ྆ํ։ൃՄೳ
ίʔυϨϏϡʔͰ͖ͯ݁Ռͱͯ͠ ্࣭ɻ
iOS/Android Ͱڞ௨ͷ UIʢѱ͘ʣ Flutter ϚςϦΞϧσβΠϯΛ࠾༻͍ͯ͠ΔͷͰɺѱ͘ݴ͏ ͱ iOS ͬΆ͍σβΠϯ͕ଛͳΘΕ͍ͯͨΓ͢Δ͜ͱ͕͋Γ· ͢ɻͨͩɺͦΕ։ൃͷ্ͷͨΊʹσβΠϯγεςϜ
Flutterʢڞ௨ʣͱͯ͠ߟ͑ͨํ͍͍ͱͯ͠ࢥ͍ͬͯ·͢ɻ
iOS/Android Ͱڞ௨ͷ UIʢѱ͘ʣ Cupertino widgets ͋Δఔଘࡏ͢Δ͕ᘳͰͳ͍ͷͰɺiOS Β͍͠σβΠϯʹશʹ ౿ऻ͍ͨ͠߹ΫϩεϓϥοτϑΥʔϜʹ͠ͳ͍ͱ͍͏ͷબࢶࢹʹ͍Ε͍ͨ
কདྷੑɺઌߦ͖ෆ҆ ։ൃݩͷاۀ͕͍͔ʹେ اۀͩΖ͏ͱΤϯδχΞ ίϛϡχςΟʹड͚͕ྑ ͘ͳ͍ͱྲྀߦΒͳ͍
iOS/Android ͷ৽ػೳͷैͷΕʁ ྫ͑ iOS 15ɺAndroid 12 ͷରԠ͕க໋తʹΕ͍ͯͯ։ൃͰ͖ͳ͍ͱ͍͏ײ֮ͳ ͍͕ɺ֤ OS ͷ৽
API ͷΠϯλʔϑΣʔεެ։͕ޙ͍ͰདྷΔͷࣄ࣮ͱͳΓ·͢
Kotlin Multiplatform
Kotlin Multiplatform • JetBrains ʹΑͬͯ։ൃ • UI ͷڞ௨ԽͤͣɺϏδωεϩ δοΫͷڞ௨ԽʹಛԽ͍ͯ͠Δ ʢೝূɺϩάͳͲͷڞ௨Խʣ
• Kotlin Ͱ Backends for Frontends Kotlin/LLVM Kotlin/JVM Kotlin/JVM Kotlin/JS Common code
Compose Multiplatform
Compose Multiplatform • 1.0.0 (Dec 2021) • Jetpack Compose ϕʔεͰ
Jetbrains ʹΑΔ։ൃ • ݩʑ Compose for Desktop ͩͬͨͷ • ݱࡏओʹ Desktop / Web ΞϓϦ͚ʢAndroid Ͱಈ͘ʣ • ݱஈ֊Ͱ iOS ͷެࣜαϙʔτൃද͞Ε͍ͯͳ͍ • άϥϑΟοΫΤϯδϯ Skia Λར༻͍ͯ͠Δ
Skia • άϥϑΟοΫϥΠϒϥϦ • Android, Chrome, Firefox, Blink, Flutter Ͱ࠾༻͞Ε͍ͯΔ
• Skia Vulkan ΛόοΫΤϯυΤϯδϯͱͯ͠มߋՄೳ • Android 9 Ҏ߱ɺσϑΥϧτͷϨϯμϥʔ Skia ʹͳ͍ͬͯΔ ʢ8 ͱ 9 ͰUI͕มΘͬͨͷͦͷͨΊʣɻFlutter ʹ͢ΔͱϨΠ Ϡʔ͕૿͑ΔͷͷϨϯμϥʔಉ͡
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+
Flutter ͷ࠾༻ࣄྫ
Flutter ͷ࠾༻ࣄྫ https://medium.com/flutter/announcing-flutter-2-8-31d2cb7e19f5 5݄ 200,000 ΞϓϦ ↓ 12݄ 375,000 ΞϓϦ
͜͜ 6 ϲ݄Ͱ 1.87 ഒ App Store
2022 Flutter Λબ ͢Δ͔Ͳ͏͔
2022 Flutter Λબ͢Δ͔Ͳ͏͔ 1. ΫϩεϓϥοτϑΥʔϜ͔ʁ֤ϓϥοτϑΥʔϜ͔ʁ 1.1. ΞϓϦͷػೳཁ݅ʁ 1.2. ΤϯδχΞͷಘҙྖҬɺͦͷਓɺظؒʁ 2.
React Native ʁ.NET MAUI ʁ 3. Compose Multiplatform ͷ಄ʁ
ΫϩεϓϥοτϑΥʔϜ͔ʁ֤ϓϥοτϑΥʔϜʢiOS / Androidʣ͔ʁ ɹΫϩεϓϥοτϑΥʔϜɹ ɹ֤ϓϥοτϑΥʔϜʢiOS / Androidʣ • UI ϏδωεϩδοΫ͕
iOS / Android Ͱҧ͏ • ҆ఆͯ͠ΫΦϦςΟ͕ߴ͍ͷ࡞ Γ͍ͨ • iOS / Android ͷܦݧऀ͕͍Δ • εέδϡʔϧʹ༨༟͕͋Δ ྫ ྫ • UI ϏδωεϩδοΫ͕ iOS / Android Ͱಉ͡ • ٕज़ࢿతͳνϟϨϯδΛ͍ͨ͠ • iOS / Android ͷܦݧऀ͕গͳ͍ ʢΤϯδχΞͷ͕গͳ͍ʣ • εέδϡʔϧʹ༨༟͕ͳ͍
ΞϓϦͷػೳཁ݅ʁ
ΞϓϦͷػೳཁ݅ʁ • iOS ͱ Android Ͱ UI ͷମݧ͕શ͘ҧ͏ʁ →
Flutter ཱͪҐஔ͕ UI ϑϨʔϜϫʔΫͳͷͰཁ͕͍݅ͦͦ͋ͬͯͳ͍͔ • ಈըͳͲͷίϯςϯπΛදࣔ͢Δͷʹ DRM ͕ඞཁʁ → Flutter ͚ͩͰ࣮͢Δͷݱஈ֊Ͱ FairPlay ରԠͨ͠ϥΠϒϥϦ͕ͳ͍ • οοΰϦοοΰϦͷΞχϝʔγϣϯ͕͋Δʁ → ύϑΥʔϚϯε͕ωΠςΟϒΑΓྼΔͷͰཁݕূ
ΤϯδχΞͷಘҙྖҬɺͦͷਓɺظؒʁ
ΤϯδχΞͷಘҙྖҬɺͦͷਓɺظؒʁ αʔόΤϯδχΞ Web ΤϯδχΞ ਓΛ૿ͤͣʹͲ͏ʹ͔͠ͳ͍ͱ͍͚ͳ͍߹
ΤϯδχΞͷಘҙྖҬɺͦͷਓɺظؒʁ αʔόΤϯδχΞ ΞϓϦΤϯδχΞ Web ΤϯδχΞ iOS / Android ͕ࣝ΄ͱΜͲͳ͍߹ʹ ผʑʹ࡞ͬͯ྆ํΛಉ࣌ʹϦϦʔε͢Δ
ͷݱ࣮తʹෆՄೳ
ΤϯδχΞͷಘҙྖҬɺͦͷਓɺظؒʁ αʔόΤϯδχΞ ΞϓϦΤϯδχΞ Web ΤϯδχΞ ͜ͷύλʔϯͰ࣮֬ʹΫϩεϓϥοτ ϑΥʔϜ͕༗ޮʹͳͬͯ͘Δ ·ͨɺFlutter ͕ෛ࠴ʹͳΔՄೳੑ͜Ε ·ͰͷΫϩεϓϥοτϑΥʔϜϑϨʔϜ
ϫʔΫʹൺΔͱ͍ʢͱࢥ͏ʣ
React Native ʁ.NET MAUI ʁ
React Native ʁ • Web ํ໘ʹڧ͍ΤϯδχΞ͕͍Δ߹ͳͲͷબࢶ → νʔϜͷಘҙྖҬٕज़ࢿ࢈ʹΑܾͬͯఆ •
ϝϧΧϦ US ͕ React Native Ͱॻ͖ͨ͠Β͍͠ → https://link.medium.com/SNFEPzc1Rlb • Facebook Coinbase Discord Tesla ͱ͍ͬͨ༗໊ͳاۀ࠾༻ → https://reactnative.dev/showcase • npm ʹ͋Δࢿ࢈Λࢧ͑ΔͷڧΈ ʢ༨ஊɿϒϩοΫνΣʔϯؔ࿈ٕज़ React Native ͚ͷ SDK ʹ͔͠ରԠ͍ͯ͠ͳ͍߹͕ଟ͍ʣ
.NET MAUI ʢچ Xamarin.Formsʣʁ • C# ํ໘ʹڧ͍ΤϯδχΞ͕͍Δ߹ͳͲͷબࢶ → νʔϜͷಘҙྖҬٕज़ࢿ࢈ʹΑܾͬͯఆ
• ৽ܕίϩφΠϧε৮֬ೝΞϓϦ Xamarin Λ࠾༻ • .NET MAUI ʹͳΔͱ XML ΛࣙΊએݴత UI Ͱॻ͚Δ • ࣄྫ͕ Flutter React Native ʹൺΔͱগͳ͍
Compose Multiplatform ͷ಄ʁ
Compose Multiplatform ͷ಄ʁ • ಄͢Δ͔͠Εͳ͍͕ɺͦΕ͕ 2022 ʹϞόΠϧ͚ ʹ Production Ready
ʹͳΔՄೳੑ͍ → ݱஈ֊Ͱ iOS ͷਖ਼ࣜαϙʔτ͕ೖ͍ͬͯͳ͍ • ͦͷஅ͕Ͱ͖Δͷ͕͏গ͠ઌʹͳΓͦ͏
• ৽نϓϩδΣΫτ • গਓʢ1ਓʙʣ • গਓͰ྆ϓϥοτϑΥʔ ϜͰϒϥϯσΟϯάͷҰ؏ੑ Λҡ͍࣋ͨ͠ • ͱʹ͔͘ૣ͘ϦϦʔε͍ͨ͠
• ΑΓνϟϨϯδ͍ͨ͠ ྫ ɹFlutterɹ Flutter ͔ʁ Kotlin MPP ͔ʁ+ Compose Multiplatform ͔ʁ ɹKotlin MPPɹ • ৽ن / طଘϓϩδΣΫτ • େਓʢ10ਓʙʣ • iOS/AndroidΞϓϦ։ൃͷਫ਼ ௨͍ͯ͠Δ • ϦεΫΛ͍֤͑ͨϓϥοτ ϑΥʔϜͰ͚ͯσβΠϯΛ ߆Γ͍ͨ ྫ ɹ+ Compose Multiplatformɹ • ݕূʢ৽نʣϓϩδΣΫτ • গਓͰ྆ϓϥοτ ϑΥʔϜͰϒϥϯσΟϯά ͷҰ؏ੑΛҡ͍࣋ͨ͠ • ͱʹ͔͘ૣ͘ϦϦʔεͨ͠ ͍ • কདྷͷٕज़ࢿΛ͍ͨ͠
• UI ϏδωεϩδοΫڞ ௨ԽͰ͖Δ • ࣄྫ͕ଟ͍ • Google Λ৴͍ͯ͡Δ ྫ
ɹFlutterɹ Kotlin MPP + Compose ɹɹɹɹɹɹ Multiplatform • Web / React ϝϯόʔ͕ଟ͍ ʢWeb ͷࢿ࢈Λ͍͍ͨʣ • UI ϏδωεϩδοΫڞ ௨ԽͰ͖Δ • ࣄྫ͕ଟ͍ʢ͕ࠃͷ͍ྼΔʣ • Facebook Λ৴͍ͯ͡Δ • Android / Kotlin ϝϯόʔ͕ ଟ͍ʢKotlin ͷࢿ࢈Λ͍͍ͨʣ • ॳظஈ֊ϏδωεϩδοΫ ͚ͩڞ௨Խ͠ Compose Multiplatform ͕҆ఆͨ͠λ ΠϛϯάͰ UI Λॻ͖͢ύ λʔϯ • Jetbrains Λ৴͍ͯ͡Δ ྫ React Native ྫ 2022 Flutter Λબ͢Δ͔Ͳ͏͔
Flutter ͱ Dart ͷ Ξοϓσʔτ
Flutter 2.8
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
Firebase UI https://link.medium.com/a7Md15TNPlb • ೝূը໘ͷΟδΣοτ • Firebase Auth Λར༻ •
Email, Google, Meta, Twitter, Apple ʹରԠ
Dart 2.15
None
Dart 2.15 1. Isolate class ͷػೳ্ 2. Constructor tear-off s
3. enum ʹ API Ճ 4. ϥΠϒϥϦ։ൃ͚Ͱ pub ʹػೳՃ https://link.medium.com/kZTQCmukPlb
Isolate ͷػೳ্ લఏͱͯ͠ɿDart Ͱ 16ms Λ͑ͯϑϨʔϜϨʔτΛམͱ͢Α͏ͳॲཧΛ͢Δ ߹ʹ Isolate Λར༻ͯ͠ Worker
Isolate Ͱ࣮ߦ͢Δ͜ͱΛਪ͞Ε͍ͯΔ ʢωοτϫʔΫϨεϙϯεΛ͍ͨͩͬͯΔ͚ͩͷΑ͏ͳॲཧͷ߹ͦͷݶΓ Ͱͳ͍ʣ Dart 2.15Ͱ Worker Isolate ͔ΒϝϞϦΛίϐʔͤͣʹ Isolate.exit() Ͱ݁ՌΛ ฦ͢͜ͱ͕Ͱ͖Δɻ Flutter ͷ compute Λطʹར༻͍ͯ͠Δ߹ Flutter 2.8 ͷΞοϓάϨʔυ͢Δ͜ͱͰࣗಈతʹύϑΥʔϚϯε্͕͢Δ https://link.medium.com/kZTQCmukPlb
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
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); }
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);
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 Ͱ͖ΔΑ͏ʹͳͬͨ
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);
ϥΠϒϥϦ։ൃ͚Ͱ pub ʹػೳՃ https://link.medium.com/kZTQCmukPlb 1. ϦϦʔε࣌ʹҙਤ͠ͳ͍ Secrets ؚ͕·Εͯͳ͍͔νΣοΫ 2. ޡͬͯϦϦʔεͨ͠ͷΛ
pub.dev ͔ΒఫճͰ͖ΔΑ͏ʹ
ϦϦʔε࣌ʹҙਤ͠ͳ͍ 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 ʹҎԼΛՃ
pub.dev ͰϦϦʔεΛఫճ https://link.medium.com/kZTQCmukPlb
DartPad
DartPad • React CodeSandbox ͷΑ͏ʹ Web ্Ͱ Dart Flutter
ͷಈ࡞ڥΛ؆୯ʹ༻ҙͰ͖ΔʢCodeSandbox ΄ͲߴػೳͰͳ͍ʣ • Ұ෦ͷطʹ༻ҙ͞Ε͍ͯΔ༗໊ͳύοέʔδར༻͢Δ ͜ͱ͕Ͱ͖ΔʢFirebaseɺhttpɺriverpodɺFlutter Hooks ͳͲʣ
DartPad
Flutter ΞϓϦ։ൃͷࠓޙ ʹ͚ͯʢݸਓࢹʣ
Flutter ΞϓϦ։ൃͷࠓޙʹ͚ͯʢݸਓࢹʣ 1. ΞϓϦͷΞʔΩςΫνϟ 2. React ͔Βֶͼ͍ͨ͜ͱ 2.1. React Hooks
2.2. React ͷΞʔΩςΫνϟ
ΞϓϦͷΞʔΩςΫνϟ
ΞϓϦͷΞʔΩςΫνϟ MVVM Bloc Redux ELM/MVU
Android ΤϯδχΞʹೃ છΈͷਂ͍Ͱ͋Ζ͏ MVVM + Repository Ͱ Flutter ͰͦΕ͕࠷దղͱ ݶΒͳ͍
View Repository ViewModel Local Source Remote Data Source MVVM Repository MVVM + Repository
͜ͷϘλϯͷঢ়ଶཧͲ͏͢Δʁ ςΩετϑΟʔϧυʹԿ͔ ͕ೖྗ͞ΕΔ·ͰϘλϯ ඇ׆ੑʹ͍ͨ͠
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'), ), ], ); } }
ίϯϙʔωϯτ ≒ ViewModelʁ • XML ࣌ͷ Android ͩͱϨΠΞτͷ୯Ґ͕େ͖͔ͬͨ • Flutter
ͰͰ͖Δ͚ͩίϯϙʔωϯτΛখ݁͘͞ʹ࡞ Γ͍ͨ • ϑΝΠϧ૿͑͗͢ΔͷͰίϯϙʔωϯτΛࡉ͔͘͢͠ ͗ͳ͍Α͏ʹ͢Δ͔ʁʢͦͷԘക͕͍͠ʣ
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 ͷൣғΛগ͠େ͖ͯ͘͠ΈΔʁ
؆୯ͳঢ়ଶίϯϙʔωϯτଆͰ͍࣋ͪͨ ʴ ؆୯ʹॻ͖͍ͨ 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++, ); } }
Flutter Hooks
LaunchedEffect(id) { // ID ͕มߋ͞ΕΔͨͼ } SideEffect { // ຖճ
} LaunchedEffect(Unit) { // ࠷ॳͷҰճ } 73 useEffect useEffect(() => { // ID ͕มߋ͞ΕΔͨͼ }, [id]); useEffect(() => { // ຖճ }); useEffect(() => { // ࠷ॳͷҰճ }, const []); Flutter Hooks Jetpack Compose
ViewModel ͔ΒϘλϯͳͲͷঢ়ଶཧΛࠩ͠Ҿ͍͍ͯ͘ͱ ViewModel ͡Όͳ͍͍͔ͯ͘͠Εͳ͍ ↓ MVVM ͡Όͳ͍͔… ʢ࣮ࡍʹଞʹ৭ʑΉͣᙱ͍ͱ͜Ζ͕͋Δʣ ΞʔΩςΫνϟΛߟ͑͢
࠷ۙϨΠϠʔଟ͗͢ΔͬͱݮΒ͍͖͍ͯͨ͠ ↓ Flutter ΞϓϦք۾ͷઃܭ͕ఆ·ͬͯͳ͍͔ΒReact ͔ΒֶͿ͔ ΞʔΩςΫνϟΛߟ͑͢
React ͔Βֶͼ͍ͨ͜ͱ
React ͔Βֶͼ͍ͨ͜ͱʢݸਓࢹʣ 1. React App ͷΞʔΩςΫνϟ 2. React Hooks ͷ͍Ͳ͜Ζ
3. ίϯϙʔωϯτ୯ҐͰͷςετ
• Redux • Recoil • + React Query / SWR
React App ͷΞʔΩςΫνϟ
• 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> }
• react-use react-hooks-testing-library ͔Β Ϣʔεέʔεͦͷςετํ๏ͳͲΛֶΜͰ Flutter ք۾ʹө͢Δ React Hooks
ͷ͍Ͳ͜Ζ
react-use • ศརͳ Custom Hooks ͕ͨ͘͞Μؚ·Ε͍ͯΔ ϥΠϒϥϦ • npm i
react-use ͍͍ͯͬͯ͠͠ɺ Unlicense ͳͷͰҰ෦Λίϐϖ͍͍ͯͬͯ͠
react-use
import { useNetworkState } from 'react-use'; const Demo = ()
=> { const state = useNetworkState(); return ( <pre> {JSON.stringify(state, null, 2)} </pre> ); }; ྫ͑ useNetworkState Λ͏ͱ ͷωοτϫʔΫঢ়ଶΛࢹͯ͠ঢ় ଶ͕มΘͬͨΒϦϏϧυͯ͠Λऔ ಘͰ͖ΔΑ͏ʹ͢Δ react-use
react-hooks-testing-library test('should increment counter', () => { const { result
} = renderHook(() => useCounter()) act(() => { result.current.increment() }) expect(result.current.count).toBe(1) }) ࣗ࡞ Hooks ͷςετΛॻ͘ʹίϯ ϙʔωϯτΛߋ৽͢ΔͨΊͷτϦ ΨʔΛॻ͍ͯ࠶ϨϯμϦϯάͤͨ͞ ΓɺΛߋ৽͢ΔͨΊͷίʔυΛॻ ͍ͨΓ͠ͳ͚Ε͍͚ͳ͔ͬͨͷ Λ؆୯ʹ͔͚ΔΑ͏ʹ͢Δ
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 ͷঢ়ଶΛ֬ೝ͢Δ ᶃ ᶄ ᶅ
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 ͦΕ͘Β͍ ϘΠϥʔίʔυΛݮͰ͖ΔϥΠϒϥϦ ᶃ ᶄ ᶅ
flutter_use ͱ flutter_hooks_testing
·ͱΊ
·ͱΊ • ΫϥΠΞϯταΠυ͕શͯએݴత UI ͷํʹͳͬͯ͘Ε͓ͨ ͔͛Ͱ Flutter Ͱ࡞Δʹͯ͠ React ͔Βֶͯ
Jetpack Compose Ͱ࡞Δʹͯ͠ࢀߟʹͳΔͷ͕ΰϩΰϩͱస ͕͍ͬͯΔ • ֤ݴޠͷҧ͍ͳΜͯࠣࡉͳͷͰ UI ϑϨʔϜϫʔΫΛͦΕͧ ΕֶͿͷ͕େม͚ͩͬͨͲɺ༏͍͠ੈքʹͳ͖ͬͯͨ
Google Developers Expert @wasabeef_jp wasabeef CyberAgent, Inc.