Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
アプリ開発の新たな選択肢が登場!Google社製Flutterのご紹介
Search
アシアル株式会社
June 24, 2019
Technology
0
670
アプリ開発の新たな選択肢が登場!Google社製Flutterのご紹介
2019年6月25日(火)開催のアシアル技術セミナーでの発表資料
アシアル株式会社
June 24, 2019
Tweet
Share
More Decks by アシアル株式会社
See All by アシアル株式会社
大学オリジナルのデジタル学生証アプリ「MyCampus」のご紹介資料
asial_corp
0
30
第2回全国商業高校Webアプリコンテスト説明会(2024年3月版)
asial_corp
0
140
第1回全国商業高校Webアプリコンテスト総括
asial_corp
0
530
6ヶ月間の授業でここまでできた。コンテスト参加に向けての授業内容と生徒の様子を紹介!
asial_corp
0
470
アプリ開発を目指した授業づくりについて
asial_corp
0
500
train20231223_mainslide.pdf
asial_corp
0
610
Monaca Education 活用事例セミナー:「Monacaでゲームプログラミング~作品制作事例~」
asial_corp
0
1.2k
おみくじアプリのスライド_20230719版
asial_corp
0
590
2023年度第二弾無料導入説明会
asial_corp
0
500
Other Decks in Technology
See All in Technology
サービスでLLMを採用したばっかりに振り回され続けたこの一年のあれやこれや
segavvy
2
590
pg_bigmをRustで実装する(第50回PostgreSQLアンカンファレンス@オンライン 発表資料)
shinyakato_
0
120
AWS re:Invent 2024 ふりかえり勉強会
yhana
0
590
事業貢献を考えるための技術改善の目標設計と改善実績 / Targeted design of technical improvements to consider business contribution and improvement performance
oomatomo
0
170
プロダクト開発を加速させるためのQA文化の築き方 / How to build QA culture to accelerate product development
mii3king
1
300
AWS環境におけるランサムウェア攻撃対策の設計
nrinetcom
PRO
0
220
Google Cloud で始める Cloud Run 〜AWSとの比較と実例デモで解説〜
risatube
PRO
0
120
AWS re:Invent 2024で発表された コードを書く開発者向け機能について
maruto
0
220
Web APIをなぜつくるのか
mikanichinose
0
440
LINEスキマニにおけるフロントエンド開発
lycorptech_jp
PRO
0
350
PHP ユーザのための OpenTelemetry 入門 / phpcon2024-opentelemetry
shin1x1
3
1.5k
サイバー攻撃を想定したセキュリティガイドライン 策定とASM及びCNAPPの活用方法
syoshie
3
1.5k
Featured
See All Featured
Stop Working from a Prison Cell
hatefulcrawdad
267
20k
Large-scale JavaScript Application Architecture
addyosmani
510
110k
Fireside Chat
paigeccino
34
3.1k
It's Worth the Effort
3n
183
28k
Statistics for Hackers
jakevdp
796
220k
Imperfection Machines: The Place of Print at Facebook
scottboms
266
13k
The World Runs on Bad Software
bkeepers
PRO
66
11k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
45
2.2k
KATA
mclloyd
29
14k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
44
6.9k
No one is an island. Learnings from fostering a developers community.
thoeni
19
3k
Raft: Consensus for Rubyists
vanstee
137
6.7k
Transcript
アプリ開発の新たな選択肢が登場! Google社製Flutterのご紹介 HIROAKI TSUTSUMI 堤 啓彰 <
[email protected]
> アシアル株式会社
堤 啓彰 Tsutsumi Hiroaki エンジニア(主にフロントエンド) 業務で使ったことのある⾔語:JavaScript PHP C# 多少は書ける⾔語:Java Swift
ここ1年ほどは、Cordovaでのアプリ開発 ※ Flutterを業務で使った経験はなし
Flutterとは Cordova/Flutterの⽐較 Dartとは Flutterの基礎 まとめ TODAY’s AGENDA
Flutterとは Cordova/Flutterの⽐較 Dartとは Flutterの基礎 まとめ TODAY’s AGENDA
Flutterとは Google製の、Android/iOS向けのモバイルアプリを 開発できるクロスプラットフォーム開発ツール 2018年12⽉4⽇、バージョン1.0が正式リリース - 現時点での最新版はバージョン1.5.4 Githubでのスター数は67,000超え
Flutterとは > Githubスター数の推移 2018年2⽉27⽇、β版公開
Flutterとは > モバイルアプリだけではないFlutter Flutter for web Flutterのコードからブラウザで実⾏可能な Webアプリケーションを⽣成する技術 - 現在テクニカルプレビュー
Flutterとは > モバイルアプリだけではないFlutter Desktop Embedding for Flutter Flutterのコードからデスクトップアプリケーション (Windows/MacOS/Linux)を⽣成する技術 -
現在開発中
Flutterとは > モバイルアプリだけではないFlutter Flutterを習得すれば、Android/iOSに加えて、 Web/デスクトップアプリケーションも 作れるように
Flutterとは Cordova/Flutterの⽐較 Dartとは Flutterの基礎 まとめ TODAY’s AGENDA
Cordova/Flutterの⽐較 Cordova Flutter 開発⾔語 HTML/CSS/JavaScript Dart レンダリング WebView ネイティブ ホットリロード
不可 可
Cordova/Flutterの⽐較 > レンダリング:Cordova OS(Android/iOS) WebView UI UIはWebViewにより レンダリング ネイティブアプリよりも、 低パフォーマンス
Cordova/Flutterの⽐較 > レンダリング:Flutter OS(Android/iOS) UI UIはネイティブで レンダリング ネイティブアプリと 遜⾊ないパフォーマンス
Cordova/Flutterの⽐較 > ホットリロード ホットリロード ソースコードの変更を、 アプリを再ビルドせず、状態を維持したまま反映 - 修正が(基本的に)1秒未満で反映 - フルリロードしても10秒程度
Cordovaでは現状できない(ブラウザでは可能)
Cordova/Flutterの⽐較 > ホットリロード Demo
Cordova/Flutterの⽐較 Flutterを使えば、ハイパフォーマンスな アプリを、ホットリロードを⽤いて ⾼速に開発可能
Flutterとは Cordova/Flutterの⽐較 Dartとは Flutterの基礎 まとめ TODAY’s AGENDA
Dartとは > Dartの歴史 Googleによりリリース - JavaScriptを代替することが⽬的 - ブラウザへのDartVMの搭載が⽬標 2011
Dartとは > Dartの歴史 Googleによりリリース - JavaScriptを代替することが⽬的 - ブラウザへのDartVMの搭載が⽬標 ブラウザへのDartVMの搭載を断念 2011
2015
Dartとは > Dartの歴史 Googleによりリリース - JavaScriptを代替することが⽬的 - ブラウザへのDartVMの搭載が⽬標 ブラウザへのDartVMの搭載を断念 Googleのフロントエンド開発の標準⾔語としてTypeScriptが採⽤
2011 2015 2017
Dartとは > Dartの歴史 Googleによりリリース - JavaScriptを代替することが⽬的 - ブラウザへのDartVMの搭載が⽬標 2011 2015
ブラウザへのDartVMの搭載を断念 2017 Googleのフロントエンド開発の標準⾔語としてTypeScriptが採⽤ 現在 Flutterの普及とともに、再び注⽬を集める
Dartとは > Dartの特徴 Dartの特徴 • オブジェクト指向 • 静的型付け
Dartとは > サンプルコード class Person { String _firstName; String _lastName;
Person(this._firstName, this._lastName); String getFullName() { return '$_lastName $_firstName'; } } void main() { Person person = Person('Hiroaki', 'Tsutsumi'); print(person.getFullName()); }
Dartとは > Dartを使ってみた所感 所感 • くせがなく、書きやすい • オブジェクト指向を理解していれば、習得は⽤意 • Javaによく似ており、Javaを触ったことがあれば
すぐ馴染める
Dartとは > カスケード記法 カスケード記法 • 同⼀オブジェクトに対する操作を、 戻り値がなくても連続して記述できる記法 • 「..」(ドット2つ)で操作を連結して記述
Dartとは > カスケード記法 var button = querySelector('#confirm'); button.text = 'Confirm';
button.classes.add('important'); button.onClick.listen((e) => window.alert('Confirmed!')); カスケード記法なし
Dartとは > カスケード記法 var button = querySelector('#confirm'); button.text = 'Confirm';
button.classes.add('important'); button.onClick.listen((e) => window.alert('Confirmed!')); カスケード記法なし querySelector('#confirm') ..text = 'Confirm' ..classes.add('important') ..onClick.listen((e) => window.alert('Confirmed!')); カスケード記法あり
Dartとは > なぜDartが採⽤されたのか Dartはコンパイル⽅式として、JIT(Just In Time)と AOT(Ahead Of Time)の両⽅をサポート -
JIT:コンパイル速・パフォーマンス低 - AOT:コンパイル遅・パフォーマンス⾼
Dartとは > なぜDartが採⽤されたのか Dartはコンパイル⽅式として、JIT(Just In Time)と AOT(Ahead Of Time)の両⽅をサポート -
JIT:コンパイル速・パフォーマンス低 - AOT:コンパイル遅・パフォーマンス⾼ 開発時はJITによる開発サイクルの⾼速化 プロダクションではAOTによるパフォーマンス向上 その他にもいくつかの理由があり、詳細は https://flutter.dev/docs/resources/faq#why-did-flutter-choose-to-use-dart (英語)を参照
Flutterとは Cordova/Flutterの⽐較 Dartとは Flutterの基礎 まとめ TODAY’s AGENDA
Flutterの基礎 すべてがWidget
Flutterの基礎 > すべてがWidget FlutterアプリのUIは、Widgetの組み合わせ Widgetの中に⼊れ⼦でWidgetを追加して、 Widget Treeを構成していくことでUIを構築
Flutterの基礎 > すべてがWidget @override Widget build(BuildContext context) { return Scaffold(
appBar: AppBar(title: Text('TODOリ スト')), body: Column( children: <Widget>[...], ), ); }
Flutterの基礎 > すべてがWidget @override Widget build(BuildContext context) { return Scaffold(
appBar: AppBar(title: Text('TODOリ スト')), body: Column( children: <Widget>[...], ), ); }
@override Widget build(BuildContext context) { return Scaffold( ..., body: Column(
children: <Widget>[ Row( children: <Widget>[...], ), Expanded( child: ListView.builder(...), ), ], ), ); } Flutterの基礎 > すべてがWidget
@override Widget build(BuildContext context) { ..., body: Column( children: <Widget>[
Row( children: <Widget>[ Flexible( child: TextField(...), ), Padding(padding: EdgeInsets.only(right: 10.0)), RaisedButton(...), ], ), ..., Flutterの基礎 > すべてがWidget
Flutterの基礎 > 豊富なWidget Flutterは標準で⼤量のWidgetを提供 https://flutter.dev/docs/development/ui/widgets
Flutterの基礎 > 豊富なWidget:マテリアルデザイン https://flutter.dev/docs/development/ui/widgets/material
Flutterの基礎 > 豊富なWidget:Cupertino https://flutter.dev/docs/development/ui/widgets/cupertino
Flutterの基礎 > 豊富なWidget どのようなWidgetがあり、 そのWidgetで何ができるのかを 把握することが重要
Flutterの基礎 StatelessとStateful
Flutterの基礎 > StatelessとStateful Statelessは状態を持たないWidget Statefulは状態を持つWidget 外部との通信やユーザの操作により 状態が変化しないWidgetはStatelessに 状態が変化するWidgetはStatefulに
Flutterの基礎 > Statelessの例 各タスクはStateless • 渡された⽂字列を表⽰しているだけ • ユーザの操作により、 保持している情報は変化しないため
Flutterの基礎 > StatelessWidget class TodoListItem extends StatelessWidget { final int
_index; final String _todo; final Function _removeTodo; TodoListItem(this._index, this._todo, this._removeTodo); @override Widget build(BuildContext context) { return Card( child: ListTile( title: Text(_todo), trailing: IconButton( icon: Icon(Icons.remove_circle, color: Colors.red), onPressed: () => _removeTodo(_index), ), ..., }
Flutterの基礎 > StatelessWidget class TodoListItem extends StatelessWidget { final int
_index; final String _todo; final Function _removeTodo; TodoListItem(this._index, this._todo, this._removeTodo); @override Widget build(BuildContext context) { return Card( child: ListTile( title: Text(_todo), trailing: IconButton( icon: Icon(Icons.remove_circle, color: Colors.red), onPressed: () => _removeTodo(_index), ), ..., } StatelessWidgetを継承
Flutterの基礎 > StatelessWidget class TodoListItem extends StatelessWidget { final int
_index; final String _todo; final Function _removeTodo; TodoListItem(this._index, this._todo, this._removeTodo); @override Widget build(BuildContext context) { return Card( child: ListTile( title: Text(_todo), trailing: IconButton( icon: Icon(Icons.remove_circle, color: Colors.red), onPressed: () => _removeTodo(_index), ), ..., } buildメソッドをoverride
Flutterの基礎 > 状態変化の例
Flutterの基礎 > 状態変化の例
Flutterの基礎 > StatefulWidget final _todos = <String>[]; ... @override Widget
build(BuildContext context) { return Scaffold( ..., RaisedButton( ..., onPressed: () => setState(() => _todos.add(_todo)), ), ], ), ... child: ListView.builder( itemCount: _todos.length, itemBuilder: (BuildContext context, int index) => TodoListItem(index, _todos[index], _removeTodo), ), ...
Flutterの基礎 > StatefulWidget final _todos = <String>[]; ... @override Widget
build(BuildContext context) { return Scaffold( ..., RaisedButton( ..., onPressed: () => setState(() => _todos.add(_todo)), ), ], ), ... child: ListView.builder( itemCount: _todos.length, itemBuilder: (BuildContext context, int index) => TodoListItem(index, _todos[index], _removeTodo), ), ... State(状態)を定義
Flutterの基礎 > StatefulWidget final _todos = <String>[]; ... @override Widget
build(BuildContext context) { return Scaffold( ..., RaisedButton( ..., onPressed: () => setState(() => _todos.add(_todo)), ), ], ), ... child: ListView.builder( itemCount: _todos.length, itemBuilder: (BuildContext context, int index) => TodoListItem(index, _todos[index], _removeTodo), ), ... Stateを更新(タスクを追加)
Flutterの基礎 > StatefulWidget final _todos = <String>[]; ... @override Widget
build(BuildContext context) { return Scaffold( ..., RaisedButton( ..., onPressed: () => setState(() => _todos.add(_todo)), ), ], ), ... child: ListView.builder( itemCount: _todos.length, itemBuilder: (BuildContext context, int index) => TodoListItem(index, _todos[index], _removeTodo), ), ... Stateの更新を検知し、buildが呼ばれる
Flutterの基礎 > StatefulWidget final _todos = <String>[]; ... @override Widget
build(BuildContext context) { return Scaffold( ..., RaisedButton( ..., onPressed: () => setState(() => _todos.add(_todo)), ), ], ), ... child: ListView.builder( itemCount: _todos.length, itemBuilder: (BuildContext context, int index) => TodoListItem(index, _todos[index], _removeTodo), ), ... State(タスク⼀覧)が変化しているため、 ListViewが更新される
Flutterの基礎 Flutterでのアニメーション
Flutterの基礎 > Flutterでのアニメーション Flutterでは、アニメーションもWidget アニメーションに関しても、豊富なWidgetを提供 もちろん、⾃作も可能
Flutterの基礎 > アニメーション例:Opacity
Flutterの基礎 > アニメーション例:Opacity bool _visible = true; @override Widget build(BuildContext
context) { ... body: Center( child: AnimatedOpacity( opacity: _visible ? 1.0 : 0.0, duration: Duration(seconds: 1), child: Container(width: 200.0, height: 200.0, color: Colors.blue), ), ), floatingActionButton: FloatingActionButton( child: Icon(Icons.flip), onPressed: () => setState(() => _visible = !_visible), ),
Flutterの基礎 > アニメーション例:Opacity bool _visible = true; @override Widget build(BuildContext
context) { ... body: Center( child: AnimatedOpacity( opacity: _visible ? 1.0 : 0.0, duration: Duration(seconds: 1), child: Container(width: 200.0, height: 200.0, color: Colors.blue), ), ), floatingActionButton: FloatingActionButton( child: Icon(Icons.flip), onPressed: () => setState(() => _visible = !_visible), ),
Flutterの基礎 > アニメーション例:Opacity bool _visible = true; @override Widget build(BuildContext
context) { ... body: Center( child: AnimatedOpacity( opacity: _visible ? 1.0 : 0.0, duration: Duration(seconds: 1), child: Container(width: 200.0, height: 200.0, color: Colors.blue), ), ), floatingActionButton: FloatingActionButton( child: Icon(Icons.flip), onPressed: () => setState(() => _visible = !_visible), ), Stateを定義
Flutterの基礎 > アニメーション例:Opacity bool _visible = true; @override Widget build(BuildContext
context) { ... body: Center( child: AnimatedOpacity( opacity: _visible ? 1.0 : 0.0, duration: Duration(seconds: 1), child: Container(width: 200.0, height: 200.0, color: Colors.blue), ), ), floatingActionButton: FloatingActionButton( child: Icon(Icons.flip), onPressed: () => setState(() => _visible = !_visible), ), Stateを更新
Flutterの基礎 > アニメーション例:Opacity bool _visible = true; @override Widget build(BuildContext
context) { ... body: Center( child: AnimatedOpacity( opacity: _visible ? 1.0 : 0.0, duration: Duration(seconds: 1), child: Container(width: 200.0, height: 200.0, color: Colors.blue), ), ), floatingActionButton: FloatingActionButton( child: Icon(Icons.flip), onPressed: () => setState(() => _visible = !_visible), ), Stateの変更を検知し、buildが呼ばれる
Flutterの基礎 > アニメーション例:Opacity bool _visible = true; @override Widget build(BuildContext
context) { ... body: Center( child: AnimatedOpacity( opacity: _visible ? 1.0 : 0.0, duration: Duration(seconds: 1), child: Container(width: 200.0, height: 200.0, color: Colors.blue), ), ), floatingActionButton: FloatingActionButton( child: Icon(Icons.flip), onPressed: () => setState(() => _visible = !_visible), ), Opacityの変更に応じて、 アニメーション
Flutterの基礎 > アニメーション例:Container
Flutterの基礎 > アニメーション例:Container double _width = 100; double _height =
100; Color _color = Colors.blue; @override Widget build(BuildContext context) { ... child: AnimatedContainer( width: _width, height: _height, decoration: BoxDecoration(color: _color), duration: Duration(seconds: 1), curve: Curves.easeInOut, ), ... onPressed: () { setState(() { final random = Random(); _width = random.nextInt(300).toDouble(); _height = random.nextInt(300).toDouble(); _color = Color.fromRGBO(random.nextInt(256), random.nextInt(256), random.nextInt(256), 1); });
Flutterの基礎 > アニメーション例:Container double _width = 100; double _height =
100; Color _color = Colors.blue; @override Widget build(BuildContext context) { ... child: AnimatedContainer( width: _width, height: _height, decoration: BoxDecoration(color: _color), duration: Duration(seconds: 1), curve: Curves.easeInOut, ), ... onPressed: () { setState(() { final random = Random(); _width = random.nextInt(300).toDouble(); _height = random.nextInt(300).toDouble(); _color = Color.fromRGBO(random.nextInt(256), random.nextInt(256), random.nextInt(256), 1); }); Stateを定義
Flutterの基礎 > アニメーション例:Container double _width = 100; double _height =
100; Color _color = Colors.blue; @override Widget build(BuildContext context) { ... child: AnimatedContainer( width: _width, height: _height, decoration: BoxDecoration(color: _color), duration: Duration(seconds: 1), curve: Curves.easeInOut, ), ... onPressed: () { setState(() { final random = Random(); _width = random.nextInt(300).toDouble(); _height = random.nextInt(300).toDouble(); _color = Color.fromRGBO(random.nextInt(256), random.nextInt(256), random.nextInt(256), 1); }); Stateを更新
Flutterの基礎 > アニメーション例:Container double _width = 100; double _height =
100; Color _color = Colors.blue; @override Widget build(BuildContext context) { ... child: AnimatedContainer( width: _width, height: _height, decoration: BoxDecoration(color: _color), duration: Duration(seconds: 1), curve: Curves.easeInOut, ), ... onPressed: () { setState(() { final random = Random(); _width = random.nextInt(300).toDouble(); _height = random.nextInt(300).toDouble(); _color = Color.fromRGBO(random.nextInt(256), random.nextInt(256), random.nextInt(256), 1); }); Stateの変更を検知し、buildが呼ばれる
Flutterの基礎 > アニメーション例:Container double _width = 100; double _height =
100; Color _color = Colors.blue; @override Widget build(BuildContext context) { ... child: AnimatedContainer( width: _width, height: _height, decoration: BoxDecoration(color: _color), duration: Duration(seconds: 1), curve: Curves.easeInOut, ), ... onPressed: () { setState(() { final random = Random(); _width = random.nextInt(300).toDouble(); _height = random.nextInt(300).toDouble(); _color = Color.fromRGBO(random.nextInt(256), random.nextInt(256), random.nextInt(256), 1); }); 各Stateの変更に応じて、 アニメーション
Flutterとは Cordova/Flutterの⽐較 Dartとは Flutterの基礎 まとめ TODAY’s AGENDA
まとめ メリット・デメリット l 学習コストは低くはない l Dart⾃体は馴染みやすい l Widgetを使いこなすのが⼤変 l ⽇本語の情報はまだ少ない
l ネイティブアプリに近い パフォーマンス l ホットリロードによる ⾼速な開発サイクル
None