Flutter x AWS Amplifyでアプリを作る
この記事はFlutter Advent Calendar(カレンダー2)の22日目の記事です。
普段私はFlutterでアプリを開発する際はFirebaseと組み合わせてアプリを開発するのですが、
今回はAWSのAmplifyと組み合わせてアプリを作る方法をAWSのチュートリアルを参照しながら実装してみます。
※チュートリアルでのFlutterはバージョンが古いので2系に書き直す必要があります。
作るもの
フォトギャラリーアプリ
今回利用するAmplifyの機能
- Amplify Auth (Cognito) ...ログイン認証
- Amplify Storage (S3) ...ストレージ
- Amplify Analytics (Pinpoint) ...ログ分析
作成する環境
% flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 2.5.3, on macOS 11.6 20G165 darwin-arm, locale ja-JP)
[✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
[✓] Xcode - develop for iOS and macOS
[✓] Chrome - develop for the web
[✓] Android Studio (version 2020.3)
[✓] VS Code (version 1.63.0)
[✓] Connected device (1 available)
Amplifyとは
公式サイトでは以下のように記載されています。
AWS Amplify は、フロントエンドのウェブ/モバイルデベロッパーが AWS でフルスタックアプリケーションをすばやく簡単に構築できるようにする専用のツールとサービスのセットであり、広範な AWS のサービスを活用してさらにアプリケーションをカスタマイズする柔軟性を備えています。
一言でいうと、AWSをmBaaSとして扱うためのプラットフォームだと思って良いかと思います。
クロスプラットフォームのフレームワークにも対応しており、FlutterはもちろんReact NativeやIonicも対応してるみたいです。
Amplifyの機能
公式サイトを見ると、Firebaseとほぼ同等の機能が使えるように見えます。
Amplifyのセットアップ
1. Amplify CLIのインストール
% npm install -g @aws-amplify/cli@flutter-preview
% amplify --version
7.7.0-flutter-preview.1
2. Amplifyの設定
amplify configure
コマンドでAWSがブラウザ上で起動し、IAMユーザーの設定画面が表示されるので最後までデフォルトで進んで、アクセスキーとシークレットキーを取得。
今回は以下の内容で作成
region: ap-northeast-1
user name: amplify-flutter
accessKeyId: IAMユーザー(amplify-flutter)のアクセスキー
secretAccessKey: IAMユーザー(amplify-flutter)のシークレットキー
Profile Name: default
% amplify configure
Follow these steps to set up access to your AWS account:
Sign in to your AWS administrator account:
https://console.aws.amazon.com/
Press Enter to continue
Specify the AWS Region
? region: ap-northeast-1
Specify the username of the new IAM user:
? user name: amplify-flutter
Complete the user creation using the AWS console
Press Enter to continue
Enter the access key of the newly created user:
? accessKeyId: ********************
? secretAccessKey: ****************************************
This would update/create the AWS Profile in your local machine
? Profile Name: default
Successfully set up the new user.
3. Amplifyのプロジェクト初期化
まずはFlutterアプリのプロジェクトのあるディレクトリに移動
% cd path/to/your/project
初期化コマンドのamplify init
を実行
今回は以下の内容で作成
project: flutteramplify
Initialize the project with the above configuration: Yes
Select the authentication method you want to use: AWS access keys
accessKeyId: IAMユーザー(amplify-flutter)のアクセスキー
secretAccessKey: IAMユーザー(amplify-flutter)のシークレットキー
region: ap-northeast-1
% amplify init
Note: It is recommended to run this command from the root of your app directory
? Enter a name for the project flutteramplify
The following configuration will be applied:
Project information
| Name: flutteramplify
| Environment: dev
| Default editor: Visual Studio Code
| App type: flutter
| Configuration file location: ./lib/
? Initialize the project with the above configuration? Yes
Using default provider awscloudformation
? Select the authentication method you want to use: AWS access keys
? accessKeyId: ********************
? secretAccessKey: ****************************************
? region: ap-northeast-1
Adding backend environment dev to AWS Amplify app: d3lihq3zh80btx
⠼ Initializing project in the cloud...
...(略)
✔ Successfully created initial AWS cloud resources for deployments.
✔ Initialized provider successfully.
Initialized your environment successfully.
Your project has been successfully initialized and connected to the cloud!
成功するとプロジェクトのあるディレクトリ直下にamplify
というフォルダが作成されます。
※Githubのパブリックリポジトリなどで管理するときの注意!
.gitignore
に、ある程度amplifyフォルダ内のファイルを除外する設定が書き込まれますが、ignoreには下記の2行を追加しておくことをお勧めします。
amplify/
**/amplifyconfiguration.dart
また、AWSのAmplifyにアクセスするとflutteramplify
が作成されてます。
flutteramplify
をクリックするとdev環境がデプロイされてることが確認できます。
FlutterでAmplifyの接続設定
さて、ここからFlutter側のコーディングを行なっていきます。
amplify_flutter
プラグインを利用します
チュートリアルではamplify_coreのプラグインを使っていますが、amplify_flutterを利用します
dependencies:
amplify_flutter: ^0.2.10
先程のamplify init
でlibの直下にamplifyconfiguration.dart
が作成されており、amplifyconfigを読み込む設定を行います。
Amplifyインスタンスの生成し、amplifyconfiguration.dart
のamplifyconfigを読み込む。
final _amplify = Amplify;
Future<void> _configureAmplify() async {
try {
await _amplify.configure(amplifyconfig);
debugPrint('Successfully configured Amplify 🎉');
} catch (e) {
debugPrint(e.toString());
}
}
Amplifyの認証を使ってみる
Amplifyの設定
次にAmplifyのAuthを使えるようにamplify add auth
を実行します。
今回は以下の内容で作成
configuration: Default configuration
sign in: Username
configure advanced settings: No, I am done.
% amplify add auth
Using service: Cognito, provided by: awscloudformation
The current configured provider is Amazon Cognito.
Do you want to use the default authentication and security configuration? Default configuration
Warning: you will not be able to edit these selections.
How do you want users to be able to sign in? Username
Do you want to configure advanced settings? No, I am done.
✅ Successfully added auth resource flutteramplifya947e592 locally
成功するとamplify/backend/backend-config.json
ファイルにauthの設定内容が書き込まれます。
amplify push
でバックエンドに反映
% amplify push
✔ Successfully pulled backend environment dev from the cloud.
Current Environment: dev
┌──────────┬────────────────────────┬───────────┬───────────────────┐
│ Category │ Resource name │ Operation │ Provider plugin │
├──────────┼────────────────────────┼───────────┼───────────────────┤
│ Auth │ flutteramplifya947e592 │ Create │ awscloudformation │
└──────────┴────────────────────────┴───────────┴───────────────────┘
? Are you sure you want to continue? Yes
...(略)
⠦ Updating resources in the cloud. This may take a few minutes...
UPDATE_COMPLETE amplify-flutteramplify-dev-02235 AWS::CloudFormation::Stack Sun Dec 12 2021 00:49:32 GMT+0900 (Japan Standard Time)
✔ All resources are updated in the cloud
FlutterでAmplifyの認証を実装する
amplify_auth_cognito
プラグインを利用します
dependencies:
amplify_flutter: ^0.2.10
# Add
amplify_auth_cognito: ^0.2.10
先ほどのamplifyconfigの読み込む処理の前にaddPlugins
でAmplifyAuthCognitoを追加します。
final _amplify = Amplify;
Future<void> _configureAmplify() async {
try {
// プラグイン読み込みを追加
await _amplify.addPlugins([AmplifyAuthCognito()]);
await _amplify.configure(amplifyconfig);
debugPrint('Successfully configured Amplify 🎉');
} catch (e) {
debugPrint(e.toString());
}
}
※プラグインの追加方法がパッケージのバージョンアップに伴いチュートリアルとは異なり、複数のプラグインを指定を指定できるのはaddPluginではなくaddPluginsを利用するみたいです。今回はアプリを作るのに3つのプラグインを利用するので、addPluginsに変更してます。
サインアップ処理の実装
チュートリアルにあるようにauth_service.dart
を用意し、signUpWithCredentialsを実装します。
Amplify.Auth.signUp
を使ってAmplifyのAuthでサインアップ処理を行います。
Future<void> signUpWithCredentials(SignUpCredentials credentials) async {
try {
final userAttributes = {'email': credentials.email};
final result = await Amplify.Auth.signUp(
username: credentials.username,
password: credentials.password,
options: CognitoSignUpOptions(userAttributes: userAttributes));
if (result.isSignUpComplete) {
// サインアップ後の処理
} else {
// サインアップ未完了
}
} on AuthException catch (authError) {
debugPrint('Failed to sign up - ${authError.message}');
}
}
次にメールアドレスに飛ばした認証コードを認証するverifyCodeを実装します。Amplify.Auth.confirmSignUp
を使って認証処理を行います。
Future<void> verifyCode(String verificationCode) async {
try {
final result = await Amplify.Auth.confirmSignUp(
username: _credentials.username, confirmationCode: verificationCode);
if (result.isSignUpComplete) {
// サインアップ後の処理
} else {
// サインアップ未完了
}
} on AuthException catch (authError) {
debugPrint('Could not verify code - ${authError.message}');
}
}
サインイン処理の実装
次にサインインを実装していきます。
Amplify.Auth.signIn
を使ってサインイン処理を行います。
Future<void> loginWithCredentials(AuthCredentials credentials) async {
try {
final result = await Amplify.Auth.signIn(
username: credentials.username, password: credentials.password);
if (result.isSignedIn) {
// サインイン後の処理
} else {
// サインイン失敗
}
} on AuthException catch (authError) {
debugPrint('Could not login - ${authError.message}');
}
}
サインアウト処理の実装
最後にサインアウトを実装していきます。
Amplify.Auth.signOut
を使ってサインアウト処理を行います。
Future<void> logOut() async {
try {
await Amplify.Auth.signOut();
// サインアウト後の処理
} on AuthException catch (authError) {
debugPrint('Could not log out - ${authError.message}');
}
}
これで一連の認証まわりの実装ができました。
チュートリアルに沿って画面を作って繋ぎこめば「サインアップ→認証コード→サインイン→サインアウト」の流れが確認できます。
Amplifyのストレージを使ってみる
Amplifyの設定
次にAmplifyのStorageを使えるようにamplify add storage
を実行します。
今回は以下の内容で作成
services: (Images, audio, video, etc.)
access: Auth users only
kind of access: create/update, read, delete
add a Lambda Trigger: no
% amplify add storage
? Select from one of the below mentioned services: Content (Images, audio, video, etc.)
✔ Provide a friendly name for your resource that will be used to label this category in the project: · s3a5a3ee9c
✔ Provide bucket name: · flutteramplify4a4f3f91ac6c4a12a6d790a94488e22d
✔ Who should have access: · Auth users only
✔ What kind of access do you want for Authenticated users? · create/update, read, delete
✔ Do you want to add a Lambda Trigger for your S3 Bucket? (y/N) · no
✅ Successfully added resource s3a5a3ee9c locally
⚠️ If a user is part of a user pool group, run "amplify update storage" to enable IAM group policies for CRUD operations
✅ Some next steps:
"amplify push" builds all of your local backend resources and provisions them in the cloud
"amplify publish" builds all of your local backend and front-end resources (if you added hosting category) and provisions them in the cloud
成功するとamplify/backend/backend-config.json
ファイルにstorageの設定内容が書き込まれます。
amplify push
でバックエンドに反映
% amplify push
✔ Successfully pulled backend environment dev from the cloud.
Current Environment: dev
┌──────────┬────────────────────────┬───────────┬───────────────────┐
│ Category │ Resource name │ Operation │ Provider plugin │
├──────────┼────────────────────────┼───────────┼───────────────────┤
│ Storage │ s3a5a3ee9c │ Create │ awscloudformation │
├──────────┼────────────────────────┼───────────┼───────────────────┤
│ Auth │ flutteramplifya947e592 │ No Change │ awscloudformation │
└──────────┴────────────────────────┴───────────┴───────────────────┘
? Are you sure you want to continue? Yes
...(略)
⠼ Updating resources in the cloud. This may take a few minutes...
✔ All resources are updated in the cloud
Amplify Studio上から見ると以下のようにデプロイされています。
FlutterでAmplifyのストレージを実装する
amplify_storage_s3
プラグインを利用します
dependencies:
amplify_flutter: ^0.2.10
amplify_auth_cognito: ^0.2.10
# Add
amplify_storage_s3: ^0.2.10
Authの時と同様にaddPlugins
でAmplifyStorageS3を追加します。
final _amplify = Amplify;
Future<void> _configureAmplify() async {
try {
// プラグイン読み込みを追加
await _amplify.addPlugins([AmplifyAuthCognito(), AmplifyStorageS3()]);
await _amplify.configure(amplifyconfig);
debugPrint('Successfully configured Amplify 🎉');
} catch (e) {
debugPrint(e.toString());
}
}
ストレージのファイルリストの読み込みとファイル取得処理の実装
チュートリアルにあるようにstorage_service.dart
を用意し、getImagesを実装します。
Amplify.Storage.list
を使ってAmplifyのStorageでファイルのリスト取得して、Amplify.Storage.getUrl
でファイルのURLを取得します。
Future<void> getImages() async {
try {
final listOptions =
S3ListOptions(accessLevel: StorageAccessLevel.private);
final result = await Amplify.Storage.list(options: listOptions);
final getUrlOptions =
GetUrlOptions(accessLevel: StorageAccessLevel.private);
final List<String> imageUrls =
await Future.wait(result.items.map((item) async {
final urlResult =
await Amplify.Storage.getUrl(key: item.key, options: getUrlOptions);
return urlResult.url;
}));
imageUrlsController.add(imageUrls);
} catch (e) {
debugPrint('Storage List error - $e');
}
}
ストレージに画像ファイルをアップロードする処理の実装
次に画像のアップロード処理を実装していきます。
Amplify.Storage.uploadFile
を使ってアップロード処理を行います。
S3UploadFileOptions
でストレージのアクセスレベルをprivate
に設定しておきます。
Future<void> uploadImageAtPath(String imagePath) async {
final imageFile = File(imagePath);
final imageKey = '${DateTime.now().millisecondsSinceEpoch}.jpg';
try {
final options =
S3UploadFileOptions(accessLevel: StorageAccessLevel.private);
await Amplify.Storage.uploadFile(
local: imageFile, key: imageKey, options: options);
getImages();
} catch (e) {
debugPrint('upload error - $e');
}
}
チュートリアルに沿って画面を作って繋ぎこめば「ギャラリー画面でストレージのファイル取得→撮影画面からストレージへのアップロード」の流れが確認できます。
わりと簡単にストレージも実装できました。
AmplifyのAnalyticsを使ってみる
Amplifyの設定
最後にAmplifyのAnalyticsを使ってログを収集してみます。
Analyticsを使えるようにamplify add analytics
を実行します。
今回は以下の内容で作成
an Analytics provider: Amazon Pinpoint
access: Auth users only
allow guests and unauthenticated users to send analytics events: Yes
% amplify add analytics
? Select an Analytics provider Amazon Pinpoint
? Provide your pinpoint resource name: flutteramplify
Auth configuration is required to allow unauthenticated users, but it is not configured properly.
Adding analytics would add the Auth category to the project if not already added.
? Apps need authorization to send analytics events. Do you want to allow guests and unauthenticated users to send analyt
ics events? (we recommend you allow this when getting started) Yes
✅ Successfully updated auth resource locally.
Successfully added resource flutteramplify locally
Some next steps:
"amplify push" builds all of your local backend resources and provisions them in the cloud
"amplify publish" builds all your local backend and front-end resources (if you have hosting category added) and provisions them in the cloud
成功するとamplify/backend/backend-config.json
ファイルにanalyticsの設定内容が書き込まれます。
amplify push
でバックエンドに反映
% amplify push
✔ Successfully pulled backend environment dev from the cloud.
Current Environment: dev
┌───────────┬────────────────────────┬───────────┬───────────────────┐
│ Category │ Resource name │ Operation │ Provider plugin │
├───────────┼────────────────────────┼───────────┼───────────────────┤
│ Analytics │ flutteramplify │ Create │ awscloudformation │
├───────────┼────────────────────────┼───────────┼───────────────────┤
│ Auth │ flutteramplifya947e592 │ Update │ awscloudformation │
├───────────┼────────────────────────┼───────────┼───────────────────┤
│ Storage │ s3a5a3ee9c │ No Change │ awscloudformation │
└───────────┴────────────────────────┴───────────┴───────────────────┘
? Are you sure you want to continue? Yes
...(略)
⠼ Updating resources in the cloud. This may take a few minutes...
✔ All resources are updated in the cloud
Pinpoint URL to track events https://ap-northeast-1.console.aws.amazon.com/pinpoint/home/?region=ap-northeast-1#/apps/****************/analytics/overview
amplify push
の最後にPinpointのURLが表示されており、そこにアクセスすると、Pinpointの分析ダッシュボードにアクセスできます。
FlutterでAmplifyのAnalyticsを実装する
amplify_analytics_pinpoint
プラグインを利用します
dependencies:
amplify_flutter: ^0.2.10
amplify_auth_cognito: ^0.2.10
amplify_storage_s3: ^0.2.10
# Add
amplify_analytics_pinpoint: ^0.2.10
Authの時と同様にaddPlugins
でAmplifyAnalyticsPinpointを追加します。
final _amplify = Amplify;
Future<void> _configureAmplify() async {
try {
// プラグイン読み込みを追加
await _amplify.addPlugins([
AmplifyAuthCognito(),
AmplifyStorageS3(),
AmplifyAnalyticsPinpoint(),
]);
await _amplify.configure(amplifyconfig);
debugPrint('Successfully configured Amplify 🎉');
} catch (e) {
debugPrint(e.toString());
}
}
イベントの定義を実装
分析する特定のイベントの場所で呼び出すためのイベント内容を一つのファイルに定義します。
abstract class AbstractAnalyticsEvent {
AbstractAnalyticsEvent.withName({required String eventName})
: value = AnalyticsEvent(eventName);
AbstractAnalyticsEvent.withEvent({required AnalyticsEvent event})
: value = event;
final AnalyticsEvent value;
}
class LoginEvent extends AbstractAnalyticsEvent {
LoginEvent() : super.withName(eventName: 'login');
}
class SignUpEvent extends AbstractAnalyticsEvent {
SignUpEvent() : super.withName(eventName: 'sign_up');
}
class VerificationEvent extends AbstractAnalyticsEvent {
VerificationEvent() : super.withName(eventName: 'verification');
}
class ViewGalleryEvent extends AbstractAnalyticsEvent {
ViewGalleryEvent() : super.withName(eventName: 'view_gallery');
}
class TakePictureEvent extends AbstractAnalyticsEvent {
factory TakePictureEvent({required String cameraDirection}) {
final event = AnalyticsEvent('take_picture');
event.properties.addStringProperty('camera_direction', cameraDirection);
return TakePictureEvent._fromEvent(event);
}
TakePictureEvent._fromEvent(AnalyticsEvent event)
: super.withEvent(event: event);
}
ログを出力する処理の実装
チュートリアルにあるようにanalytics_service.dart
を用意し、logを実装します。
引数に先ほど実装したanalytics_events.dart
のAbstractAnalyticsEventを渡し、
Amplify.Analytics.recordEvent
を使ってAmplifyのAnalyticsでログを収集します。
class AnalyticsService {
static void log(AbstractAnalyticsEvent event) {
Amplify.Analytics.recordEvent(event: event.value);
}
}
ログを取りたいところにAnalyticsを埋め込む
ログインボタン押下時にログを収集するためにAnalyticsService.log(LoginEvent())
を埋め込みます。
void _login() {
final username = _usernameController.text.trim();
final password = _passwordController.text.trim();
final credentials =
LoginCredentials(username: username, password: password);
widget.didProvideCredentials(credentials);
// ログ収集
AnalyticsService.log(LoginEvent());
}
ログの確認
アプリを実行し、いくつか記録されるようにアプリを動かしたら下記のamplify console
でPinpointダッシュボードを開きます。
今回は以下の内容で作成
site: Amplify Studio
% amplify console
? Which site do you want to open? …
❯ Amplify Studio
AWS console
https://ap-northeast-1.admin.amplifyapp.com/admin/**********/dev/home
Amplify StudioでAnalyticsを開くと、デプロイしたリソースが表示されているので、それをクリックします。
Pinpointが別タブで立ち上がり、「分析 > イベント」をクリックするとイベントが収集されてることが確認できます。
ここまでがチュートリアルでやれることです。
(おまけ)AmplifyとFirebaseとの比較
参考記事
下記の画像で気になったのは、cost
とproject size
。
Firebaseの方がコスト削減向けのようで、プロジェクトサイズに関してはAmplifyは中規模の企業やエンタープライズ向けに対し、Firebaseは小規模の企業も対象になっています。
中小企業やスタートアップのような小さくアプリを作って検証したい時はFirebase。
エンタープライズのような要件が複雑になりそうなものはAmplifyや裏側のAWSを駆使するみたいな構成がいいのかなと感じました。
AmplifyとFirebaseでそれぞれ裏側で利用されてるサービスの一覧
最後に
今回チュートリアルで作ったソース
ソース載せときます。
Discussion