FlutterでID/Password入力画面を作ってみる
FlutterでID/Pass入力画面を作るときに設定するのパラメータをちょっと調べたのてまとめてみます。(※入力のバリデーションやオートフォーカス等のアクションは含みません)
よくあるID/Pass入力画面の要件
よくあるID/Passの入力画面の要件といえばこんな感じでしょうか。
ID入力
- 半角英数が入力できる
Password
- 半角英数が入力できる
- 入力内容はマスクしたい
- 入力内容を確認したいので、マスクの表示非表示を切り替えられるようにしたい
- 予測変換はさせたくないしヒストリーに記録なんてさせたくない
- 入力欄のコピペはブロックしたい
入力フォームはTextInputFiled
を使えば実現できます。中でTextFieldをラップしているようです。
TextFormField class - material library - Dart API
TextField constructor - TextField class - material library - Dart API
上記の要件に絡みそうなパラメータは以下の通りです。
- obscureText
- 入力内容のマスク表示の切り替え
- autocorrect
- オートコレクト・予測変換の有効・無効化
- enableInteractiveSelection
- 入力エリアのセレクトアクション(コピペ、選択、削除など)の有効・無効化
- TextInputType
- 立ち上げるキーボードタイプ。以下の種類がある。
- TextInputType class - services library - Dart API
- datetime
- emailAddress
- multiline
- number
- phone
- text
- url
- visiblePassword
今回の要件では、以下のような設定にするのがよさそうです。
ID入力欄
パラメータ | 値 | 理由 |
---|---|---|
obscureText | false | IDは常に見せておくため |
autocrrect | false/true | どちらでもよさそう。メールアドレスとかだとサジェストがあると嬉しいかもしれない。 |
enableInteractiveSelection | true | コピペしたいケースがありそうなので。 |
TextInputType | emailAddress | IDがメールアドレスのケースも多く、とりあえず半角英数で立ち上がってほしいので。 |
Password入力欄
パラメータ | 値 | 理由 |
---|---|---|
obscureText | true/false | 右端に目のアイコンを用意し、クリックで切り替えられるようにする。 |
autocrrect | false | パスワードは守りたいので。 |
enableInteractiveSelection | false | コピペはブロックしたいので。 |
TextInputType | visiblePassword | パスワードを見せる専用のキーボードタイプ。v1.9.1+hotfix-6から使える模様。 |
Widgetに上記の設定をしてiOS/Androidそれぞれエミュレータで動かしてみます。
今回試したコードサンプルはこちら。
なおPassword入力画面のパーツについては本家のflutter garallyにもあり、今回の実装の参考にしました。
実行環境は以下の通りです。
$ flutter doctor Doctor summary (to see all details, run flutter doctor -v): [✓] Flutter (Channel unknown, v1.9.1+hotfix.6, on Mac OS X 10.14.6 18G87, locale en-JP) [✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3) [✓] Xcode - develop for iOS and macOS (Xcode 11.3) [✓] Android Studio (version 3.5) [!] IntelliJ IDEA Ultimate Edition (version 2019.3) ✗ Flutter plugin not installed; this adds Flutter specific functionality. ✗ Dart plugin not installed; this adds Dart specific functionality. [!] VS Code (version 1.41.0) ✗ Flutter extension not installed; install from https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter [✓] Connected device (2 available) ! Doctor found issues in 2 categories. $ flutter devices 2 connected devices: AOSP on IA Emulator • emulator-5554 • android-x86 • Android 9 (API 28) (emulator) iPhone 11 Pro Max • 424952E6-D634-4B19-AA9A-8552B62DE670 • ios •com.apple.CoreSimulator.SimRuntime.iOS-13-3 (simulator)
挙動確認
iOS
想定通り動いてそうです。
Android
Androidも大丈夫そうです。
余談:TextInputTypeがvisiblePasswordじゃないとAndroidでautocorrectが効かないらしい。
そもそもFlutterにはautocorrectのバグがあったようです。
このバグの対処のために、最新のstableであるv1.12.13+hotfix.5
ではenableSuggestions
というパラメータが追加されたようです。
このパラメータ追加で予測変換を一律制御できるのかな〜と思ったのですがそもそもAndroidのみとのこと。またIssueのコメントにあるようにTextInputType.text
だと予測変換の無効化は効かない模様。まじかー。
入力のI/O周りはAndroidとiOSの両OSのモジュールをうまくラップして制御するのが難しいのでしょうかね。そういえばWebやDesktopもあるんだった・・・。
あと今回他のサービスはどうなってるのかな〜と思っていろいろ調べたのですが、ほとんどがWebViewでの入力画面が立ち上がるパターンでした。。。
GitLab APIを使ってtag名とtagのタイムスタンプをcsv形式で出力する
リリース頻度のデータを分析するために、GitLabのtag名とtagを作成した時のタイムスタンプの一覧が欲しくなったのでGitLab API経由で取得するシェルを書きました。
#!/bin/sh BASE_URL="xxxx" API_TOKEN="xxxx" PROJECT_ID="xxxxx" # 全tag一覧を取得するための最大ページ数を取得する TOTAL_PAGES=`curl -D - -s -o /dev/null -X GET -H "PRIVATE-TOKEN: ${API_TOKEN}" "${BASE_URL}/api/v4/projects/${PROJECT_ID}/repository/tags?per_page=100" | grep "X-Total-Pages" | tr -d "X-Total-Pages: " | tr -d "\r"` # タグとタグのタイムスタンプをカンマ区切りで取得する RESULT="" for i in `seq 1 ${TOTAL_PAGES}` do RESULT=${RESULT}`curl -X GET -H "PRIVATE-TOKEN: ${API_TOKEN}" "${BASE_URL}/api/v4/projects/${PROJECT_ID}/repository/tags?per_page=100&page=${i}" | jq -r '.[] | (.name|tostring) + "," + (.commit.authored_date|tostring)'`"\n" done # UTCで返却されるので、JSTに変換し出力する for line in ${RESULT} do TAG_NAME=`echo ${line} | cut -d ',' -f1` TIMESTAMP_UTC=`echo ${line} | cut -d ',' -f2` TIMESTAMP_JST=`date -v+9H -j -f "%Y-%m-%dT%T.000Z" ${TIMESTAMP_UTC} +%Y-%m-%dT%T.000Z` echo ${TAG_NAME},${TIMESTAMP_JST} done
tag一覧の取得は/api/v4/projects/${PROJECT_ID}/repository/tags
のエンドポイントを叩くと取れます。
https://docs.gitlab.com/ce/api/
tag一覧の取得はページングのハンドリングが必要なので、レスポンスヘッダーのX-Total-Pages
からページ数を取得し、最終的にはfor文で回してjqで加工したものを連結します。
タイムゾーンの設定によってはUTCで結果が帰ってくるので、最後にdateコマンドでJSTに変換しています。
上記のシェルを実行すると以下のようなcsvが取得できます。
1.5.0,2019-09-30T10:59:49.000Z 1.4.0,2019-09-26T15:35:21.000Z 1.3.2,2019-09-20T19:00:11.000Z 1.3.1,2019-09-17T18:21:30.000Z 1.3.0,2019-09-11T21:01:37.000Z 1.2.0,2019-09-03T22:08:34.000Z 1.1.0,2019-08-27T22:41:38.000Z 1.0.2,2019-08-20T22:37:28.000Z 1.0.1,2019-08-13T22:13:56.000Z 1.0.0,2019-08-06T21:38:05.000Z 0.3.0,2019-07-30T21:16:30.000Z 0.2.0,2019-07-23T22:38:51.000Z 0.1.0,2019-07-17T15:30:01.000Z
あとはこれをSpreadSheetなりExcelなりPythonなりで集計すればリリース頻度の分析の集計ができます。
LeanとDevOpsの科学[Accelerate] テクノロジーの戦略的活用が組織変革を加速する (impress top gear)
- 作者:Nicole Forsgren Ph.D.,Jez Humble,Gene Kim
- 出版社/メーカー: インプレス
- 発売日: 2018/11/22
- メディア: 単行本(ソフトカバー)
master中心のブランチ戦略で開発している話
ここ数年、CI/CDパイプラインを構築したりブランチ戦略を考えるロールで仕事をすることが多いのですが、ブランチ戦略はいつも頭を悩ませていました。
当初はGit FlowやGitLab Flowの採用を考えたりしたのですが、ブランチやマージの戦略がちょっと重厚でめんどうなだという印象を持っていました。
「releaseブランチとかpre-productionとか管理面倒だからぶっちゃけmasterだけでよくね?」とふと思い、master中心のシンプルなブランチ戦略を考え、実践してみました。するとそれなりにうまく立ち回ることができるようになっていたので、整理もかねてまとめておきます。
対象とするプロジェクト
本ブランチ戦略は、以下のような開発チームに対してうまく機能できると考えています(※もちろんこの方法が最適な解とは限りません)
- バックエンド・フロントエンド・スマホアプリなど開発領域ごとにチームが別れている
- サービスを成立させるためには各チームが独立にリリースすることはできず、最終的には資材の同期を取る必要がある
- 先に開発を終えたチームは次の案件の開発に着手しており、追加開発とリリース用の2つの資材を管理する必要がある
- 開発チームメンバーは数人から20人程度
- masterをcleanに保つためのCIが整っている
基本的な考え方
master中心のブランチ戦略のベースとなる考え方は以下の通りです。
- masterが最新の安定版となるようにコミットしていく(※ リリース版ではなく機能開発の最新)
- ブランチは本開発、追加開発、リリース版などの開発の流れ(= Flow)を表す
- ブランチはどこかのブランチにマージするか、マージしない場合は独立に更新を続け最終的には捨てる
- この機能を入れる資材と入れない資材が必要、というときにブランチを切って開発の流れを分岐させる
- リリースバージョンはタグに紐づけるようにし、ブランチと実行環境は紐付けない
これら原則に従うことで、以下のようなメリットが得られます。
- 管理するブランチが少なくなるため、ブランチの管理やマージ先の手間をへらすことができる
- 「masterブランチを最新の安定版」とするため、Pull Reuquest / Merge Requestのマージ先はhotfix以外はすべてmasterになり、追加開発時のマージ先誤りの事故を防ぐことができる
- ブランチと実行環境が分離されるため、環境管理とは独立して資材のバージョン管理ができる
以下、実際にリリースの前・リリース後のブランチ戦略を説明していきます。
リリース前のブランチ戦略
リリース前のブランチ戦略は非常にシンプルです。masterブランチに対して、featureブランチ・bugfixブランチをマージすることで機能追加を反映していきます。
初期開発時に利用するブランチは以下の通りです。
ブランチ名 | ブランチの切り元・マージ先 | 用途 |
---|---|---|
master | - | 最新の安定版ブランチ |
feature/* | master | 機能追加用ブランチ。CIが通ったもののみマージする。チケット番号と紐付ける。masterにマージしたら削除する。 |
bugfix/* | master | テスト・QA等で発覚したバグの修正用のブランチ。CIが通ったもののみマージする。チケット番号と紐付ける。masterにマージしたら削除する。 |
このとき、成長するブランチはmasterブランチのみであり、チームメンバはmasterブランチのみを追いかけていればよいです。
検証環境へのリリース資材を作成する場合はtagでバージョンとコミットハッシュを紐付けることでバージョン管理ができます(図のv0.1.0、v0.1.1)。
リリース後のブランチ戦略
ここでのリリース後、とは自分のチームの開発範囲のリリースを指します。すなわちバックエンドチームであればバックエンドのAPIのみのリリースを指します。
バックエンドは順調に開発が進み先に環境へリリースできた一方で、フロントエンドは画面の仕様調整に難航しスケジュールが遅れてしまった、というケースはよくあると思います(逆もしかり)。
このときバックエンドチームはフロントエンドチームの待ちの状態になるため、開発チームの余ったリソースを使って先に追加開発に着手し始めるケースがよくあります。このとき、masterブランチのみの運用だと本来のリリースには含めてはいけない資材が混じってしまう可能性があるため、フロントエンドの改修がバックエンドに波及したときのhotfixの対応を受け入れるために、masterとは別のproductionブランチを作成し2つの流れを作って運用します。
productionブランチを作っておくことで、フロントエンドチームと同期をとったときの不具合のフローと追加開発のフローを分けて管理することができます(下図)。
利用するブランチは以下の通りです。 リリース後のブランチはリリース前にあったブランチに加えてproductionブランチとhotfixブランチが追加されています。
ブランチ名 | ブランチの切り元・マージ先 | 用途 |
---|---|---|
master | - | 最新の安定版ブランチ |
production | master | 最新のリリース版、リリースごとに作成する。リリース版にのみ緊急に反映させたいパッチがあればあてる。追加開発版のリリースが行われたら今まで使っていたproductionブランチは削除し、リリース対象のタグから新しいproductionブランチを作成する。 |
feature/* | master | 機能追加用ブランチ。CIが通ったもののみマージする。チケット番号と紐付ける。masterにマージしたら削除する。 |
bugfix/* | master | テスト・QA等で発覚したバグの修正用のブランチ。CIが通ったもののみマージする。チケット番号と紐付ける。masterにマージしたら削除する。 |
hotfix/* | production / master | リリース版バグ修正用のブランチ。CIが通ったもののみマージする。チケット番号と紐付ける。productionにのみパッチをあてる場合はproductionから切ってproductionにマージし削除する。production / master両方に必要なパッチの場合はそれぞれの根本から2本パッチを充ててそれぞれにマージし削除する。 |
productionブランチは外部チームへの提供可能なバージョンのタグを切ったときに作成します。productionブランチにはリリースに必要なパッチや緊急のhotfixのみの変更が当てられます。hotfixのパッチは場合によってはデグレを防ぐためにmasterとproduction両方に当てる必要があります(※後述)。追加開発向けの機能追加はリリース前と同様です。
リリース版で発覚したバグ修正のhotfixは、追加開発を行っている最新版のmasterに入れる場合と入れない場合とで以下のように対応を分けます。
- リリース版および最新版にもパッチを入れる場合(例:恒久的なバグ対応)
- hotfixブランチをproductionから切って、productionにマージする
- hotfixブランチをmasterからも切って、productionブランチへのhotfixと同様の変更を加えmasterにマージする(cherry-pickなどを使う)
- リリース版のみに入れるパッチの場合(例:ライブラリの緊急パッチ等の暫定対処)
- hotfixブランチをproductionから切って、productionにのみマージする
hotfixの対応は一見複雑そうに見えますが、「masterが常に追加開発の最新版である」こと、「productionブランチがリリース版の最新版である」ことを考えると意外とシンプルにまとまっているのではないでしょうか。
なお、productionブランチはmasterには不要な変更を含んでいる場合があるため、masterにはマージしません。次のリリース版のtagが打たれたらまた新しいproductionブランチを作成します。
まとめ
Gitのブランチ戦略はGiit FlowやGitLab Flow等がありますが、どちらも扱うブランチの種類が多かったりデプロイ先の環境と密結合に語られていて扱いにくい印象を持っていました。
「masterを最新の安定版ブランチ」とする、というこのmaster中心のブランチ戦略を使うことで、シンプルで運用しやすい資材管理ができるようになったと個人的には考えています。興味を持たれた方はぜひ実践してみてください。