Slide 1

Slide 1 text

TechCon Official App on Flutter Katsumi Onishi Android Engineer 株式会社ディー・エヌ・エー @katsummy

Slide 2

Slide 2 text

目次 2 DeNA TechCon 2019 Why Flutter ? What New Challenged? Review 1 3 Appendix 4 2

Slide 3

Slide 3 text

3

Slide 4

Slide 4 text

4 DeNAでは、ゲームやエンタメだけでなく、 Eコマース、ソーシャルLIVE、ヘルスケア、オートモーティブ、 そして横浜DeNAベイスターズのようなスポーツなど、様々な事業を行っています。 また、技術の力で事業の未来をリードするため、様々なチャレンジも行っています。 DeNA TechCon はこれらのチャレンジの中から、 技術的に特に面白いものを厳選して皆さんにお披露目するお祭りです。

Slide 5

Slide 5 text

5 今年のテーマは「SHIFT UP」です。 『面白かったー!』と思っていただく工夫を凝らしてお待ちしてますので、 みなさまぜひお越しください!

Slide 6

Slide 6 text

6 12月中旬... Why Flutter ?

Slide 7

Slide 7 text

Why Flutter ? • 12月中旬... • DeNA TechApp 2019 2.6 開催にあたりオフィシャルアプリを作成した い • iOS / Android 両方でリリースしたい • 短納期なのでハイブリッド? • 先日、Flutter 1.0 リリースされた!! • Flutter Live '18 at 4.Nov in London • 新しい技術にチャレンジ! 7

Slide 8

Slide 8 text

What New Challenged? • DeNA の Flutter アプリは初めて • どうせなら普段のアプリできないことをやりたい • マテリアルデザインの新しいコンポーネントを使用 • Backdrop • Flareでアニメーション • PlatformView で Google Map を表示 • 新しいソフトウェアアーキテクチャ • Redux 8

Slide 9

Slide 9 text

What New Challenged? • マテリアルデザインの新しいコンポーネントを使用 • Backdrop - Material Design 9 Back layer Front layer Subheader

Slide 10

Slide 10 text

Backdrop 10

Slide 11

Slide 11 text

Timetable with Fixed Header 11

Slide 12

Slide 12 text

Timetable with Fixed Header 12 Stack Custom ScrollView Custom ScrollView SliverAppBar SliverFixedExtentList ListView ListView タイムテーブルのViewの縦スク ロールを時間のViewにSync

Slide 13

Slide 13 text

FLARE • 2Dimensions社無償公開の2Dのベクターアニメーションツール • エクスポートしたアニメーションをそのままFlutterで再生が可能 13

Slide 14

Slide 14 text

FLARE • Splash 14 2D - denaxtech - Logo

Slide 15

Slide 15 text

FLARE child: Center( child: FlareActor( "assets/animations/Logo.flr", animation: _animationName, fit: BoxFit.contain, callback: (string) { Navigator.of(context) .pushReplacementNamed(AppRoutes.home); }, ), ), 15

Slide 16

Slide 16 text

PlatformView で Google Map • 組み込みは簡単 • google_maps_flutter を使用 • Android のみ実装 • iOS 挙動不安定... • Backdropの影響? 16

Slide 17

Slide 17 text

TechCon Official App 17 16:9

Slide 18

Slide 18 text

What New Challenged? • アーキテクチャー • MultiModule • Flutterでもできる • Redux (Flux) 18 App Architecture (Redux) Repository Common Repository Impl

Slide 19

Slide 19 text

MultiModule 19

Slide 20

Slide 20 text

MultiModule dependencies: flutter: sdk: flutter commons: path: ../commons architecture: path: ../architecture repository: path: ../repository repository_cache: path: ../repository_cache 20

Slide 21

Slide 21 text

Redux • 採用箇所 • Backdrop / TimeTable 21 isLoading activeTab

Slide 22

Slide 22 text

Store Redux 22 Action Widget Middleware Repository State Reducer State ViewModel Dispatch

Slide 23

Slide 23 text

Redux class App extends StatelessWidget { /// Store final Store store = Store( appReducer, initialState: AppState.initial(), middleware: createStoreMiddleware(RepositoryCache()), ); @override Widget build(BuildContext context) { return StoreProvider( store: store, child: MaterialApp( 23

Slide 24

Slide 24 text

Redux /// Reducer final appReducer = combineReducers([ TypedReducer(_onLoading), TypedReducer(_onError), TypedReducer(_onLoadSessions), TypedReducer(_onLoadedSessions), TypedReducer(_onUpdateTab), ]); 24

Slide 25

Slide 25 text

Redux @immutable class AppState { final bool isLoading; final bool hasError; final AppTab activeTab; final List sessions; 25

Slide 26

Slide 26 text

Redux /// Middleware List> createStoreMiddleware(Repository repository) { _repository = repository; return [ TypedMiddleware(_load), ]; } 26

Slide 27

Slide 27 text

Redux /// Sessions Load Future _load(Store store, action, NextDispatcher next) async { // Dispatch a LoadingAction to show a loading spinner store.dispatch(LoadingAction()); // Get session var sessions = await _repository.getSessionList(); store.dispatch(SessionsLoadedAction(sessions)); next(action); } 27

Slide 28

Slide 28 text

Redux class TimeTablePage extends StatelessWidget { @override Widget build(BuildContext context) { return StoreConnector( onInit: (store) => store.dispatch(SessionsLoadAction()), distinct: true, converter: _ViewModel.fromStore, builder: (context, vm) { if (vm.isLoading) { return Center(child: LoadingIndicator()); } else { return TimeTable( sessions: vm.sessions, ); } }, 28

Slide 29

Slide 29 text

• TimeTableWidget は力技感.... • Redux • View と Logicの分離 • State は Storeで一元管理 • View毎に StoreからViewModelを作成が若干手間 • Middleware内でdispatchさせるとnextのactionは...? • 小規模アプリでは... Review 29

Slide 30

Slide 30 text

• 課題 • FCM • 通知 の アプリ内表示 • LicensePage • 内容に重複が多く法務確認が手間 • Flutter Engineのライセンスまで表示される... • skia で使用している gif ライブラリが MPL 1.1/GPL 2.0/LGPL 2.1 トリプルライセンスであるが、LGPL 2.1 のみ表示される。 • CI • [Jan 23, 2019] Flutter CI v.1.0.0 がBitriseに登場! • もっとはやくに... Review 30

Slide 31

Slide 31 text

Appendix 31 ソースコードは公開します! will soon 詳しくはGitHubで!

Slide 32

Slide 32 text

32 テックコン 検索 ブースも出 します!