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

DevFest_2022_What_it_Takes_to_be_a_Flutter_Developer

 DevFest_2022_What_it_Takes_to_be_a_Flutter_Developer

Daichi Furiya (Wasabeef)

January 24, 2023
Tweet

More Decks by Daichi Furiya (Wasabeef)

Other Decks in Programming

Transcript

  1. Tokyo, Japan Daichi Furiya ( Wasabeef ) CyberAgent, Inc. What

    it Takes to be a Flutter Developer
  2. Flutter を書き始める時に役に立つ知識

  3. 02. Android エンジニアが Flutter 始める時に 01. Flutter のこれまでの振り返りと 2023 に向けて

    03. まとめ
  4. 02. Android エンジニアが Flutter 始める時に 01. Flutter のこれまでの振り返りと 2023 に向けて

    03. まとめ
  5. History of Flutter

  6. 1. Windows 2. macOS 3. Linux 〜〜〜〜〜〜〜〜〜〜〜〜 4. Foldable Phone

    5. Web 1. FFI 2. Null Safety 3. Impeller Devices Tools 1. Game Engine (Flame) 2. Firebase (FlutterFire) 3. Material 3 4. FlutterFlow Codes
  7. iOS の描画パフォーマンスの課題

  8. iOS の描画パフォーマンス問題(Shader compilation jank) 現行の Skia ではアプリ初回起動時にシェーダーコンパイルが行われ、初 回起動時は数十フレームの欠落することがあるが、それ以降はキャッシュさ れ滑らかなアニメーションになる。 しかし、Android

    はそれが可能だが iOS の場合はアプリを最初から開くた びに行われてしまう。 (キャッシュファイルを埋め込むこともできるが)
  9. 新しいグラフィックエンジンの 「Impeller」 Skia のパフォーマンス問題を解決するために現在グラフィックエンジンの書 き換えが行われている。それは以下が行われ解決するもの → シェーダーコンパイルをアプリビルド時にオフラインで実行 → アニメーションをキャプチャし、ディスクに永続化 →

    Metal や Vulkan などのモダン API に対応 → 並行処理を効果的に利用
  10. Try Impeller <key>FLTEnableImpeller</key> <true/> <meta-data android:name="io.flutter.embedding.android.EnableImpeller" android:value="true" /> $ flutter

    run --enable-impeller iOS: Info.plist Android: AndroidManifest.xml https://github.com/flutter/flutter/wiki/Impeller Master channel
  11. Wonderous https://flutter.gskinner.com/wonderous/

  12. 02. Android エンジニアが Flutter 始める時に 01. Flutter のこれまでの振り返りと 2023 に向けて

    03. まとめ
  13. android/architecture-templates

  14. https://github.com/android/architecture-templates android/architecture-templates

  15. android/architecture-templates 構成要素 1. Editor, IDE 2. KTS Gradle files 3.

    Version catalog 0. App Architecture 1. Room 2. DI with Hilt 3. Navigation 4. Retrofit, OkHttp 5. Coroutines and Flow 6. Unit tests Build UI Architecture 1. Jetpack Compose
  16. Build 1. Editor, IDE 2. Flutter Version Management 3. Project

    Configuration 3.1. Multi-Module Project 3.2. Assets Management
  17. Editor, IDE

  18. Android Studio || VSCode || Vim

  19. 海外からのアウトプットを見る限りでは VSCode を使ってる人が多そうな印象

  20. Flutter Version Management

  21. Flutter Version Management 2.10 3.0 3.3 チーム開発で各個人環境で実行 バージョンに差異があると挙動に 問題起きやすい

  22. # FVM Install $ brew tap leoafarias/fvm $ brew install

    fvm # Run with FVM $ fvm flutter pub get Flutter Version Management # asdf Install $ brew install asdf # Flutter plugin Install $ asdf plugin add flutter # Run with asdf $ flutter pub get FVM asdf Flutter 専用のバージョン管理ツール (rbenvのようなイメージ) Flutter に限らずマルチランタイムのバージョン管理ツール (anyenvのようにオールインワンのイメージ)
  23. Project Configuration

  24. # Create a new Flutter app $ flutter create my_app

    $ cd my_app # To launch the app in the Simulator $ flutter run Create a Flutter project これだけで flutter コマンドでプロジェクトを作成しシミュレータ等で実行します。
  25. # pubspec.yaml name: material_3_demo description: A Flutter project. publish_to: "none"

    version: 1.0.0+1 environment: sdk: ">=2.17.0-0 <3.0.0" dependencies: flutter: sdk: flutter cupertino_icons: ^1.0.2 dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^2.0.1 flutter: uses-material-design: true pubspec.yaml Flutter Project を作成した際に、プロジェク トルートに pubspec.yaml ファイルが生成さ れているので SDK のバージョン指定、依存 パッケージ、アセットの設定などを指定しま す。
  26. https://pub.dev/ Maven Central のように Google が公式で提供しているパッケージリポジトリ

  27. https://pub.dev/ 同サイトから Google が推奨する パッケージとしてリス ト化している Flutter Favorites や人気な パッケージも検索で

    きる
  28. $ dart pub publish Publish to https://pub.dev/ Maven Central への公開

    ・pom.xml, doc.jar, sources.jar 生成 ・GPU PG Key 生成 ・JIRA のアカウント作成 ・JIRA のチケット作成 ・Maven Central でチェック待ち ・リリース(Drop) pub.dev への公開 ・pub.dev ログイン ・publish コマンド実行
  29. Multi-Module Project

  30. Multi-Module Project Kotlin for Android ではビルド時間の短縮で あったりクラス間の依存関係の明確化を目的に マルチモジュールにすることがありますが Flutter ではマルチモジュール(マルチプラグイ

    ン)にビルド時間の短縮のような効果が得られる わけではありませんし、アプリ開発ではマルチモ ジュールという概念は浸透していません。
  31. # Melos Install $ dart pub global activate melos #

    Run analyze $ melos run analyze # Run a script $ melos run Select a script to run in this workspace: 1) analyze 2) format 3) build_runner 4) build 5) test Melos --> Multi-Module Project Flutter では Melos を使うことでマル チモジュール(マルチプラグイン)の 構成管理が便利になるツールも有志 によって公開されています。 Firebase, AWS, Stripe でも採用され ているので実績があります。 Makefile の置き換えと考えると便利 なものになっています。
  32. # melos.yaml name: App packages: - packages/** scripts: analyze: dart

    analyze format: dart format --set-exit-if-changed . build_runner: run: | melos exec -- dart pub run build_runner build select-package: depends-on: 'build_runner' build: run: | melos exec -- flutter build apk test: run: melos exec -- dart test select-package: dir-exists: test Melos --> Multi-Module Project Flutter では Melos を使うことでマル チモジュール(マルチプラグイン)の 構成管理が便利になるツールも有志 によって公開されています。 Firebase, AWS, Stripe でも採用され ているので実績があります。 Makefile の置き換えと考えると便利 なものになっています。
  33. Melos --> Multi-Module Project Gradle Version Catalog のように各モ ジュールでバージョンを合わせるような機 能は

    Flutter SDK や Melos でも提供され ていないので、注意が必要である。 pubspec.yaml retrofit: 3.0.0 pubspec.yaml retrofit: 3.3.1 pubspec.yaml retrofit: 3.0.0 module1 module2 pubspec.yaml retrofit: 3.3.1 module3 home pubspec.yaml retrofit: 3.3.1 login
  34. Assets Management

  35. R.txt (runtime_symbol_list) Android では `res/` に画像等のリソースを配置 することで AGP がリソースにアクセスすることが 可能ですが、この仕組みを

    Flutter では公式に提 供されていません。
  36. // R.txt int string app_name 0x7f0b0001 int string close_drawer 0x7f0b0002

    int string close_sheet 0x7f0b0003 int animator fragment_close_enter 0x7f020000 int animator fragment_close_exit 0x7f020001 int animator fragment_fade_enter 0x7f020002 int animator fragment_fade_exit 0x7f020003 int animator fragment_open_enter 0x7f020004 int animator fragment_open_exit 0x7f020005 int attr action 0x7f030000 int attr alpha 0x7f030001 int attr argType 0x7f030002 int attr data 0x7f030003 int attr dataPattern 0x7f030004 int attr destination 0x7f030005 int attr enterAnim 0x7f030006 int attr exitAnim 0x7f030007 int attr font 0x7f030008 ................ R.txt (runtime_symbol_list) Android では `res/` に画像等のリソースを配置 することで AGP がリソースにアクセスすることが 可能ですが、この仕組みを Flutter では公式に提 供されていません。
  37. FlutterGen --> R.txt # pubspec.yaml flutter: assets: - assets/images/profile.jpg Widget

    build(BuildContext context) { return Image.asset('assets/images/profile.jpeg'); } // The following assertion was thrown resolving an image codec: // Unable to load asset: assets/images/profile.jpeg Widget build(BuildContext context) { return Assets.images.profile.image(); } Flutter では pubspec.yaml で リソースファイルの指定を行 い、Widget 側で相対パスの 文字列で指定をする必要が あるが、FlutterGen を使うこ とで安全にリソースを指定す ることが出来る。
  38. UI 1. Widgets 2. Side-effects 3. Local State management

  39. Widgets

  40. class HomePage extends StatelessWidget { const HomePage({super.key}); @override Widget build(BuildContext

    context) { return Scaffold( appBar: AppBar( title: const Text('Testing Sample'), actions: [ TextButton.icon( onPressed: () { ... }, icon: const Icon(Icons.favorite_border), label: const Text('Favorites'), ), ], ), body: ListView.builder( itemCount: 100, controller: ScrollController(), padding: const EdgeInsets.symmetric(vertical: 16), itemBuilder: (context, index) => ItemTile(index), ), ); } } Widgets Jetpack Compose と同様に宣言 的 UI フレームワークなので似た ような感覚での記述が可能です。
  41. class HomePage extends StatelessWidget { const HomePage({super.key}); @override Widget build(BuildContext

    context) { return Scaffold( appBar: AppBar( title: const Text('Testing Sample'), actions: [ TextButton.icon( onPressed: () { ... }, icon: const Icon(Icons.favorite_border), label: const Text('Favorites'), ), ], ), body: ListView.builder( itemCount: 100, controller: ScrollController(), padding: const EdgeInsets.symmetric(vertical: 16), itemBuilder: (context, index) => ItemTile(index), ), ); } } Widgets Jetpack Compose と同様に宣言 的 UI フレームワークなので似た ような感覚での記述が可能です。 AppBar --> TopAppBar
  42. class HomePage extends StatelessWidget { const HomePage({super.key}); @override Widget build(BuildContext

    context) { return Scaffold( appBar: AppBar( title: const Text('Testing Sample'), actions: [ TextButton.icon( onPressed: () { ... }, icon: const Icon(Icons.favorite_border), label: const Text('Favorites'), ), ], ), body: ListView.builder( itemCount: 100, controller: ScrollController(), padding: const EdgeInsets.symmetric(vertical: 16), itemBuilder: (context, index) => ItemTile(index), ), ); } } Widgets Jetpack Compose と同様に宣言 的 UI フレームワークなので似た ような感覚での記述が可能です。 TextButton --> Button
  43. class HomePage extends StatelessWidget { const HomePage({super.key}); @override Widget build(BuildContext

    context) { return Scaffold( appBar: AppBar( title: const Text('Testing Sample'), actions: [ TextButton.icon( onPressed: () { ... }, icon: const Icon(Icons.favorite_border), label: const Text('Favorites'), ), ], ), body: ListView.builder( itemCount: 100, controller: ScrollController(), padding: const EdgeInsets.symmetric(vertical: 16), itemBuilder: (context, index) => ItemTile(index), ), ); } } Widgets Jetpack Compose と同様に宣言 的 UI フレームワークなので似た ような感覚での記述が可能です。 ListView --> LazyColumn
  44. Side-effects

  45. Flutter Hooks (Local State Management) React Hooks の Flutter 版で文法も使い方もほぼ一緒。

    ステートの初期化(initState)や破棄 (dispose) をウィジェットと分離ができる。 単純にクラスの定義を減らすシ ンタックスシュガー的な恩恵もある。
  46. useEffect --> DisposableEffect // Flutter useEffect(() => { final subscription

    = source.subscribe(id); return () => { // 破棄される時に実行 subscription.unsubscribe(id); }; }, [id]); 当該の Widget だけで利用するようなものは Flutter Hooks でローカルに状態管理す ることでコードがスッキリする場合があります。 // Jetpack Compose DisposableEffect(id) { val subscription = source.subscribe(id) onDispose { // 破棄される時に実行(Activity破棄など) subscription.unsubscribe(id) } }
  47. // Jetpack Compose LaunchedEffect(id) { // ID が変更されるたび } SideEffect

    { // 毎回 } LaunchedEffect(Unit) { // 最初の一回 } // Flutter useEffect(() => { // ID が変更されるたび }, [id]); useEffect(() => { // 毎回 }); useEffect(() => { // 最初の一回 }, []); useEffect --> LaunchedEffect, SideEffect React Hooks や Flutter Hooks は useEffect の指定の仕方で実行回数がわかれてい る が Jetpack Compose のほうが後発に出来たこともあってか読み取りやすい。
  48. Local State management

  49. // Flutter class CountPage extends HookWidget { @override Widget build(BuildContext

    context) { final count = useState(0); return TextButton( onPressed: () { count.value++; }, child: Text("Count: ${count.value}"), ); } } Flutter Hooks’s useState --> mutableStateOf 当該の Widget だけで利用するようなものは Flutter Hooks でローカルに状態管理す ることでコードがスッキリする場合があります。 // Jetpack Compose @Composable fun Count() { val count = remember { mutableStateOf(0) } Button(onClick = { count.value++ }) { Text("Count: ${count.value}") } }
  50. Architecture 0. App Architecture 1. Dependency injection 2. Networking 3.

    Unit tests
  51. App Architecture

  52. App Architecture ?

  53. App Architecture ? Flutter で推奨されているアプリアーキテクチャは何ですか?

  54. App Architecture ? Flutter で推奨されているアプリアーキテクチャは何ですか? Flutter で推奨されているアプリアーキテクチャは、状態管理パターンとして Model-View-Update (MVU) のアーキテクチャがあります。

    MVU は、状態と ビューのみを管理するシンプルなアーキテクチャで、アプリのロジックを分離 し、テストしやすくすることができます。 MVU のアーキテクチャは、非同期プロ グラミングや React のフレームワークで使われる Redux のアーキテクチャに 似ています。Flutter では、MVU のアーキテクチャを推奨していますが、他の アーキテクチャを使用することも可能です。
  55. Dependency Injection

  56. Riverpod --> Hilt Riverpodは、Dart で状態管理を行うためのライブラリで。容易かつ効率的にアプリケーションの状態管理を行 うことができます。

  57. ここでは簡単なサンプルです が、Riverpod の中心的な機能 に Provider というものあり以下 のような機能が備わっていま す。 ・グローバルの状態管理 ・キャッシング

    ・テスト向けに値のオーバーライド final configurationsProvider = FutureProvider<Configuration>((ref) async { final uri = Uri.parse('configs.json'); final rawJson = await File.fromUri(uri).readAsString(); return Configuration.fromJson(json.decode(rawJson)); }); Riverpod --> Hilt class Example extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final configs = ref.watch(configurationsProvider); return configs.when( loading: () => const CircularProgressIndicator(), error: (err, stack) => Text('Error $err'), data: (configs) => Text('data: ${configs.host}'), ); }
  58. Networking

  59. Dio や dart-lang/http は、クライアント/サーバ通信のための Dart 向け HTTP クライアントライブラリです。 HTTPリクエストを容易かつ効率的に処理することができます。 Dio

    || dart-lang/http --> OkHttp
  60. Retrofit For Dart は Android アプリ開発でよく使われている Retrofit を参考にして作られた Dio 用のクライア

    ントコード生成ライブラリです。 Retrofit For Dart
  61. @RestApi(baseUrl: "https://wasabeef.jp/api/v1/") abstract class RestClient { factory RestClient(Dio dio, {String

    baseUrl}) = _RestClient; @GET("/tasks") Future<List<Task>> getTasks(); @GET("/tasks/{id}") Future<Task> getTask(@Path("id") String id); @PATCH("/tasks/{id}") Future<Task> updateTaskPart( @Path() String id, @Body() Map<String, dynamic> map); } @JsonSerializable() class Task { ... } アノテーションでのパス・パラメー タ指定が出来るので、似たような 感覚で記述ができる。 Retrofit For Dart
  62. Unit test

  63. dart-lang/Mockito --> Mockito, Mockk dart-lang/Mockito は Android アプリ開発でよく使われている Java 用の

    Mockito を参考にして作られたモッ クフレームです。
  64. 02. Android エンジニアが Flutter 始める時に 01. Flutter のこれまでの振り返りと 2023 に向けて

    03. まとめ
  65. 今回の主題である既に Kotlin で Android を作ってる人であればモバイル開発の前提知識 のショートカットが出来つつ Flutter アプリ開発に参入することができます。 また、React を書いている

    Web エンジニアの方々も Flutter に興味もってもらえるとこれま での Kotlin Android に比べて比較的簡単にモバイルアプリ開発に参入することができま す。
  66. Flutter コミュニティの発展のために ブログや Qiita などに投稿された内容に対して強い言葉で全否定の 意見をぶつける → アーキテクチャ等の全否定 ⇨ ブログ数の減少

    ⇨ 初学者が敬遠
  67. Online Communities r/FlutterDev https://discord.com/invite/N7Yshp4 Google Developers Online https://t.co/qXZdmipQpt FlutterDev https://www.reddit.com/r/FlutterDev/

    Flutter Community https://fluttercommunity.slack.com/ Flutter https://twitter.com/i/communities/1472249315724771329
  68. Daichi Furiya @wasabeef_jp Thank you Twitter: @wasabeef_jp GitHub: wasabeef #DevFest2022

    Connect