Starでは、お客様企業向けのモバイルアプリを開発する際に、様々なアプリケーションやツールを使う機会があります。その中でも、迅速なアプリ開発のために使用しているフレームワークのひとつに「Flutter」があります。今回は、このツールに関する私たちの経験と、魅力的なUIをデザインするための効果的な使い方を紹介します。
Googleが提供するFlutterは、優れたクロスプラットフォームのフレームワークです。単一のコードベースで、モバイル・ウェブ・デスクトップ向けにネイティブコンパイルされた美しいアプリを構築できるUIツールキットが用意されています。開発者にとって次のようなメリットがあります:
- 迅速な開発 – ホットリロード機能により、アプリの状態を保ったまま、素早くUIを確認できます。
- ネイティブパフォーマンス – 互換性のあるウィジェットにより、iOSおよびAndroid上での完全なネイティブパフォーマンスを実現できます。C/C++で構築されたグラフィックスやレンダリングエンジンに対応したネイティブバイナリデータにコンパイルされるため、高速かつ高パフォーマンスのアプリを構築できます。
- 柔軟で快適なUI – Material DesignやCupertinoのウィジェット、スムーズなスクロール、豊富なモーションAPIなどにより、大胆なデザインにも挑戦できます。
Starは、Flutterを使ってさまざまなプロジェクトに取り組んでいます。以下では、私たちが開発したアプリの一部を簡単に紹介します。
有意義なアプリ構築
アプリ その1
建物内の空気の流れをコントロールするアプリです。Bluetooth LE接続により、通気口(給排気グリル)や温度センサーにアクセスします。ユーザーはこのアプリを使って、以下のようなことが可能になります。
- 気流制御システムの状態監視
- 気流コントロールシステムの設定
- 部分的なゾーンの作成・設定
- 遠隔からのファームウェアアップデートによる、通気口やセンサーの更新
- システムログの監視・収集・遠隔データベースへの送信
- Firebaseによるアプリケーションの安定性監視
使用した技術:
- Flutterフレームワーク
- Dart言語
- BLoCアーキテクチャパターン
- Providerライブラリ(依存オブジェクト注入)
- Flutter Blueライブラリ(Bluetooth LE通信)
- Floorライブラリ(データベース抽象化)
- Firebase Crashlytics(分析サービス)
アプリ その2
体組成分析(体重、体脂肪、BMI、体内水分、代謝率、血圧、心拍数などの計測)を実証するアプリです。専用のフィットネスデバイスからQRコードを読み取り、データを可視化します。ユーザーは以下のことが可能になります:
- 身体組成レポートをグラフやチャートで表示
- 過去の結果と比較した、個人別の変化の確認
- Firebaseによるアプリケーションの安定性の監視
使用した技術:
- Flutterフレームワーク
- Dart言語
- BLoCアーキテクチャパターン
- SQFliteプラグイン(データベース)
- Firebase Crashlytics(分析サービス)
アーキテクチャ・アプローチの定義
モバイルアプリのアーキテクチャには、さまざまな選択肢があります。どれが適しているかを探るため、私たちはRedux、MVVM、BLoCを試しました。それぞれに長所と短所があるなか、私たちは現在はBLoCを好んで使用しています。その理由を以下に説明します。
BLoCはシンプルで予測可能なアーキテクチャです。主な特徴は、「ロジックコンポーネント」と、入出力インターフェイスを持つ抽象化ブロックが分離されていることです。ロジックをコンポーネント単位で管理できるため拡張が可能で、既存のコンポーネントを増やしたり、新しいコンポーネントを追加したりできます。また、ロジックが独立し、入出力が明確なため、ブロックのテストも容易です。
https://pub.dev/packages/bloc ライブラリを使用することで、ボイラープレートコード(定型コードの繰り返し)を避けられます。また、エラー処理が簡素化され、トランジションやデリゲート(委譲)といった追加機能も提供されています。私たちは本番環境でも使用していますが、安定していて良い感じです。さらに、BLoCは独立して実装しやすいので、アプリに依存性が加わらないというメリットもあります。
Flutter利用時の課題
サードパーティのライブラリが不安定
Flutterには素晴らしいコミュニティがあり、多くのオープンソースプロジェクトが毎日、数多くのエンジニアを助けています。一部の人気プロジェクトは動作が安定しており、メンテナンスも行き届いています。ただ、私たちが探していたBluetooth Low Energy(BLE)を扱うライブラリなど、一般的でないものを探す際には、スムーズに行かない場合があります。
例えば、BLEを扱う最も安定したライブラリは「flutter_blue」です。しかし、pub.devで 「BLE」と入力して検索しても、このライブラリは結果の上位には表示されず、リストの下位で、メンテナンスの行き届いていない類似ライブラリに紛れてしまっています。GithubではなくGitlabに保存されているflutter_blueのコピーという紛らわしいものがあるなど、間違ったライブラリを選択してしまう恐れもあります。
大きな問題ではありませんが、検索がスムーズにいかないのは厄介です。パッケージの評価、信頼できるパブリッシャー、Flutterのお気に入りなど、pub.devにいくつかの改良を加えることで、この問題が解決されることを期待しています。
このようなことから、私たちはサードパーティのライブラリの使用を最小限に抑え、アプリの安定性を確保しています。
ローカライズ
Flutterでローカライズを行うのは簡単ではありません。デバイスのロケール検出は問題なくできますが、Flutterにはロケール依存のリソースを管理する仕組みがありません。例えば、Androidにはリソース管理の優れた仕組みがあり、コードからリソースにアクセスできます。各リソースは別々の内部ファイルに格納されており、エンジニアでなくても翻訳を行えます。
コミュニティにはいくつかのソリューションが提示されていますが、どれも完璧とは言えません。最も一般的に使われている方法は、jsonファイルを使って、定数をjsonフィールドとして参照するというものです。すべての文字列定数をエクスポートする必要がある場合は、格納ファイルの構造が単純なため非常に簡単だと言えますが、一方で、定数フィールドに名前でアクセスする際にミスがあった場合は、ランタイムエラーとなってしまいます。この問題を避けるために、Android Studioのflutter-i18nプラグインを使う方法がありますが、設定ごとのIDEインスタンスがない場合は、すべてのプロジェクトに特別なファイルが追加されるため、便利とは言えません。
このような背景から、今後のプロジェクトを進める上でローカライズが課題になりそうだとわかったため、それをできるだけ容易にする方法を検討しました。
とりあえずの解決策として、単純にリソースを定数として別々のdartファイルに格納しようと考えました。こうすると作業的には便利そうです。そこで、このアプローチに基づいてローカライズの開発を行ってみました。方法はとてもシンプルです。定数に対して必要なフィールドを持つインターフェイス(私たちの場合は抽象クラス)を抽出し、必要な言語の文字列クラスを作成するだけです。これにより、現在のデバイスのロケールに基づいた適切な文字列クラスを提供でき、その結果、ローカライズされた正しい値が得られます。また、jsonを使って、エンジニア以外の人でもアクセスしやすいように改良することもできます。
アダプティブUI
モバイルアプリは、さまざまなデバイスのサイズ、ピクセル密度、画面の向きに対応しなければなりません。この課題自体は今に始まったものではありませんが、依然として注意が必要です。
Androidの開発者である私たちは、アプリのUIコンポーネントを構築する際に、「dp」(Density-Independent Pixels:密度非依存ピクセル)と呼ばれる、画面の物理的な密度に基づいた抽象的な単位を用いることに慣れています。dpは160dpiの画面を基準にした相対値で、1dpは160dpiの画面の1ピクセルに相当します。dpとピクセルの比率は画面の密度によって変化します。しかし、Flutterは全く新しい単位「論理ピクセル」を用いています。論理ピクセルとは何でしょうか?
Googleはこう説明しています。「Flutterではdpではなく論理ピクセルを用います。これは基本的にデバイス非依存ピクセルと同じものです」
とはいえ、私たちの経験では、これらは完全に同じものではありません。スケッチを描いてそのサイズでUIを構築すれば、どの画面でも同じように見えると考えてはいけません。
「デバイスピクセルは、物理ピクセルとも呼ばれます。論理ピクセルは、デバイス非依存ピクセル、または解像度非依存ピクセルとも呼ばれます」
つまり、ピクセルパーフェクトなデザインを構築するためには、デザインのレイアウトを具体的な画面の解像度にマッピングする必要があります。つまり、必要な表示のdp(またはポイント)サイズに、デバイスの画面幅を掛けて、デザイン幅で割るという、ちょっとした計算が必要です。このようにデザイン・ピクセル比を考慮することで、さまざまな画面でピクセルを扱いやすくなります。
私たちはこの簡単な解決策で、良い結果を得られています。
状態の保存
Androidでの開発に慣れている方なら、アプリケーションの状態保存が常に課題であることをご存知かもしれません。画面の向き状態の変更や、アプリがOSによって強制終了される際の状態など、どのような状態の保存であっても、取り扱いは簡単ではありません。Flutterは、画面の向きに関しては、ユーザーデータを失うことなく処理できるようになっています。ただ、OSによるアプリの強制終了の場合に、それを管理して以前のセッションのデータを復元することはできません。
結論
- Flutterは迅速な開発、ネイティブパフォーマンス、柔軟性といった多くの利点を開発者にもたらす、高速でパフォーマンスの高いツールです。
- Flutterを使用する際には、シンプルで予測可能、テストも容易なBLoCアーキテクチャを採用することをお勧めします。
- Flutterには素晴らしいコミュニティがありますが、サードパーティのライブラリは不安定でメンテナンスが不十分なものもあるため、限定的な使用に留めることをお勧めします。
- ローカライズ作業は簡単ではありません。そこで私たちは、リソースを定数として別々のdartファイルに格納するという、シンプルなローカライズ方法を考案しました。
- 論理ピクセルは便利ですが、デザインのレイアウトを具体的な画面解像度にマッピングすることを忘れないでください。
- Flutterでは、画面の向き状態の変更についての問題は解決されましたが、OSがアプリを強制終了した際の状態保存の問題は、残念ながら未解決です。
- Flutterは、魅力的で有意義なUIを迅速に開発するのに役立つ優れたツールです。モバイルアプリのアイデアをお持ちで、それを実現するためのサポートが必要な場合は、ぜひご連絡ください。Starの経験豊富な開発者がいつでもお手伝いします。
Flutterは、魅力的で有意義なUIを迅速に開発するのに役立つ優れたツールです。モバイルアプリのアイデアをお持ちで、それを実現するためのサポートが必要な場合は、ぜひご連絡ください。Starの経験豊富な開発者がいつでもお手伝いします。