公式のcodelabでFlutterに入門してみた
今度Flutter Meetup Tokyo #2に参加するので、事前にちょっと手を動かしてみました。
What’s Flutter
Flutter - Beautiful native apps in record time
Googleが開発しているmobile appのSDKで、Dartという言語を用いて開発します。
本家サイトによると、特徴は以下の5つ。
- Fast development
- ホットリロードが可能
- Expressive and Flexible UI
- Modern, reactive framework
- Access native features and SDKs
- Unified app development
環境構築
環境
- macOS 10.13.4
- Android Studio 3.1.2
- Xcode 9.3
1. install Dart
$ brew tap dart-lang/dart
==> Tapping dart-lang/dart Cloning into '/usr/local/Homebrew/Library/Taps/dart-lang/homebrew-dart'... remote: Counting objects: 5, done. remote: Compressing objects: 100% (5/5), done. remote: Total 5 (delta 0), reused 2 (delta 0), pack-reused 0 Unpacking objects: 100% (5/5), done. Tapped 1 formula (30 files, 26.3KB)
$ brew install dart --with-dartium --with-content-shell
==> Installing dart from dart-lang/dart ==> Downloading https://storage.googleapis.com/dart-archive/channels/stable/release/1.24.3/sdk/dartsdk-macos-x64-release.zip ######################################################################## 100.0% ==> Downloading https://storage.googleapis.com/dart-archive/channels/stable/release/1.24.3/dartium/dartium-macos-x64-release.zip ######################################################################## 100.0% ==> Downloading https://storage.googleapis.com/dart-archive/channels/stable/release/1.24.3/dartium/content_shell-macos-x64-relea ######################################################################## 100.0% ==> Caveats Please note the path to the Dart SDK: /usr/local/opt/dart/libexec ==> Summary 🍺 /usr/local/Cellar/dart/1.24.3: 3,039 files, 657.7MB, built in 21 seconds
2. install Flutter
$ git clone https://github.com/flutter/flutter.git
Cloning into 'flutter'... remote: Counting objects: 120517, done. remote: Total 120517 (delta 0), reused 0 (delta 0), pack-reused 120516 Receiving objects: 100% (120517/120517), 36.60 MiB | 3.11 MiB/s, done. Resolving deltas: 100% (90418/90418), done.
$ git co v0.3.1 # flutter公式ページのzip最新版がv0.3.1だったため(2018/04/29現在)
$ vim ~/.zprofile
export PATH=$HOME/flutter/bin:$PATH
3. Set up environment
$ flutter doctor
Downloading Dart SDK from Flutter engine 09d05a38912a3c1a906e95099cac9a7e14fae85f... % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 43.9M 100 43.9M 0 0 9507k 0 0:00:04 0:00:04 --:--:-- 9508k Building flutter tool... ╔════════════════════════════════════════════════════════════════════════════╗ ║ Welcome to Flutter! - https://flutter.io ║ ║ ║ ║ The Flutter tool anonymously reports feature usage statistics and crash ║ ║ reports to Google in order to help Google contribute improvements to ║ ║ Flutter over time. ║ ║ ║ ║ Read about data we send with crash reports: ║ ║ https://github.com/flutter/flutter/wiki/Flutter-CLI-crash-reporting ║ ║ ║ ║ See Google's privacy policy: ║ ║ https://www.google.com/intl/en/policies/privacy/ ║ ║ ║ ║ Use "flutter config --no-analytics" to disable analytics and crash ║ ║ reporting. ║ ╚════════════════════════════════════════════════════════════════════════════╝ Downloading Material fonts... 0.9s Downloading package sky_engine... 0.5s Downloading common tools... 1.1s Downloading darwin-x64 tools... 1.9s Downloading android-arm-profile/darwin-x64 tools... 0.7s Downloading android-arm-release/darwin-x64 tools... 0.8s Downloading android-arm64-profile/darwin-x64 tools... 0.8s Downloading android-arm64-release/darwin-x64 tools... 0.8s Downloading android-x86 tools... 1.8s Downloading android-x64 tools... 1.5s Downloading android-arm tools... 1.6s Downloading android-arm-profile tools... 1.0s Downloading android-arm-release tools... 1.2s Downloading android-arm64 tools... 1.3s Downloading android-arm64-profile tools... 1.1s Downloading android-arm64-release tools... 1.0s Downloading ios tools... 2.2s Downloading ios-profile tools... 2.1s Downloading ios-release tools... 1.9s Downloading Gradle Wrapper... 0.2s Doctor summary (to see all details, run flutter doctor -v): [✓] Flutter (Channel unknown, v0.3.1, on Mac OS X 10.13.4 17E199, locale ja-JP) -Error executing simctl: -6 dyld: Symbol not found: _SimDeviceBootKeyDisabledJobs Referenced from: /Applications/Xcode.app/Contents/Developer/usr/bin/simctl Expected in: /Library/Developer/PrivateFrameworks/CoreSimulator.framework/Versions/A/CoreSimulator in /Applications/Xcode.app/Contents/Developer/usr/bin/simctl [!] Android toolchain - develop for Android devices (Android SDK 27.0.3) ! Some Android licenses not accepted. To resolve this, run: flutter doctor --android-licenses [!] iOS toolchain - develop for iOS devices (Xcode 9.3) ✗ Xcode requires additional components to be installed in order to run. Launch Xcode and install additional required components when prompted. ✗ libimobiledevice and ideviceinstaller are not installed. To install, run: brew install --HEAD libimobiledevice brew install ideviceinstaller ✗ ios-deploy not installed. To install: brew install ios-deploy ✗ CocoaPods not installed. CocoaPods is used to retrieve the iOS platform side's plugin code that responds to your plugin usage on the Dart side. Without resolving iOS dependencies with CocoaPods, plugins will not work on iOS. For more info, see https://flutter.io/platform-plugins To install: brew install cocoapods pod setup [✓] Android Studio (version 3.1) ✗ Flutter plugin not installed; this adds Flutter specific functionality. ✗ Dart plugin not installed; this adds Dart specific functionality. [!] IntelliJ IDEA Community Edition (version 2017.2.6) ✗ Flutter plugin not installed; this adds Flutter specific functionality. ✗ Dart plugin not installed; this adds Dart specific functionality. [✓] VS Code (version 1.22.2) [!] Connected devices ! No devices available ! Doctor found issues in 4 categories.
いくつか引っかかりました。
Android license
$ flutter doctor --android-licenses
3 of 6 SDK package licenses not accepted. 100% Computing updates... Review licenses that have not been accepted (y/N)? y 1/3: License android-googletv-license: 2/3: License google-gdk-license: 3/3: License mips-android-sysimage-license:
iOS
CocoaPods入れてなかったのがつらい。。。30分休み。
Android Studio
- Flutter plugin
- Dart plugin
Device
Device繋がってないよ!
はい。
対応し、再挑戦してみます。
$ flutter doctor
master Doctor summary (to see all details, run flutter doctor -v): [✓] Flutter (Channel unknown, v0.3.1, on Mac OS X 10.13.4 17E199, locale ja-JP) [✓] Android toolchain - develop for Android devices (Android SDK 27.0.3) [✓] iOS toolchain - develop for iOS devices (Xcode 9.3) [✓] Android Studio (version 3.1) [✓] VS Code (version 1.22.2) [✓] Connected devices (2 available)
いい感じです。これで開発環境が整いました。
codelabについて
スタートアップの会社名候補を生成するシンプルなモバイルアプリ
を作っていきます。お気に入り機能があり、別のページでお気に入りの名前リストを表示することもできます。
開発はAndroidStudioを使いましたが、VScodeなどを使っても良いそうです。
Step 1: Create the starting Flutter app
Flutterのプロジェクトを新規生成します。
Android Studioを使う場合はウィザードから、VScodeを使う場合はコマンドからアプリの雛形を生成できます。
ファイル構成はこんな感じです。
├── README.md ├── android # androidネイティブのコード ├── build ├── ios # iOSネイティブのコード ├── lib │ └── main.dart # 手を加えていくファイル ├── pubspec.lock ├── pubspec.yaml # 依存関係などなどを管理するファイル └── test └── widget_test.dart
終わったら、codelabにあるコードでlib/main.dart
を置き換えましょう。
Step 2: Use an external package
english_wordsというプラグインを入れます。プラグインの追加は、以下の手順で行います。
pubspec.yaml
に追記english_words: ^3.1.0
- Android Studioのタブに表示されている
Packages Get
をクリック- 以下が表示されればOK
${PATH_TO_FLUTTER}/flutter/bin/flutter --no-color packages get Running "flutter packages get" in ${YOUR_APP_NAME}... Process finished with exit code 0
lib/main.dart
にimportを追記import 'package:english_words/english_words.dart';
後はいつも通り使うだけです。特に難しいところはなさそうです。
Step 3: Add a Stateful widget
WidgetにはStatefulとStatelessの2種類があります。画面を表示している間にWidgetを書き換えるかどうかで使い分けます。今回のアプリでは無限スクロールのListを描画するので、StatefulWidgetを拡張したクラスを使用します。
まずは中央に表示されたtextを試しにstatefulにしてみます。
import 'package:flutter/material.dart'; import 'package:english_words/english_words.dart'; void main() => runApp(new MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return new MaterialApp( title: 'Welcome to Flutter', home: new Scaffold( appBar: new AppBar( title: new Text('Welcome to Flutter'), ), body: new Center( child: new RandomWords(), ), ), ); } } class RandomWords extends StatefulWidget { @override createState() => new RandomWordsState(); } class RandomWordsState extends State<RandomWords> { @override Widget build(BuildContext context) { final wordPair = new WordPair.random(); return new Text(wordPair.asPascalCase); } }
Step 4: Create an infinite scrolling ListView
いよいよ無限スクロールのListViewを生成します。ListView.builder()
を返すWidgetを定義し、builderの引数として渡すitemBuilder
プロパティの中でリスト生成のロジックを記述します。
(省略...) class RandomWordsState extends State<RandomWords> { final _suggestions = <WordPair>[]; final _biggerFont = const TextStyle(fontSize: 18.0); @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( title: new Text('Startup Name Generator'), ), body: _buildSuggestions(), ); } Widget _buildSuggestions() { return new ListView.builder( // ListView.builderを生成 padding: const EdgeInsets.all(16.0), itemBuilder: (context, i){ // itemBuilderのプロパティにリストを描画する無名関数を定義 if (i.isOdd) return new Divider(); final index = i ~/ 2; if (index >= _suggestions.length) { _suggestions.addAll(generateWordPairs().take(10)); } return _buildRow(_suggestions[index]); }, ); } // リスト1行をセットする Widget _buildRow(WordPair pair) { return new ListTile( title: new Text( pair.asPascalCase, style: _biggerFont, ), ); } }
Step 5: Add interactivity
ハート型アイコンをセットして、タップするとお気に入り登録できるようにします。Icons
クラスがすごく充実していて、アイコン追加がかなり楽そうです。
Androidで言うonClick
メソッドは、onTap
プロパティに対応します。
(省略...) Widget _buildRow(WordPair pair) { final alreadySaved = _saved.contains(pair); return new ListTile( title: new Text( pair.asPascalCase, style: _biggerFont, ), trailing: new Icon( alreadySaved ? Icons.favorite : Icons.favorite_border, color: alreadySaved ? Colors.red : null, ), onTap: () { setState(() { if (alreadySaved) { _saved.remove(pair); } else { _saved.add(pair); } }); }, ); }
Step 6: Navigate to a new screen
画面遷移のコードを書いていきます。Flutterでは新しい画面のことをroute
と言うみたいですね。
route
のスタックは、Navigation
クラスを使って管理していきます。
(省略...) void _pushSaved(){ Navigator.of(context).push( new MaterialPageRoute( builder: (context) { // お気に入り登録されたリストを各行にマップ final tiles = _saved.map( (pair) { return new ListTile( title: new Text( pair.asPascalCase, style: _biggerFont, ), ); }, ); // リストを生成 final divided = ListTile .divideTiles( context: context, tiles: tiles, ) .toList(); // appBarと画面のコンテンツ(リスト)をセット return new Scaffold( appBar: new AppBar( title: new Text('Saved Suggestions'), ), body: new ListView(children: divided), ); }, ), ); }
Step 7: Change the UI using Themes
UIの色をいじってみます。今回はひとまず、primaryColorを変更してappBarの色を変えてみます。
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return new MaterialApp( title: 'Startup Name Generator', theme: new ThemeData( primaryColor: Colors.white, ), home: new RandomWords(), ); } }
簡単ですね!ただ、結構大胆にカスタマイズをしようとすると大変なことになりそうな。。。
MaterialDesignからどうしても離れなきゃいけないときは厳しそうですね。
作ったもの
まとめ
一通りアプリを完成させるところまでやってみました。かなり簡単にそれなりのUIを作成することができました。
イメージとしてはAnkoのような感じかなーと思っていたのですが、ちょっと違う印象でした。ReactやVueなどのライブラリは使ったことがないのですが、そういったjsのライブラリで培ったノウハウが必要になりそうです。
とはいえ、これでFlutterのことが何となく完全に理解できました。今からmeetupが楽しみです。
今後やりたいこと
- ファイル構成を考える
- ファイルってどうやって分けていくんだろ
- いい加減Reactやらねば。。。
- OS依存の機能を使う
- network通信
- GPS
- camera
- SMS(出来るかな……?)