FirebaseRealtimeDatabaseのJSONデータをFlutterのRestAPIで表示
目次
前説
前回 Raspberry piで温度湿度気圧をFirebase Realtime Databaseにデータを格納しました。
このデータをAndroidで表示するためFlutterを使って最低限最新のデータ1つを表示するものを作成しました。
検証環境
Windows11 22H2 Flutter 3.7.12 Dart 2.19.6 PowerShell 7 Android 13
RealtimeDatabaseのルール変更
前回から以下の通りに変更しました。
ただし、uidが流出した場合と認証無しでデータの読み込みができてしまうため、推奨されません。
今回繋ぐときの認証を実装していないため暫定的にこのようにしました。
{
"rules": {
"users":{
"$uid":{
"tempdata":{
".read": "true"
},
".write": "auth.uid !== null && auth.uid === $uid"
}
}
}
}
実際のデータは以下のようになっています。
UIDに任意の文字列を入れています。
Flutterのインストール 開発環境の準備
公式ドキュメントを参考にインストールしました。
今回はWindowsのため、flutter_windows_3.7.12-stable.zipをダウンロードして、解凍、C:\src\flutterに配置しています。
システム詳細設定からシステム環境変数のPathにC:\src\flutterを追加して、PowerShellからflutterコマンドを実行できるようにしています。
https://docs.flutter.dev/get-started/install
プロジェクトの作成
公式ドキュメントに習い、VisualStudioCodeで新規プロジェクトを作成しました。
https://docs.flutter.dev/get-started/test-drive
プラグインの追加
PowerShellでプロジェクトのフォルダーにcdして以下を実行します。
flutter pub add dio
コードの変更
https://github.com/TKano-Null/tempviewer
プロジェクト作成時に生成されるlib/main.dartを変更し、RealtimeDatabaseからhttp通信でデータを取得、表示しています。
また、更新ボタンを押すことで最新のデータに更新できます。
先程追加したパッケージをインポートします。
import 'package:dio/dio.dart';
mainメソッドの変更を行います。
Future main() async {
await getTempData();
runApp(const MyApp());
}
getTempDataメソッドを実行してデータを取得したら表示を行うため、asyncとawaitを使用しています。
getTempDataメソッドを作成します。
getTempData() async {
const String tempDataUrl =
'https://xxxxxx.firebaseio.com/users/xxxxxxx/tempdata.json?orderBy="key"&limitToLast=1';
final response = await Dio().get(tempDataUrl);
if (response.statusCode == 200) {
String rawJson = response.toString();
Map<String, dynamic> map = jsonDecode(rawJson);
map.forEach((key, value) {
final DateTime date =
DateTime.fromMillisecondsSinceEpoch((value['date'] * 1000).round());
final hour = date.hour;
final minute = date.minute;
final String timeText = '$hour' '時' '$minute' '分';
final String temp = value['temp'].toStringAsFixed(1);
final String tempText = '$temp' '℃';
final String humi = value['humi'].toStringAsFixed(1);
final String humiText = '$humi' '%';
final String pres = (value['pres'] / 100).toStringAsFixed(1);
final String presText = '$pres' 'hPa';
_temptext =
'$timeText' '\n' '$tempText' '\n' '$humiText' '\n' '$presText';
print(_temptext);
});
} else {
print(response.statusCode);
}
}
今回RealtimeDatabaseに繋ぐとき認証を行っていないため、認証無しで実装することは推奨できません。
最低限とりあえずデータを取得表示したいためこのようにしてみました。
取得したいURLにorderBy=”key”&limitToLast=1を追加することで最新のデータ1件のみ取得しています。
DateTimeはUNIX時間で格納しているため、
final DateTime date =
DateTime.fromMillisecondsSinceEpoch((value['date'] * 1000).round());
と言う形で変換しています。
その他細かい点を変更していますが、Githubを参照してください。
テスト実行
PowerShellで、
flutter run
を実行し任意のブラウザで実行し動作を確認します。
Android13実機でテスト実行
実機で実行する場合まず最初に、開発者向けオプションを有効にする必要があります。
有効にする方法は各端末で異なりますが、Pixel6aの場合、
設定>デバイス情報 と遷移してビルド番号を何度かタップすると有効になります。
次に、USBデバッグを有効にします。
設定>システム>開発者向けオプションと遷移してUSBデバッグを有効にしてください。
テスト実行が終了したらUSBデバッグ及び開発者向けオプションの使用を無効にすることを推奨します。
USBデバッグを有効にした状態で、開発端末とUSB接続を行い、
flutter run
を再度実行すると、Android端末でアプリケーションが実行されます。
躓いた点
最初firebase_databaseプラグインを使用してJSONの取得を行っていたのですが、
取得したJSONのkeyとvalueが”でくくられていないため、
Map<String, dynamic> map = jsonDecode(rawJson);
でデコードする際エラーとなってしまいました。
firebase_databaseプラグインをした場合のJSON例
{objectID:{temp:28,humi:58}}
RestAPIを試用した場合のJSON例
{"objectID":{"temp":28,"humi":58}}
この問題が解決できなかったため、プラグイン使用からRestAPI使用に変更して対応しました。
懸念点としてはRestAPIを使用した場合おそらく認証の実装が大変になるのではないかと推測しています。
作成した感想
今回Dartを初めて使ったのですが、JavaやJavaScriptに慣れている私としては、クセが非常に少なく使いやすい言語でした。
また、Flutterもプロジェクト自体の容量が重いという点はありましたが、各OSでの開発やweb、スマートフォンに向けての実行も引っかかること無く実行できたため、ハイブリッド開発を行う上で有用な選択肢であると思います。
今後は温度湿度気圧を時間推移でグラフ表示出来るようにしたいと考えています。
コメントを残す