FlutterとAmplify DataStoreを使って爆速で雑談アプリを作る

Pocket

はじめに

ここ最近はもっぱらFlutter推しな早川です。初めて触ったのは去年の夏ごろですが、こんなに簡単にモバイルアプリが作れるのかー、と感動したものです。Flutter2がリリースされて、よりイケイケになったFlutterをエバンジェリストとして社内に広めていきたいな、と思っています。

今回はまだFlutter Webには対応してないんかい!とツッコミを入れつつも、AWS Amplifyを組み合わせて雑談アプリを作っていきたいと思います。なぜFirebaseじゃなくてAmplify?という声も聞こえてきそうですが、いいんです!やりたいからやるんですw

少しロングコンテンツですが、お付き合いいただければ幸いです。

考える

雑談アプリの構成はいたってシンプルです。まぁ、よくある構成ですね。モバイルアプリだとMacで開発されている方が多いかもしれませんが、ここではWindowsでAndroid Emulatorを使って動かすところまでやっていきます。

画面もDataStoreにフォーカスするために入室画面(認証なし!)と雑談画面の2画面です。

ハンドル名を入力して入室し、メッセージを送信すると相手側にもリアルタイムにメッセージが表示されます。

 

準備する

まず環境を整えます。環境の作り方についてはそこら中に書かれている方がいらっしゃると思いますので、ここでは深くは触れませんが、ざっくり以下のような手順を踏みます。

    1. Flutterをインストールする(ダウンロードしてパスを通すだけ)
    2. Android Studioをインストールし、Virtual Deviceを作る
    3. VSCodeをインストールし、Flutterの拡張機能を有効にする
    4. Node.jsをインストールする(nvmで複数バージョン管理すると便利ですね)
    5. Amplify CLIをインストールする

 

作る

それでは早速作っていきましょう!

プロジェクトの作成

VSCodeを起動し、Ctrl+Shift+Pでコマンドパレットを開き、「Flutter: New Project」から「Application」を選択します。

プロジェクトを保存するフォルダを選択し、プロジェクト名(ここではmiso_app)を入力します。

スケルトンではコメントがいっぱい記述されているので、正規表現で「//.*」を空置換しておきます。また、MyAppやMyHomePageも好きな名前に置換しておきましょう。今回はMisoAppとMisoHomePageに置換しました。

ここでプロジェクトのルートにあるpubspec.yamlを編集して、今回必要なライブラリを追加しておきます。雑談メッセージをかわいく吹き出し風に表示するためにchat_bubblesというライブラリも使っています。欲しいUIなどをサクッとpub.devで検索して組み込めるのもFlutterのいいところ。

本来あればpubspec.yamlを編集したらflutter pub getコマンドを実行しますが、VSCode上で編集すると自動で実行してくれるので便利ですね!

ここで一旦デフォルトのカウンタアプリが動くか確認しておくといいと思います。Flutter Amplifyあるあるですが、AmplifyはAndroidのSDKバージョン21以上を必要とするためandroid\app\build.gradleを編集しておくのを忘れずに!

モデルとリソースの作成

続いて雑談アプリをやり取りするためのモデルを作成するとともにAWS上にリソースを作っていきます。

1.Amplifyの初期化

VSCodeでコマンドプロンプトのターミナルを開き、以下のAmplifyの設定コマンドを実行します。

AWSコンソールが表示されるので、サインインしたらターミナルでEnterを押します。

リージョン(? region)と作成するIAMユーザー名(? user name)を入力します。

再びAWSコンソールの画面が表示されるので、そのまま「次のステップ:アクセス権限」ボタンをクリックします。

「AdministratorAccess-Amplify」にチェックを入れ、「次のステップ:タグ」ボタンをクリックします。「AdministratorAccess」にチェックが入っていたら外しましょう。

必要であればタグを入力し、「次のステップ:確認」ボタンをクリックします。

入力内容を確認して「ユーザーの作成」ボタンをクリックします。

後で使用するので、「.csvのダウンロード」ボタンをクリックしておきます。

ダウンロードしたCSVファイルからアクセスキーID(? accessKeyId)とシークレットアクセスキー(? secretAccessKey)、プロファイル名(? Profile Name)を入力すると設定完了です。

次にAmplifyの初期化コマンドを実行します。プロジェクト名(? Enter a name for the project)を入力して設定を確認したら「Y」を入力します。

使用する認証方法(? Select the authentication method you want to use:)で「AWS profile」を選択し、先ほど入力したプロファイル名(? Please choose the profile you want to use)を選択すると、初期化処理のCloudFormationが実行されます。”Your project has been successfully initialized and connected to the cloud!”というメッセージが表示されたら無事に初期化完了です。

2.GraphQL APIの作成

GraphQLのスキーマ情報を追加していきます。以下のコマンドを実行し、情報を入力します。

GraphQLのスキーマが作成されると “Do you want to edit the schema now? (Y/n)”と聞かれますが、一旦ここでは「n」と入力しておきます。

3.モデルの作成

