Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Speaker Deck
PRO
Sign in
Sign up for free
Flutter はプロダクション開発に耐えうるのか / Flutter ready for production?
Daichi Furiya (Wasabeef)
October 17, 2020
Programming
34
11k
Flutter はプロダクション開発に耐えうるのか / Flutter ready for production?
Daichi Furiya (Wasabeef)
October 17, 2020
Tweet
Share
More Decks by Daichi Furiya (Wasabeef)
See All by Daichi Furiya (Wasabeef)
DevFest_2022_What_it_Takes_to_be_a_Flutter_Developer
wasabeef
0
9
FlutterKaigi 2022 Keynote
wasabeef
1
320
Flutter Hooks を使ったアプリ開発 / App Development with the Flutter Hooks
wasabeef
2
780
Flutter 2021 の振り返りと今後のアプリ開発に向けて / Looking back on Flutter 2021 and for future app development.
wasabeef
4
1.8k
Flutter Hooks, sometimes Jetpack Compose
wasabeef
2
1.4k
Skia and Skija, Skiko [ja]
wasabeef
1
1.2k
モバイル開発におけるクロスプラットフォームの期待と課題 / Cross-platform expectations and challenges in mobile development
wasabeef
0
290
Repository with Store4 [ja]
wasabeef
2
1k
来年に備えるために Android の知識を網羅する / Looking back on this Android year in preparation for next year.
wasabeef
17
13k
Other Decks in Programming
See All in Programming
Workshop on Jetpack compose
aldefy
0
140
状態ってなに?🙃
taro28
0
260
OSSから学んだPR Descriptionの書き方
fugakkbn
4
120
ポケモンで学ぶiOS 16弾丸ツアー 🚅
giginet
PRO
1
610
eBPF와 함께 이해하는 Cilium 네트워킹
hadaney
3
830
Prácticas de Seguridad en Kubernetes
pablokbs
0
100
あなたと 「|」 したい・・・
track3jyo
PRO
2
1k
花き業界のサプライチェーンを繋げるプロダクト開発の進め方
userlike1
0
100
Functional Data Engineering - A Blueprint for adopting functional principles in data pipeline
vananth22
0
160
TokyoR#103_DataProcessing
kilometer
0
460
はてなリモートインターンシップ2022 Web API 講義資料
hatena
0
150
Circuit⚡
monaapk
0
200
Featured
See All Featured
Why You Should Never Use an ORM
jnunemaker
PRO
49
7.9k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
318
19k
From Idea to $5000 a Month in 5 Months
shpigford
374
44k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
44
14k
A Modern Web Designer's Workflow
chriscoyier
690
180k
Three Pipe Problems
jasonvnalue
89
8.9k
Navigating Team Friction
lara
176
12k
How To Stay Up To Date on Web Technology
chriscoyier
779
250k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
236
1.1M
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
24
4.5k
Making the Leap to Tech Lead
cromwellryan
116
7.6k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
500
130k
Transcript
Flutter はプロダクション開発に耐 えうるのか Google Developers Expert @wasabeef_jp wasabeef CyberAgent, Inc.
Flutter はプロダクション開発に耐えうるのか
• Flutter でプロダクトを作るという判断 • モバイルアプリの開発の現状と課題 • クロスプラットフォームの期待と課題 • アプリ開発で必要な要素 •
アーキテクチャ • ライブラリ • その他 今日話すこと
Flutter でプロダクトを作るという判断
• モバイルアプリ開発の現状と課題 • クロスプラットフォームの期待と課題 Flutter でプロダクトを作るという判断
モバイルアプリ開発の現状と課題
• モバイルアプリ開発は成熟期でもあるので、致命 的な課題もなく可もなく不可もない現状。 • Jetpack Compose/Swift UI などの宣言的な UI を構築できる仕組みが来年くらいから安定化され
るたらまた大きな変化が起きるかもしれない。 現状
過去 〜 Android アプリ開発の黎明期 RetroLambda MVC VOLLEY JUICE ActionBarSherlock Timber
現在 〜 Android アプリ開発の成熟期 DAGGER2 MVVM FLUX Timber
現在 〜 Android アプリ開発の成熟期 Activity/Fragment Repository ViewModel LiveData Local Source
Room/DataStore Remote Data Source Retrofit/okHttp Jetpack Jetpack Jetpack Dagger Hilt Android Studio ここでいう成熟のイメージは アーキテクチャ論争、パフォー マンス改善手法確立がひと段落 し、それらの知見が一般化した 状態であり、アプリ開発(コー ド)の簡略化・テンプレート化 に向かっていることとする。
Jetpack Compose などの宣言的な UI の手法を採 用したことによるパラダイムシフトと、それによる 今後の影響は…? MVVM から Flux/Redux/MVU
のような状態管理 への移行もあるかもしれない。 宣言的 UI による VIEW のパラダイムシフト
• Android エンジニアの不足?(なんかこれ話題が今週プチバズってた?) • iOS/Android の機能仕様ずれ (SDKやライブラリの差、認識ずれ、、) • 開発期間の長期化(良くも悪くも) 課題
Android エンジニアの不足 ※ 事例 即戦力の中途採用は年間 1 人するのも大変な状態であり、未経験や若 手の育成を重視する方向性にシフトしつつある。 + 10
ਓ Android Λ࠾༻ʁ iOS 50 ਓ Android 40 ਓ
ポジショントーク(仮) iOSエンジニア or Androidエンジニア? Swift or Kotlin ? Flutter or
React Native?
クロスプラットフォームへの期待と課題
• アプリ動作の安定性 (クロスプラットフォーム <<= ネイティブ) • 将来性、先行き不安 • iOS/Android で共通の
UI(悪くも) • iOS/Android の新機能への追従の遅れ? • Flutter と Kotlin MPP のどちらを採用するか? 課題
将来性、先行き不安 開発元の企業がいかに大 企業だろうとエンジニア コミュニティに受けが良 くないと流行らないとい うことがわかりました。
• 世界的に200万人以上のエンジニアが Flutter を使って いて毎月10%増加している • 利用数上位5地域は インド、中国、米国、EU、ブラジル • Google
Play に既に100,000個、毎月10,000個以上の Flutter アプリがアップされている 事例 https://medium.com/flutter/flutter-spring-2020-update-f723d898d7af
Flutter の採用事例(国内)
• 2018 年 6 月サービス開始 (Flutter stable 1.0 のリリースは2018年 12
月) • 担当アプリエンジニア 2 人 REQU
Flutter の採用事例(国外)
• アリババ傘下のフリマアプリ • カメラ機能で商品検索 • アプリ評価 ★ 4.6 DAU 2000万
• Flutter 事例でユーザ数が世界最大級 ༽ (Idle Fish)
iOS/Android で共通の UI(悪くも) Flutter はマテリアルデザインを採用しているの で、悪く言うと iOS っぽいデザインが損なわれてい たりすることがあります。ただ、それは開発速度の 向上のためにデザインシステムは
Flutter (共通) と して考えた方いいとして思っています。
iOS/Android で共通の UI(悪くも) https://flutter.dev/docs/development/ui/widgets/cupertino Cupertino widgets もある程度存在するが完璧ではないので、iOS らしいデ ザインに完全に踏襲したい場合は、Flutter 以外の選択肢も視野にいれたい。
iOS/Android の新機能への追従の遅れ? 例えば最近の iOS 14、Android 11 への対応は Flutter 1.22.0 でも改善され
ていますし、致命的には対応が遅れてないという個人的な感覚はあるが、各 OS の新 API のインターフェース公開が後追いで来るのは事実です。
• アプリ動作の安定性がかなり向上 (60 fps) • エンジニアのリソース節約 • 開発期間短縮 • 2020年、開発コミュニティの急速的な拡大
• iOS/Android で共通の UI(良くも) 期待
エンジニアのリソース節約 サーバエンジニア iOS エンジニア Web エンジニア Android エンジニア 一般的な Swift/Kotlin
アプリのアサインスタイル
エンジニアのリソース節約 Flutter ͷΞαΠϯελΠϧ アプリエンジニア とりあえず1人以上いれば iOS/ Android アプリ両方開発可能 サーバエンジニア Web
エンジニア 余剰
エンジニアのリソース節約 サーバエンジニア iOS エンジニア Web エンジニア Android エンジニア 一般的な Swift/Kotlin
アプリのアサインスタイル それぞれ一人の場合、 コードレビューされない ケースも...
エンジニアのリソース節約 Flutter ͷΞαΠϯελΠϧ サーバエンジニア アプリエンジニア Web エンジニア とりあえず1人以上いれば iOS/ Android
アプリ両方開発可能 コードレビューできて結果として 品質向上も。
Flutter と Kotlin MPP のどちらを採用するか?
• Google によって開発 • 2018 年 12 月リリース (BREAKING CHANGES
はありえる) • Dart • ステートフルホットリロード (高速開発) • UI ツールキット(豊富なウィジェット) Flutter
• グラフィックライブラリ • Android, Chrome, Firefox, Blink, Flutter で採用されている •
Skia は Vulkan をバックエンドエンジンとして変更可能 • Android 9 以降、デフォルトのレンダラーは Skia になってい る(8 と 9 でUIが変わったのはそのため)。Flutter にする とレイヤーが増えるもののレンダラーは同じ Skia
対応プラットフォーム • Windows 7, 8, 8.1, 10 • macOS 10.10.5
or later • iOS 8 or later • Android 4.1 (JellyBean) or later • Ubuntu 14.04+, Debian 8+, openSUSE 13.3+, or Fedora Linux 24+ もちろん iOS でも Windows でも動作する Skia
• Swift/Kotlin で良い体験をしてしまったエンジ ニアには Dart の言語実装が足りない。 (Data class, Nested Class,
Enum Custom Value, Switch expression, protected, alias..) • アーキテクチャの議論が活発(良くも悪くも) • 各 SaaS の SDK が無い場合がある Flutter の難点
Flutter だけだと解決できない例 • 各 SaaS や広告計測系などの Flutter SDK 対応が間に合ってない 場合は自分でラッパー相当を実装する必要があり、その時は
Kotlin/Swift の知識が必要になる。 • どうしても Flutter からだとコールできない OS 側の機能を使い たい時には PlatformView を使い Flutter アプリ内のウィジェッ トの一部だけをネイティブにすることは出来るが、DRM などの 一部制限があるようなものではそれも出来ない。 例
Flutter だけだと解決できない例 例えばこのアプリが Flutter で作ら れてるとして、動画部分に DRM で HW Secure
Decoder を使っている ような場合には PlatformViewを 使ったとしても Flutter から呼び出 すのは出来ない。
Flutter だけだと解決できない例 Flutter から MethodChannel API 経由で iOS/Android 側で 実装された画面をまるまる表示
することが出来るデザインだと 解決が可能になる
Flutter <-->- iOS/Android Flutter から MethodChannel API 経由で iOS/Android 側で
実装された画面をまるごと表示 することが出来るデザインだと 解決が可能になる
Flutter <-->- iOS/Android ウィジェットの一部分だけを 各 OS 側のものを使うのは出来 ないが各 OS の
API を呼び出 したり、画面まるごと起動した りは出来る。
Flutter <-->- iOS/Android Flutter (Dart code) Android (Kotlin code) iOS
(Swift code) Activity を起動 ViewController を起動
• JetBrains によって開発 • UI の共通化はせず、ビジネスロジックの共通化 に特化している(認証、ログなどの共通化) • Kotlin で
Backends for Frontends Kotlin Multiplatform
JetBrains の野望として はクラサバのロジックを 全て共通化すること。将 来的には UI にも手を出 しそうな情報を小出しし ている。 Kotlin
Multiplatform Kotlin/LLVM Kotlin/JVM Kotlin/JVM Kotlin/JS Common code
• iOS エンジニアコミュニティに刺さってない • iOS のエンジニアも Kotlin と Gradle を覚えない
といけない Kotlin Multiplatform の難点
iOS (arm32, arm64, simulator x86_64) macOS (x86_64) Android (arm32, arm64)
Windows (mingw x86_64, x86) Kotlin/Native - Target Platforms Linux (x86_64, arm32, MIPS, MIPS LE, Raspberry Pi) WebAssembly (x86_64)
Flutter か? Kotlin MPP か? Flutter か? Kotlin MPP か?
Flutter か? Kotlin MPP か? • ゼロから作る新規プロジェクト?
Flutter か? Kotlin MPP か? • ゼロから作る新規プロジェクト? • 既存プロジェクトのリアーキテクチャ?リプレイス?
Flutter か? Kotlin MPP か? • ゼロから作る新規プロジェクト? • 既存プロジェクトのリアーキテクチャ?リプレイス? •
アプリ開発に当てれるエンジニアの人数は?
Flutter か? Kotlin MPP か? • ゼロから作る新規プロジェクト? • 既存プロジェクトのリアーキテクチャ?リプレイス? •
アプリ開発に当てれるエンジニアの人数は? • エンジニアの技術レベル感は?
Flutter か? Kotlin MPP か? • ゼロから作る新規プロジェクト? • 既存プロジェクトのリアーキテクチャ?リプレイス? •
アプリ開発に当てれるエンジニアの人数は? • エンジニアの技術レベル感は? • 安定的な技術志向か?リスクをとった挑戦志向か?
Flutter か? Kotlin MPP か? • ゼロから作る新規プロジェクト? • 既存プロジェクトのリアーキテクチャ?リプレイス? •
アプリ開発に当てれるエンジニアの人数は? • エンジニアの技術レベル感は? • 安定的な技術志向か?リスクをとった挑戦志向か? • プロジェクト・プロダクトのスケールを強く意識するか?
Flutter か? Kotlin MPP か? • ゼロから作る新規プロジェクト? • 既存プロジェクトのリアーキテクチャ?リプレイス? •
アプリ開発に当てれるエンジニアの人数は? • エンジニアの技術レベル感は? • 安定的な技術志向か?リスクをとった挑戦志向か? • プロジェクト・プロダクトのスケールを強く意識するか? • とにかく早くリリースしたい?
Flutter か? Kotlin MPP か? • ゼロから作る新規プロジェクト? • 既存プロジェクトのリアーキテクチャ?リプレイス? •
アプリ開発に当てれるエンジニアの人数は? • エンジニアの技術レベル感は? • 安定的な技術志向か?リスクをとった挑戦志向か? • プロジェクト・プロダクトのスケールを強く意識するか? • とにかく早くリリースしたい?
Flutter か? Kotlin MPP か? Flutter Kotlin MPP • 新規プロジェクト
• 少人数(1〜4人) • 少人数でも両プラットフォーム でブランディングの一貫性を維 持したい • とにかく早くリリースしたい • よりチャレンジしたい • 新規/既存プロジェクト • 大人数(10人〜) • iOS/Androidアプリ開発の精 通している • リスクを抑えたい • 各プラットフォームで分けて デザインを拘りたい 例 例
Flutter か? Kotlin MPP か? 結論 プロダクトの仕様、プロジェクトの規模、エンジニアの 能力によって様々なケースがある。という結論
Hello World のその先へ
アプリ開発で必要な要素
• アーキテクチャ • ライブラリ • アーキテクチャを実現するための • カスタムウィジェットを表現するための • その他
アプリ開発で必要な要素
Architecture
Architecture それぞれのアーキテクチャが目 指していることが違うので、シ ステムのライフサイクルによっ て相性の良し悪しはあります。 ただ、それが絶対的な正解はあ りません。チームの成熟度や趣 味思考を考えた結果であれば、 何を選んでも良いと思います し、自分で新たに生み出すのも
良いと思います。 MVVM Bloc Redux ELM/MVU
MVVM + Repository View Repository ViewModel Local Source Remote Data
Source このスライドでは Android エンジニアの馴 染みが一番あるであろう MVVM + Repository を 例として取り上げていこ うと思います。 MVVM Repository
MVVM UI の実装において、例えばテキストを入力し、バリーデーション、データを保持し、ボタン をタップして、サーバに送信するようなコードを View に全て追加していくと UI が複雑に なっていった時には更にコードが肥大化してしまい、それは UI
とプレゼンテーションロジッ クとビジネスロジックの密結合になっているのでメンテナンスが大変ですし、テストを書く が困難に思えます。 そこで必要になってくる概念が関心の分離 (SoC) です。 簡単に説明す ると全てのアーキテクチャ共通して言えることですが、何をさせたいのか?その役割によっ て分離した構成要素とすることです。
MVVM MVVM は Model–View–ViewModel のことを指し、その構成要素の基本形は以下となっています。 • View は UI (Widget)
を描画(出力)し、ユーザからの入力データを受け取ります。 • ViewModel は View から入力された状態(データ)を適切に変換して Model として持ちます。 また、Model の状態(データ)を View 渡して画面の更新を促します。 • Model は状態(データ)を保持し、それがどう変換されて画面に描画されるかは知りません。
Repository Repository Local Source Remote Data Source Repository pattern はデータソース
へのアクセスを抽象化するためのデ ザインパターンです。ViewModel が 持つことになりますが、ViewModel 側からすると Repository とデータ の形式だけを取り決めるだけで、入 手先がサーバからなのか、ローカル の DB なのか、オンメモリなのかな どは知りません。
MVVM + Repository View Repository ViewModel Local Source Remote Data
Source Android で現在一般的な アーキテクチャは MVVM に Repository Pattern を合わせた設計 となっています。 MVVM Repository
DI/Service Locator
DI/Service Locator View Repository ViewModel Local Source Remote Data Source
DI/SL クラス間の密結合を減らして、 再利用性を高めるための手法。 すごくポピュラーな例をいうと テスト書きたいので、テスト実 行時はサーバ API を叩くので はなくて、モックデータを読み 込むような処理に変えたいがた めに使います。 (テスタビリティの向上)
主な DI/Service Locator のパッケージ InheritedWidget Riverpod package • Flutter SDK
に内包 • BuildContext が必要 • 子ウィジェットからでも O(1) でオブジェクトが取得できる • 少しローレベルなクラス • 有名な方が個人開発 • 新しい Provider でシンプル • まだ安定版ではない • 今や Dagger みたいな位置付 • コンパイルセーフ • Flutter に依存せずにも使える https://github.com/rrousselGit/river_pod https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html
Riverpod # pubspec.yaml dependencies: flutter_riverpod: ^0.11.x pubspec.yaml に依存関係を追加して、flutter pub get
をする https://github.com/rrousselGit/river_pod $ flutter pub get
Riverpod https://github.com/rrousselGit/river_pod final myNotifierProvider = ChangeNotifierProvider((_) { return MyNotifier(); });
class MyNotifier extends ChangeNotifier { int count; /// TODO: typical ChangeNotifier logic } この例では ChangeNotifier を継承した MyNotifier を Riverpod に管理しても らいます。Riverpod には ChangerNotifierProvider というものが用意されてい るので、そこで MyNotifier のインスタンスを返却します。
Riverpod https://github.com/rrousselGit/river_pod main.dart にて、MyApp を Riverpod のクラスである ProviderScope で囲いま しょう。このスコープの設定がないとランタイムエラーになります。
void main() { runApp( const ProviderScope(child: MyApp()), ); }
Riverpod https://github.com/rrousselGit/river_pod class MainPage extends ConsumerWidget { @override Widget build(BuildContext
context, ScopedReader watch) { final count = watch(myNotifierProvider); return Text(count.toString()); } } Riverpod の ConsumerWidget を継承したウィジェット内であれば、シンプル に値の監視をすることができます。MyNotifier の値が変わっていれば、この build が再実行されます。
State management
State management View Repository ViewModel Local Source Remote Data Source
DI 主に View とViewModel 間 で状態の共有を行うことが 目的となっています。View 側は状態が変わったことを 知りたいので ViewModel から通知をもらうようなイ メージになります。
State management 右の簡単なアプリを例にします。 このアプリはカタログとカートに画面 が分かれています。各アイテムの [ADD] をタップすることで、カート にアイテムが追加される想定です。 https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple
State management そのウィジェットツリーを表現するとこ のようになっており、それぞれクラスが 分かれていたとします。 [ADD] ボタン自体は MyListItem クラス が制御を管理しているので、どうやって
MyCart クラスに通知するかを考えないと いけません。 Observable に該当する仕組みが必要で す。 https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple
State management https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple そのウィジェットツリーを表現するとこ のようになっており、それぞれクラスが 分かれていたとします。 [ADD] ボタン自体は MyListItem クラス
が制御を管理しているので、どうやって MyCart クラスに通知するかを考えないと いけません。 Observable に該当する仕組みが必要で す。
State management ChangeNotifier StateNotifier package • Flutter SDK に内包 •
状態を複数管理できる • 割と自由にできる • その状態は Mutable • 状態の変更を通知できる • Riverpod に合わせて使える • 有名な方が個人開発 • ValueNotifier の進化版 • 状態(state)を一つだけ管理 • その状態は Immutable • 状態の変更を通知できる • Freezed で copyWith を自動 生成してもらうと良い • Riverpod に合わせて使える Android の LiveData のような役割
ChangeNotifier を継承した ViewModel final homeViewModelNotifierProvider = ChangeNotifierProvider( (ref) =>= HomeViewModel(repository:
ref.read(newsRepositoryProvider))); class HomeViewModel extends ChangeNotifier { HomeViewModel({@required NewsRepository repository}) : _repository = repository; final NewsRepository _repository; News _news; News get news =>= _news; Future<void> fetchNews() async { _news = _repository.getNews(); notifyListeners() } } 全体的に少しシンプルにしてありますが、HomeViewModel は ChangeNotifier を継承します。
ChangeNotifier を継承した ViewModel final homeViewModelNotifierProvider = ChangeNotifierProvider( (ref) =>= HomeViewModel(repository:
ref.read(newsRepositoryProvider))); class HomeViewModel extends ChangeNotifier { HomeViewModel({@required NewsRepository repository}) : _repository = repository; final NewsRepository _repository; News _news; News get news =>= _news; Future<void> fetchNews() async { _news = _repository.getNews(); notifyListeners() } } StateNotifier の場合は管理対象の状態は state を実装が必要になりますが、ChangeNotifier は特に何も。
ChangeNotifier を継承した ViewModel final homeViewModelNotifierProvider = ChangeNotifierProvider( (ref) =>= HomeViewModel(repository:
ref.read(newsRepositoryProvider))); class HomeViewModel extends ChangeNotifier { HomeViewModel({@required NewsRepository repository}) : _repository = repository; final NewsRepository _repository; News _news; News get news =>= _news; Future<void> fetchNews() async { _news = _repository.getNews(); notifyListeners() } } Repository で取得したデータを格納しただけでは、リスナーに通知はされません。
ChangeNotifier を継承した ViewModel final homeViewModelNotifierProvider = ChangeNotifierProvider( (ref) =>= HomeViewModel(repository:
ref.read(newsRepositoryProvider))); class HomeViewModel extends ChangeNotifier { HomeViewModel({@required NewsRepository repository}) : _repository = repository; final NewsRepository _repository; News _news; News get news =>= _news; Future<void> fetchNews() async { _news = _repository.getNews(); notifyListeners() } } notifyListeners() をコールすることで、通知がいきます。
ChangeNotifier を継承した ViewModel class MainPage extends ConsumerWidget { @override Widget
build(BuildContext context, ScopedReader watch) { final news = watch(homeViewModelNotifierProvider); return Text(news.title); } } 先ほどの Riverpod の説明のところで紹介したものと同じです。
Networking
Networking View Repository ViewModel Local Source Remote Data Source DI
主に Remote Data Source でサーバの API を叩くために Endpoint, Header, Token, Body の制 御を行います。
主な Http client のパッケージ http package dio package • 公式に
Google が開発 • メンテは活発 • シンプルな Http client で単純 なことをやるならこれでも十分 • Flutter China コミュニティ が開発(主に一人) • メンテが若干不安 • 機能が豊富で Cancel, Cache や Cookie の制御や retrofit like なジェネレータもある • で人気がある https://github.com/flutterchina/dio https://github.com/dart-lang/http
dio + Cache https://github.com/flutterchina/dio # data_source.dart import 'package:dio/dio.dart'; @override Future<News>
getNews() async { return _dio.get<Map<String, dynamic>>>( '/v1/wasabeef', queryParameters: <String, String>{ 'apiKey': 'VEhJUyBJUyBBUElLRVk', }, options: buildCacheOptions(const Duration(hours: 1)), ) .then((response) =>= News.fromJson(response.data)); } # pubspec.yaml dependencies: dio: ^3.x.x dio_http_cache: ^0.2.x 何かしら他の分野でも Http client を使ったこと ある人であれば理解は難し くないと思います。
Serializable/Deserialize
Serializable/Deserialize View Repository ViewModel Local Source Remote Data Source DI
特にサーバ API 通信で使 われる送受信したデータを シリアライズとデシリアラ イズ。
主な Serializable/Deserialize のパッケージ json_serializable package Freezed package • 公式に Google
が開発 • アノテーションを元に自動生成 • to/from JSON • 有名な方が個人開発 • json_serializable のサポートし ている • アノテーションを元に自動生成 • toString, hashCode.. • copyWith • Immutable https://github.com/rrousselGit/freezed https://github.com/google/json_serializable.dart
Freezed part 'article.freezed.dart'; part 'article.g.dart'; @freezed abstract class Article with
_$Article { factory Article({ @required Source source, String author, @required String title, @required String description, @required String url, String urlToImage, @required DateTime publishedAt, String content, }) = _Article; factory Article.fromJson(Map<String, dynamic> json) =>= _$ArticleFromJson(json); } この例では、@freezed アノ テーションをつけて、 _$Article (自動生成されるク ラス)の mixin を適用していま す。 Freezed は json_serializable にも対応しているので、 _$ArticleFromJson のイン ターフェースも生成されていま す。 https://github.com/rrousselGit/freezed
Assets/Fonts
Assets/Fonts View Repository ViewModel Local Source Remote Data Source DI
アプリ内で画像やフォ ントなどのファイルを 使いたい場合の設定を 説明していきます。
Assets - ローカル画像ファイルへのアクセス # pubspec.yaml flutter: assets: - assets/images/ -
assets/images/icons/ pubspec.yaml に画像ファイルを置いたところのパスを assets: に指定します。 ディレクトリを指定した場合は、そのディレクトリ内は全て精査されますが、サ ブディレクトリ内までを再帰的には精査しません。
Assets - ローカル画像ファイルへのアクセス デバイスのピクセル密度毎によって 2.0x, 3.0x のディレクトリに配置します。 ※pubspec.yaml に指定する必要はありません。
Android (AAPT) の R.java に該当するもの が Flutter の世界では公式にはなく、画像な どのリソースへのアクセスはファイルパスを 文字列で
”assets/images/profile.jpg” で指定 しないといけません。 Assets - ローカル画像ファイルへのアクセス
Assets - ローカル画像ファイルへのアクセス /// main.dart Widget build(BuildContext context) { return
Image.asset(‘assets/images/icons/profile.jpg'); } 例えば、Image class にローカルの画像を指定したい場合には以下のようにパス を指定します。
Assets - ローカル画像ファイルへのアクセス /// main.dart Widget build(BuildContext context) { return
Image.asset(‘assets/images/icons/profile.jpg'); } ただ、文字列で指定するのはとてもタイプセーフだと言えず R.java って良くで きた仕組みだなぁって感じることとなります。。
Fonts - ローカルフォントへのアクセス # pubspec.yaml flutter: fonts: - family: RobotoMono
fonts: - asset: assets/fonts/RobotoMono-Regular.ttf - asset: assets/fonts/RobotoMono-Bold.ttf weight: 700 好きな Fonts を使いたい場合にも pubspec.yaml に指定が必要となります
Fonts - ローカルフォントへのアクセス /// main.dart Widget build(BuildContext context) { return
Text( 'Hi there', style: TextStyle( fontFamily: 'RobotoMono', ), } フォントもファミリー名を文字列で指定します。
もしタイポしていた場合 拡張子が間違っていたなどのタイポ(❌ jpeg、⭕ jpg)でも ランタイムエラーになるので、気をつけないといけません。 The following assertion was thrown
resolving an image codec: Unable to load asset: assets/images/profile.jpeg /// main.dart Widget build(BuildContext context) { return Image.asset(‘assets/images/icons/profile.jpeg'); }
R.java, R.swift, SwiftGen, FlutterGen プロモーションを含みます
FlutterGen /// main.dart Widget build(BuildContext context) { return Image.asset(‘assets/images/icons/profile.jpg'); }
FlutterGen を使えば、コマンド一つでタイプセーフにクラスを自動生成します プロモーションを含みます /// main.dart Widget build(BuildContext context) { return Assets.images.profile.image(); }
FlutterGen /// main.dart TextStyle(fontFamily: FontFamily.robotoMono), フォントも自動生成されます /// main.dart TextStyle(fontFamily: 'RobotoMono')
プロモーションを含みます
FlutterGen プロモーションを含みます FlutterGen https://github.com/FlutterGen/flutter_gen さらに詳しく知りたい場合は
Test
Mockito /// Real class class Dog { String sound() =>=
"Woof"; } /// Mock class class MockCat extends Mock implements Cat {} test('Dog Sound Test', () async { var dog = MockDog(); dog.sound(); verify(dog.sound()); when(dog.sound()).thenReturn("Grrrr"); expect(dog.sound(), "Grrrr"); }); https://github.com/dart-lang/mockito Android アプリ開発 でもよく使われるモッ ク化ライブラリの Mockito の Dart 版 が Google 公式とし て公開されているの で、最初はこのパッ ケージを導入してみる ことをお勧めします。
Lint/Analyze
複数人でプロダクション開発していく上では 特に、コードの可読性や保守性を保つために はコード規約に則って維持していくことが当 たり前の時代になりました Lint/Analyze
Effective Dart style # main.dart library peg_parser.source_scanner; import 'file_system.dart'; import
'slider_menu.dart'; # main.dart library pegparser.SourceScanner; import 'file-system.dart'; import 'SliderMenu.dart'; 例:Lower snake case でディレクトリやファイル名をつけること。
Linter, Analyzer 設定 プロジェクトルートに analysis_options.yaml を作成することでルールの設定が可能になります # analysis_options.yaml analyzer: exclude:
- "**/*.g.dart" strong-mode: implicit-casts: false implicit-dynamic: false ..... linter: rules: - camel_case_types .....
effective_dart style Effective Dart に準拠 した Lint ルール Linter, Analyzer
設定 pedantic style Google 内部で採用され ている Lint ルール flutter style Flutter analyze コマン ドで適用されている Lint ルール https://dart-lang.github.io/linter/lints/index.html
Flutter Architecture Blueprints プロモーションを含みます https://github.com/wasabeef/flutter-architecture-blueprints これらのサンプルコードを見たい方は
References * Docs https://flutter.dev/ * Samples https://github.com/brianegan/flutter_architecture_samples * Images https://unsplash.com/
https://www.irasutoya.com/
@wasabeef_jp wasabeef