Flutter入門時のメモ
,
でフォーマット制御可能
個人的には,
を全部付与していきたい。
左端揃っている方が上下見やすくなることが多い為。
return Scaffold(appBar: AppBar());
return Scaffold(
appBar: AppBar(),
);
セットアップ
インストール
-
$ brew install flutter
以後、都度$ flutter doctor
を確認しながら進めると良い
iOS
XCode
-
$ xcode-select --install
// cocoapodsはiOSネイティブコードを触るflutterプラグインを使わない場合は不要かも?(公式より)
// でも今回flutter doctorに言及された気がするので追加した
// 公式はgemでインストールしている $ brew install cocoapods
$ sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
-
$ sudo xcodebuild -runFirstLaunch
XCodeを起動してWelcome画面まで進める(初起動は許可を求められるかも)
Android
-
$ brew install --cask android-studio
(JetBrainsの人はJetBrains toolboxでOK。私です) - Android Studioで起動してWelcome画面まで進める。
-
Customize -> All Settings -> Android SDK -> SDK Tools
で、
Android SDK Command-line Tools(latest)
をチェックする。 $ flutter doctor --android-licenses
確認
$ flutter doctor
がすべてチェックされていることを確認する
エディタ
- Android Studioで Plugins -> flutter、Dart インストール
- AppCodeでDartプラグインをインストール
新規プロジェクト作成
$ flutter create my_app
$ cd my_app
-
$ flutter run
これでブラウザで立ち上がる
シミュレータも立ち上げたい場合は起動してから実行する
確認
$ flutter doctor -v
[✓] Connected device (3 available)
• sdk gphone64 arm64 (mobile) • emulator-5554 • android-arm64 • Android 12 (API 31)
(emulator)
• iPhone 13 (mobile) • ECD4C6D8-7BD4-4FC8-BA1F-78A769C823AD • ios •
com.apple.CoreSimulator.SimRuntime.iOS-15-0 (simulator)
• Chrome (web) • chrome • web-javascript • Google Chrome 95.0.4638.69
備考
-
$ flutter run
の起動デバイスは一つだけ -
$ flutter run -d all
で全デバイス
コマンド
Global Options
command | desc |
---|---|
flutter --version | SDKバージョン確認 |
SDK
command | desc |
---|---|
flutter channel | 現在利用しているSDKのチャンネル確認 |
flutter config |
~/.flutter_settings を更新する。直接編集可能 |
flutter doctor -v | Flutter環境診断 |
flutter downgrade | 現チャンネルの旧バージョンにダウングレード |
flutter upgrade | 現チャンネルの新バージョンにアップグレード |
Project
command | desc |
---|---|
flutter analyze | プロジェクトのDartコードを解析 |
flutter create | プロジェクト新規作成。引数覚えるのが面倒なので、IDEから作成でOK |
flutter clean | ビルドファイルを削除する |
Package
command | desc |
---|---|
flutter pub add xxx | パッケージをpubspec.ymlのdependenciesに追加 |
flutter pub add xxx --dev | パッケージをpubspec.ymlのdependenciesに追加 |
flutter pub get | パッケージの取得、更新。pubspec.ymlを更新した時に使う |
flutter pub deps | 依存関係ツリー表示 |
run, build
command | desc |
---|---|
flutter run | devicesのターゲット(Android/iOS優先)にpub get、ビルド、インストールを実行 |
flutter run -d [頭文字] | 対象デバイスで実行 |
flutter run --release | リリースモードで実行 |
flutter run --debug | デバッグモードで実行 |
flutter run --verbose | 詳細実行 |
flutter build xxx | xxxの部分はapk, iosだけ覚えておけばOK--analyze-size でビルドサイズ確認可能 |
test
command | desc |
---|---|
flutter drive --target=xxx.dart | インテグレーションテスト |
flutter test | ユニットテスト実行 |
Tools & Devices
command | desc |
---|---|
flutter devices | 接続されたデバイス一覧。エミュレータは起動後に表示される |
flutter install | ビルドしたパッケージをデバイスにインストール |
flutter install -d [頭文字] | 対象デバイスにインストール |
flutter screenshot | 接続されたデバイスをスクリーンショット。--out で出力先を指定可能 |
チャンネル
チャンネル名 | desc |
---|---|
master | 最新版。不安定な可能性あり |
dev | α版相当。masterでテストパスしたビルド※削除予定 |
beta | beta版相当。月初めの月曜日にmasterから切り出される |
stable | 正式リリース安全版。基本これ。四半期に一度安定したbetaから切り出される |
InkResponse, InkWell, Ink
デバッグ時のみ実行するコードを書く
import 'package:flutter/foundation.dart';
if (kDebugMode) {
print('debug code');
}
経緯
次のように記述すると、print
に警告波線が表示され、IDEのヒントで「Make conditional on 'kDebugMode'」と表示された
printメソッドを使って、これが出たのは今回始めてな気がするが、確かにケアしたほうが良い。
onTap: () {
print('押されたよ');
},
kDebugModeを使う根拠(assertではなく)
公式にassertを使ったコードがあり、依存関係もないしassert使おう派もいるらしい。
が、どうやらkDebugModeが後から出来たようなので、単純に古いassertコードが残っているだけではという意見あり。
個人的には、適切な役割であるkDebugModeを使っていく方が気持ちいいように思う。
Did you know that you can execute some code that will only be compiled and executed on debug mode, with an assert?
I am using the if(kDebugMode) {...} for the same thing, later the tree shaking does it magic to remove this code in release build. Do you see any advantage of using assert?
Probably because those asserts pre-date the addition of kDebugMode
kDebugMode is significantly more readable and flexible
ページ遷移
決り文句だと思ってOK
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const OtherPage(),
),
);
},
別ページに値を渡す/受け取る
渡す
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const OtherPage('Foo'),
),
);
},
受け取る
class TalkRoom extends StatefulWidget {
+ final String name;
- const TalkRoom({Key? key}) : super(key: key);
+ const TalkRoom({Key? key, required this.name}) : super(key: key);
@override
_TalkRoomState createState() => _TalkRoomState();
}
標準ライブラリ
ライブラリ名 | desc |
---|---|
dart:core | Dartの基本型、日付など基本的なAPIを提供する。このライブラリはimportせずとも暗黙的に利用可能 |
dart:math | 指数関数、対数関数、n、乱数を扱うRandomクラスなど数学に関連するAPIを提供する |
dart:io | ファイル、通信などI/Oに関連するAPIを提供する |
dart:async | 非同期処理に対応するためのライブラリ |
プロジェクトの構成要素
ライブラリ名 | desc |
---|---|
.dart_tool | pub等のツールで使用されるフォルダ |
.idea | IntelliJ IDEA系の設定情報が格納されるフォルダ |
android | Androidアプリ生成に必要なファイルが格納されるフォルダ |
ios | iOS 〃 |
lib | dartファイルを格納するフォルダ |
test | ユニットテストを格納するフォルダ |
.gitignore | Git管理対象外を設定するファイル |
.metadata | Flutterツールが機能の評価、アップグレード等で使用するファイル |
.packages | 使用パッケージ情報が定義されているファイル |
アプリ名.iml | モジュール定義ファイル |
pubspeck.lock | 依存パッケージのバージョンをロックする設定ファイル |
pubspeck.yml | 依存パッケージのバージョン情報などの設定ファイル |
README.md | プロジェクト説明 |
Containerの最大サイズ調整
Container(
constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width * 0.6),
),
//
)
ListViewスクロール逆転
ListView.builder(
reverse: true,
//
)
要素が少ない時は上部配置したいとき
高さをコンテンツ由来にすればよい
ListView.builder(
+ shrinkWrap: true,
reverse: true,
//
)
さらにスクロールできるのはコンテンツが画面を超えた時だけでいいので
(コンテンツ由来の高さの中でスクロールしたときに、その高さの中でコンテンツが動いて、見切れたりするので、スクロールできない方が美しい)
ListView.builder(
+ physics: const RangeMaintainingScrollPhysics(),
shrinkWrap: true,
reverse: true,
//
)
Firebaseプロジェクト作成
Firebase Consoleでプロジェクトを作成
いつもどおりなので、細かいところは割愛
Android追加
- 取得
- AndroidManifest.xmlの2行目の値をコピー
- アプリ追加からAndroidを選択
指示に従って作業するだけでよい
Authを使うならこの段階でSHA-1を登録しておいて良さそう
iOS追加
- Bundle Identifier取得
open ios/Runner.xcworkspace
- 左サイドバーRunner -> TARGETSのRunner -> Generalタブ -> Bundle Identifierをコピー
- アプリ追加からiOSを選択
- GoogleService-info.plistをダウンロード
- RunnerのRunnerにD&Dで設置する
- この時、
Copy items if needed
にチェックを入れる- これがないとコピーされているように見えるが、実際は参照しているだけになる
- この時、
- Firebase SDK、初期化コードの追加(今回は必要なさそうなのでスキップ。Authとか使うなら必要になる?TODO: 今後確認)
Firestore作成(お試し)
- テストモードにて作成(今回は勉強用なので)
- asia-northeast1(東京)を選択(2は関西)
FlutterとFirebase(Firestore)連携
$ flutter pub add cloud_firestore
$ flutter pub add firebase_core
$ flutter pub get
-
$ npm install -g firebase-tools
(The CLI depends on the underlying Firebase CLI.
とあったので) $ dart pub global activate flutterfire_cli
-
$ flutterfire configure
- プロジェクト選択、ターゲット選択、iOSのbundle IDを入力(コピペ使えなかった)
-
lib/firebase_options.dart
が作成される
-
lib/main.dart
にFlutterFire開始の為の初期化コードを追加
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
runApp(const MyApp());
}
Preparing the list of your Firebase projectsの解決
firebase-toolsを再インストール(アップグレード)した関係か、時間的に認証トークンが無効になったせいか、flutterfire configure
をしたときにこんなエラーが出た
試しに、firebase projects:list
をしても同様のエラーが出た
(flutterfire configue
は、firebase projects:list --json
でコケているようだったので試した)
(firebase login
をすると、ログイン済みにはなっていたが)
$ firebase projects:list
✖ Preparing the list of your Firebase projects
Error: Failed to list Firebase projects. See firebase-debug.log for more info.
これはfirebase-toolsをアップグレードすると、認証トークンが無効になる可能性がある為のようである。
$ firebase login --reauth
ログイン、ログアウトでも可能
$ firebase logout
$ firebase login
iOSビルド
Error running pod install
デバッグモードで起動を試すとこのようなメッセージが出た
[!] CocoaPods could not find compatible versions for pod "cloud_firestore":
[!] Automatically assigning platform `iOS` with version `9.0` on target `Runner` because no platform was specified. Please specify a platform for this target in your Podfile. See `https://guides.cocoapods.org/syntax/podfile.html#platform`.
CocoaPodsのiosターゲットバージョンを上げると解決する
デフォルト値である10.6にすれば良いが、試しに14系を指定しておく
# Uncomment this line to define a globalf platform for your project
- // platform :ios, '9.0'
+ platform :ios, '14.0'
再度デバッグモードで起動を試すと成功した
Androidビルド
minSdkVersionの設定
デバッグモードで起動を試すと、次のエラーが表示された
Launching lib/main.dart on sdk gphone arm64 in debug mode...
Running Gradle task 'assembleDebug'...
Warning: Mapping new ns http://schemas.android.com/repository/android/common/02 to old ns http://schemas.android.com/repository/android/common/01
Warning: Mapping new ns http://schemas.android.com/repository/android/generic/02 to old ns http://schemas.android.com/repository/android/generic/01
Warning: Mapping new ns http://schemas.android.com/sdk/android/repo/addon2/02 to old ns http://schemas.android.com/sdk/android/repo/addon2/01
Warning: Mapping new ns http://schemas.android.com/sdk/android/repo/repository2/02 to old ns http://schemas.android.com/sdk/android/repo/repository2/01
Warning: Mapping new ns http://schemas.android.com/sdk/android/repo/sys-img2/02 to old ns http://schemas.android.com/sdk/android/repo/sys-img2/01
/Users/harapeko/hobby/flutter_udemy_chat/android/app/src/debug/AndroidManifest.xml Error:
uses-sdk:minSdkVersion 16 cannot be smaller than version 19 declared in library [:cloud_firestore] /Users/harapeko/hobby/flutter_udemy_chat/build/cloud_firestore/intermediates/library_manifest/debug/AndroidManifest.xml as the library might be using APIs not available in 16
Suggestion: use a compatible library with a minSdk of at most 16,
or increase this project's minSdk version to at least 19,
or use tools:overrideLibrary="io.flutter.plugins.firebase.firestore" to force usage (may lead to runtime failures)
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:processDebugMainManifest'.
> Manifest merger failed : uses-sdk:minSdkVersion 16 cannot be smaller than version 19 declared in library [:cloud_firestore] /Users/harapeko/hobby/flutter_udemy_chat/build/cloud_firestore/intermediates/library_manifest/debug/AndroidManifest.xml as the library might be using APIs not available in 16
Suggestion: use a compatible library with a minSdk of at most 16,
or increase this project's minSdk version to at least 19,
or use tools:overrideLibrary="io.flutter.plugins.firebase.firestore" to force usage (may lead to runtime failures)
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 12s
The plugin cloud_firestore requires a higher Android SDK version.
Fix this issue by adding the following to the file /Users/harapeko/hobby/flutter_udemy_chat/android/app/build.gradle:
android {
defaultConfig {
minSdkVersion 19
}
}
Note that your app won't be available to users running Android SDKs below 19.
Alternatively, try to find a version of this plugin that supports these lower versions of the Android SDK.
Exception: Gradle task assembleDebug failed with exit code 1
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "dev.harapeko.flutter_udemy_chat"
- minSdkVersion flutter.minSdkVersion
+ minSdkVersion math.Max(flutter.minSdkVersion, 30)
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
ext.kotlin_versionを最新バージョンにする
続けて次のようなエラーが出た
BUILD FAILED in 24s
[!] Your project requires a newer version of the Kotlin Gradle plugin.
Find the latest version on https://kotlinlang.org/docs/gradle.html#plugin-and-versions, then update /Users/harapeko/hobby/flutter_udemy_chat/android/build.gradle:
ext.kotlin_version = '<latest-version>'
Exception: Gradle task assembleDebug failed with exit code 1
buildscript {
- ext.kotlin_version = '1.3.50'
+ ext.kotlin_version = '1.6.10'
repositories {
google()
mavenCentral()
}
備考
minSdkVersion
を対象デバイスのバージョンよりも高くしたときのエラー
Error: ADB exited with exit code 1
Performing Streamed Install
adb: failed to install /Users/harapeko/hobby/flutter_udemy_chat/build/app/outputs/flutter-apk/app.apk: Failure [INSTALL_FAILED_OLDER_SDK: Failed parse during installPackageLI: /data/app/vmdl141932564.tmp/base.apk (at Binary XML file line #7): Requires newer sdk version #31 (current version is #30)]
Error launching application on sdk gphone arm64.
また、Error: ADB exited with exit code 1
はエミュレータのデータが一杯になったときにも表示されることがある(以前、遭遇した)
このときは、AVD MangerからWipe Dataを選択して解決した