スキーマ作成時のメッセージでschema.graphqlへのパスが表示されているはずです。これがGraphQLのスキーマ情報となり、プロジェクトのルート\amplify\backend\api\初期化したときに入力したプロジェクト名、となっていると思います。デフォルトではTodoというスキーマが作成されているかと思いますので、こちらを今回用に編集します。

雑談メッセージは投稿したタイムスタンプ順にソートしたいので、@indexでインデックスをつけておきます。

編集が完了したら、以下のコマンドを実行しモデルを作成します。

4.リソースの作成

AWS上にGraphQL APIのためのAppSyncとデータが保管されるDynamoDBのリソースを作成していきます。以下のコマンドを実行します。

CloudFormationが実行され、自動的にリソースが作成されます。

UIの作成

それでは今回のUIを作成していきましょう。FlutterでUIを組み立てていくのってなんだか楽しい、と思うのは私だけでしょうか??

1.入室画面のUI作成

こちらはデフォルトで作成されたmain.dartを編集していきます。MisoAppクラスの内容は以下のようになります。そのままだと中国語フォントっぽくなったり、デバッグ時のバナーが出たりするのを変更しています。

package:flutter_localizations/flutter_localizations.dartもインポートしておきましょう。

_MisoHomePageStateクラスの内容は以下のようになります。ハンドル名未入力のチェックを入れてあります。入室ボタン押下時の処理は後で書きます。

2.雑談画面のUI作成

libの下にsmall_talk_page.dartというファイルを作成します。私はVSCodeにAwesome Flutter Snippetsの拡張機能を入れているので、「statefulW」を補完することで一気に作っています。

補完されたらnameのところにSmallTalkPageと入力するだけでベースが完成します。まずは入室画面からハンドル名を受け取るためにSmallTalkPageクラスの内容を編集していきます。

続いて_SmallTalkPageStateクラスを編集します。自分の投稿(簡易的に入室した際のハンドル名と一致した場合を条件としています)は右側に来るようにし、スワイプで削除できるようにしてあります。フィールドにSmallTalkクラスのリストがありますが、これはGraphQLのスキーマから自動でモデル生成されたものです。

3.入室画面から雑談画面への遷移

雑談画面のUIが完成したところで入室画面から遷移できるようにしておきます。入室画面(main.dart)の入室ボタンのonPressedを以下のようにしましょう。入力チェックを通過した場合に雑談画面に遷移します。

 

処理の追加

処理は_SmallTalkPageStateクラスのほうに追加していきます。

まずは初期処理を追加します。GraphQLスキーマで定義した中にroomという項目がありましたが、ここでは”1″固定ということを想定しています(本当なら雑談部屋ごとにルームIDを振る感じになるかと思います)。DataStore.observeQuery()を実行する際、room=”1″というWhere条件をつけ、createdAtで降順ソートしています。

次にメッセージ送信時の処理を_postMessage()というメソッドで実装します。メッセージが入力されていたら、SmallTalkのオブジェクトを作ってDataStore.save()を実行するだけです。

これをIconButtonのonPressedから呼び出せば、メッセージを送信できるようになります。

さらに自分のメッセージをフリックで削除する機能を作っていきましょう。まず_deleteMessage()というメソッドを実装します。IDが一致したレコードを検索してDateStore.delete()で削除しています。

これを_buildMessage()内のDismissibleのonDismissedから呼び出すようにすれば、削除したいメッセージをフリックして削除できるようになります。

動かす

さあ、これで完成したはずです!動作確認してみましょう!

misoさんが送ったメッセージがsoupさんの画面にリアルタイムに表示されていて、フリックで削除したら表示が消えています。

DymamoDBのほうも見てみると_deletedという属性が「true」になっているのが確認できます。物理削除ではなく論理削除なんですね。ちなみにAmplify Studioで確認してみたところ、論理削除されたデータも表示されませんでした。

せっかくDataStoreで作成したので、オフライン時の動きも確認したところ以下のような挙動になりました。

misoのエミュレータの機内モードをONに設定変更し、メッセージを送信する
→miso上は送信したように見えるが、 soup側には送信したメッセージは表示されない
misoのエミュレータの機内モードをOFFに設定変更する
→soup側には送信したメッセージは表示されない
misoから別のメッセージを送信する
→soup側には送信したメッセージがまとめて表示される

本当は機内モードから復帰したときに自動的に同期されてほしかったんですけどね。

作ってみて

爆速で作ると言っておきながら、いろいろ細かいことが気になって割と時間がかかってしまいました。とはいえ特に大きくハマることなく作ることができました。この記事を読んだ方はこの通りやればきっと爆速で完成すると思います!

それでは、いいFlutterライフを!!

お問い合わせ先

執筆者プロフィール

Hayakawa Masafumi
Hayakawa Masafumitdi デジタルイノベーション技術部
昔も今も新しいものが大好き!
インフラからアプリまで縦横無尽にトータルサポートや新技術の探求を行っています。
週末はときどきキャンプ場に出没します。
Pocket

関連記事