湯婆婆が画面いっぱいに出てきてわあとなりました。
今日はうって変わってFlutter Webは非対応ですのでご了承ください。
まえがきのまえがき
2021-2-18にAmplify FlutterがGAされました。公式ブログ
GA時点では大きく機能追加されたわけではなく、Preview版の修正や小規模な機能追加が中心と見られるため、
まだそれほど古くなったものではないと思いたいです。。。
が、Preview版時点での情報を記載していますので、その辺は悪しからず。
まえがき
今年の7月から10月くらいにかけて、仕事でFlutterをゼロから勉強してやってました。(すなわち今回久しぶりにリハビリする・・・)
そんな縁もあって、初めてこういう企画に参加しようかなって思ったら、表側にはmonoさんがいたりと、Googlingでお世話になった人もいて恐縮です。まあ、できる限り情報提供できるように頑張ってみます。
表題の通り、Amplify Flutterをやってみようと思います。
目標
この記事では、Amplify公式のGetting Startedから初めて、ごくごくあり得そうな構成を実際に作ってみようと思いますした。
Amplify Flutterについて簡単に説明
Amplifyとは
正式名称は「AWS Amplify」。公式ページの説明を借りると、以下です。
AWS Amplify は、モバイルとウェブのフロントエンドデベロッパーが、安全でスケーラブルなフルスタックアプリケーションを構築しデプロイできるようにする、AWS による製品およびツールのセットです。
ということで、主語がフロントエンドデベロッパーとあるように、フロントエンド開発するときに、いい感じにAWS環境(バックエンド)まで作ってくれるツール、が本来のAmplifyです。ただ、もちろん既に構築済みのバックエンドに対するAWS謹製のフロントエンドライブラリとしても利用できます。
体感ですが、そこそこの規模のtoB,toC向けシステムなら、後者になりそうな気がします。Amplifyが絡まない部分の管理どうすんねんっていう話がありますからね。。。
Amplify Flutterとは
これまで、Amplifyはこのページにあるように色んなフロントエンドフレームワークに対応していましたが、2020年8月、ついにFlutterにも対応しました。ただし、Developer Previewなので、本番環境には使うなということです。
ちなみに、じゃあ今までどうしてたのかというと、大半の人はpub.devで調べてサードパーティのものを使うなり、場合によってはMethodChannelを駆使しつつ、ネイティブのものを使って自作、なんてことをする必要があったのかもしれません。
設計と実装
何はともあれ、ちゃんとPreviewしないとねってことで、つべこべ言わずに早速発表から3ヶ月経ってるのに今更やってみます。
Todoリスト
はい。最後は諦めました。が、半日くらいでそこそこのレベルにはなってくれました。
- チュートリアル通りにAmazon PinPointと疎通できる
- サインアップできる
- サインインできる
- サインアウトできる
- REST APIで疎通できる(Amplify非対応)
- S3にファイルをアップロードできる
- サインイン状態を維持できる
成果物リンク
- リポジトリhttps://github.com/taniyuu/amplify_flutter_sample
- デモ(サインイン/サインアウト)↓
手順(抜粋)
チュートリアルページを進める
- Amplify CLIは、現時点では不要です。
- (iOSのみ)Podfileを11.0に上げるよう指示されますが、
flutter create
時にはPodfileは生成されません。pubspec.yaml
に追加した時点でPodfileも追加されるので、その時点で調整しましょう。
-
amplifyconfiguration.dart
が何か全然わからないので、ファイルは作らずに飛ばしましょう(Amplify CLIで決めることはわかっていつつ)。- なんなら、AnalyzeとAuthを勝手にimportさせられている(自己責任)
ここで、満を辞してAmplify CLIの登場です。CLIのセットアップはそれだけで記事になるレベルなので、こちらを参照ください。
AWS Amplify CLIの使い方〜インストールから初期セットアップまで〜
ちなみに、古いとそもそもCLIでFlutter選べないのでご注意。
yuki@taniyamayuukinoMacBook-Air amplify_flutter_sample % amplify --version
╭─────────────────────────────────────────────╮
│ │
│ Update available 4.29.3 → 4.37.1 │
│ Run npm i -g @aws-amplify/cli to update │
│ │
╰─────────────────────────────────────────────╯
4.29.3
yuki@taniyamayuukinoMacBook-Air amplify_flutter_sample %
アップデートすると出てきました。
yuki@taniyamayuukinoMacBook-Air amplify_flutter_sample % amplify init
Initializing new Amplify CLI version...
Done initializing new version.
Scanning for plugins...
Plugin scan successful
Note: It is recommended to run this command from the root of your app directory
? Enter a name for the project amplifyfluttersample
? Enter a name for the environment dev
? Choose your default editor: Visual Studio Code
? Choose the type of app that you're building (Use arrow keys)
android
❯ flutter
ios
javascript
念押しされますが気にせず進みましょう。
⚠️ Flutter project support in the Amplify CLI is in DEVELOPER PREVIEW.
Only the following categories are supported:
* Auth
* Analytics (Amazon Pinpoint only)
* API (GraphQL only)
* Storage
デプロイに成功すると、このようになります。
-
Flutter側
- amplifyconfiguration.dartができています。さっき飛ばしたのが正解だったとここで確信します。
- (お断り) amplify/配下は、環境値が入っているので今回のリポジトリからはごめんなさいします。
ちなみに、この時点でiOSでflutter run
すると、このようなログが出ます。
MethodChannel
を呼び出しているのが意図せず~~(割と意図してました)~~確認できました。
[VERBOSE-2:ui_dart_state.cc(177)] Unhandled Exception: PlatformException(AmplifyException, Failed to Configure Amplify, The operation couldn’t be completed. (Amplify.PluginError error 2.), null)
#0 StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:582:7)
#1 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:159:18)
<asynchronous suspension>
#2 MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:332:12)
#3 MethodChannelAmplifyCore.configure (package:amplify_core_plugin_interface/method_channel_amplify.dart:25:21)
#4 Amplify.configure (package:amplify_core/amplify_core.dart:78:35)
#5 _MyHomePageState._configureAmplify (package:amplify_flutter_sample/main.dart:78:27)
#6 _MyHomePageState.initState (package:amplify_flutter_sample/main.dart:65:5)
#7 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:4765:58)
#8 ComponentElement.mount (package:flutter<…>
長くなりましたが、あとは手順に従いAnalyticsを導入します。
(東京リージョンでAmplifyの設定は行ったのに、Amazon Pinpointはオレゴンリージョンにできました...)
すると、変数_amplifyConfigured
がtrue
になって、イベント記録ができるようになったようです。
record event
ボタンをポチッとすると・・・記録されてますね。
Next steps
完成!ここまでは順調。でした。
Authentication
https://docs.amplify.aws/lib/auth/getting-started/q/platform/flutter
Cognito User Poolを使って認証してみます。
が、チュートリアルでId Pool使ってるので、アップデートになる…
なお、Default configuration
にも2つあるので、今回はwithout Social Provider
にしました。(ソーシャル連携は、それはそれで別記事が1つできます)
yuki@taniyamayuukinoMacBook-Air amplify_flutter_sample % amplify update auth
Please note that certain attributes may not be overwritten if you choose to use defaults settings.
You have configured resources that might depend on this Cognito resource. Updating this Cognito resource could have unintended side effects.
Using service: Cognito, provided by: awscloudformation
What do you want to do? Apply default configuration without Social Provider (Federation)
さて、続いてログインのUIは…
なんと自作を要求されました。。。
JavaScript系はUse pre-built UI componentsでAmplifyがUIを提供してくれていたので、ここはかなりがっかりでした。
まあ、仕方なく作りました。
ユーザ名とパスワードでサインアップ、サインインできるかなと推測してやっても、
flutter: Unrecognized auth error returned from platform. See logs for details
とdetailsの行方がわからず、とりあえずユーザプールの設定を見に行くことにしました。
Cognitoユーザプールの設定確認
Eメールアドレスが必須になっていました。1 サインアップ時は、このアドレスを確認することで登録完了とするようで、その画面実装がマストになってしまいました。
ということで、サインアップ、確認コード入力ページ、サインインページを実装し…たところ、思わぬ事象に当たりました。
サインインの戻りに、認可情報(IDトークンなど)がついてこない…
REST APIは、未対応なのでスクラッチでDartでメソッド作って内につけたいのに…っていうか、ユーザの属性照会画面とか、「Hello,〇〇さん」とかでユーザ名欲しい場面あるっしょ。
【解消済み】ログインしたユーザの属性が取れない
下記記載の事象はこのPRによって解消されました。
現在はDocも更新されているので、それに従ってください。
2020年12月現在こちらをみると、
Fetch the current user’s attributes
Invoke the following api to get the list of attributes assigned to the user.
This functionality has not yet been implemented for Flutter, this section will be updated once it has been added.
ギョエェェ、、、
仕方なくIssueを調べると、WorkAroundが出てきました。
https://github.com/aws-amplify/amplify-flutter/issues/201#issuecomment-730822991
final authState = await Amplify.Auth.fetchAuthSession(
options: CognitoSessionOptions(getAWSCredentials: true))
as CognitoAuthSession;
if (authState.isSignedIn) {
final claims = _parseJwt(authState.userPoolTokens.idToken);
final email = claims['email'] as String;
}
fetchAuthSession
でセッション情報を取得し、idToken
(JWT)をパースしclaim
を取得し、そこから属性を取得…という、かなり(主観では)ゴリゴリな実装を求められました。
fetchAuthSession
は、こちらにあるように、トークンリフレッシュも期限切れのタイミングでよしなにやってくれる便利メソッドです。
何はともあれ、これを使って、最初のデモにあるようにHello (ユーザ名)を出せるようになりました。
(見た目上は画面遷移で渡してるだろって思われそうですが、再起動しても同様に表示できていることから、トークンの情報を使えているということでお許しください。)
ちょっと考察
途中でMethodChannel.invokeMethod
のスタックトレースを出してみたりしましたが、結局はAmplify FlutterはiOS版とAndroid版をラップしたインタフェースを実装している段階です。
下記はAWS公式のブログより拝借したものですが、将来的にはDart onlyにして、WebもDesktopもやるぞという心意気だそうです。
ということは、プロダクションレディになるのはその段階なのか?とも思える感覚は、今回Authの実装ひとつとっても持てました。推測にはなりますが、少なくともAuthに関してはかなりの部分がDart onlyで実装できそうですし、APIもその気になればpackage:http
でクライアントはできちゃいそうですし、はてどれだけこれから需要が出てくるのかな?(反語?)っていうのは気になるところでした。
ただ、この思想にはいいところもあって、ちゃんとiOS, Androidのネイティブライブラリ、SDKを遺憾無く使ってくれる2 のは良かったです。今回のサンプルコード、あえて状態管理を超適当にできたのも、認証情報をネイティブ側に持っていってくれてたからですし。Flutterプラグインサードパーティーばっかりなのもな…っていうとっかかりに悩む人にも門戸を広げるきっかけになってくれることを期待はしたいです。
まとめ
Amplify Flutterで、バックエンドの実装をすることなく認証機能を作ることができました。
個人的に作業ログを振り返ると、圧倒的Amplify力不足で申し訳なかったですが、とはいえ結構詰まりそうな所を踏んで解決したという自信も無駄に出てきました。
とりあえず、本番環境では使うな、じゃなくてまだ見た目もよちよち赤ちゃんレベルなので、使う気もあんまり起こらないとは思います(こら)が、それくらいFlutterもといDartは、AWSエンジニアの一部の心を揺さぶってるんだろうなとか想像しました。そしてこのリポジトリ、結構これから険しい道が待っていそうな気がしていますが、頑張って欲しいですね。
→GAされたので、今以上に発展していくことを願って協力していきたいですね。
ということで乱文になってしまいましたが、ありがとうございました。
明日は @muttsu-623 さんです。
参考記事
日本語に限ると、2020/12初旬時点ではこんな感じです。
-
Amplify Flutterを学ぶ
- Authのスニペット付き
-
【速報】Amplify Flutterがリリースされました!(プレビュー)
- AWSブログを翻訳してくれている
-
AWSのハンズオン
- 機械翻訳?RxDartを使っているので、その経験がないとちょっと難しいかもしれない(自分含む)。
-
iOSは認証情報をデフォルトでKeyChainに入れてくれてます ↩