Amplify Flutterを学ぶ

#はじめに

Qiitaで[FlutterとAWSで始めるサービス開発](https://www.makotomi.com/flutter-aws-service/)をまとめていましたが、ついにAWSの公式モバイルアプリ開発のFWである[Amplify](https://aws.amazon.com/jp/amplify/)のFlutterサポート版が登場しました。現在は__Developer Preview__なのでまだまだ途中ですが、早速触っていきたいと思います。今回もCognito連携を中心に見ていきます。
まずは、[Developers.io](https://dev.classmethod.jp/articles/what-new-amplify-flutter/)の記事を見るのをおすすめします。[公式の発表](https://aws.amazon.com/jp/blogs/mobile/announcing-aws-amplify-flutter-developer-preview/)がわかりやすく日本語で解説されています。

#環境構築
[ここ](https://docs.amplify.aws/start/getting-started/setup/q/integration/flutter)を参考にしながら開発環境を作っていきます。以前の連載でVisual Studio Code上にFlutterのプロジェクトを作っているのでそれを前提に進めます。[(1)Windowsでの開発環境構築](https://qiita.com/makotomi/items/2eabe799954259a5427a)と[(2)Flutterのテンプレートアプリを作ってみる](https://qiita.com/makotomi/items/6669970d5a22019e2fbe)まで進んだところが出発点です。
また、Cognitoも[(3)AWS Cognito連携](https://qiita.com/makotomi/items/cb6ccb8568eacf8772dd)で用意したものをそのまま使います。今回はAmprifyのCLIを使ったサーバー側のリソース作成は一切行わず、Library部分の利用を試します。

それでは、実際にAmplifyを入手して実装を始めましょう。FlutterアプリケーションにAmplifyのライブラリを追加します。

``pubspec.yaml``ファイルの__dependencies__セクションに以下2行を追加します。

``` yaml
dependencies:
  flutter:
    sdk: flutter

  amplify_core: "<1.0.0"
  amplify_auth_cognito: "<1.0.0"
```

VS Codeであれば、``pubspec.yaml``ファイルを保存すると自動で__pub get__コマンドが実行されパッケージが取得されます。


#アプリの実装

lib/main.dartを以下に掲載します。

``` dart
import 'package:flutter/material.dart';
import 'package:amplify_core/amplify_core.dart';
import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';

const amplifyconfig = ''' {
  "UserAgent": "aws-amplify-cli/2.0",
  "Version": "1.0",
  "auth": {
    "plugins": {
      "awsCognitoAuthPlugin": {
        "IdentityManager": {"Default": {}},
        "CognitoUserPool": {
          "Default": {
            "PoolId": "ap-northeast-1_********",
            "AppClientId": "**********",
            "Region": "ap-northeast-1"
          }
        },
        "Auth": {
          "Default": {"authenticationFlowType": "USER_SRP_AUTH"}
        }
      }
    }
  }
}''';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final _mailAddressController = TextEditingController();
  final _passwordController = TextEditingController();
  final _verificationController = TextEditingController();

  // Instantiate Amplify
  Amplify amplifyInstance = Amplify();

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      AmplifyAuthCognito authPlugin = AmplifyAuthCognito();
      amplifyInstance.addPlugin(authPlugins: [authPlugin]);
      amplifyInstance.configure(amplifyconfig);
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
      appBar: AppBar(
        title: const Text('Amplify Core example app'),
      ),
      body: Center(
        child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: TextField(
                  decoration: InputDecoration(
                    border: OutlineInputBorder(),
                    hintText: 'test@examle.com',
                    labelText: 'メールアドレス',
                  ),
                  controller: _mailAddressController,
                ),
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: TextField(
                  decoration: InputDecoration(
                    border: OutlineInputBorder(),
                    hintText: 'password',
                    labelText: 'パスワード',
                  ),
                  obscureText: true,
                  controller: _passwordController,
                ),
              ),
              Container(
                alignment: Alignment.centerRight,
                padding: const EdgeInsets.all(8.0),
                child: RaisedButton(
                  child: Text('登録'),
                  color: Colors.indigo,
                  shape: StadiumBorder(),
                  textColor: Colors.white,
                  onPressed: () => _singUp(),
                ),
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: TextField(
                  decoration: InputDecoration(
                    border: OutlineInputBorder(),
                    hintText: '012345',
                    labelText: '確認コード',
                  ),
                  controller: _verificationController,
                ),
              ),
              Container(
                alignment: Alignment.centerRight,
                padding: const EdgeInsets.all(8.0),
                child: RaisedButton(
                  child: Text('登録確認'),
                  color: Colors.indigo,
                  shape: StadiumBorder(),
                  textColor: Colors.white,
                  onPressed: () => _confirmSignUp(),
                ),
              ),
              Container(
                alignment: Alignment.centerRight,
                padding: const EdgeInsets.all(8.0),
                child: RaisedButton(
                  child: Text('ログイン'),
                  color: Colors.indigo,
                  shape: StadiumBorder(),
                  textColor: Colors.white,
                  onPressed: () => _signIn(),
                ),
              ),
            ]),
      ),
    ));
  }

  void _singUp() async {
    try {
      Map<String, dynamic> userAttributes = {
        "email": _mailAddressController.text
        // additional attributes as needed
      };
      SignUpResult res = await Amplify.Auth.signUp(
          username: _mailAddressController.text,
          password: _passwordController.text,
          options: CognitoSignUpOptions(userAttributes: userAttributes));
      print(res.isSignUpComplete);
    } on AuthError catch (error) {
      print(error.cause);
    }
  }

  void _confirmSignUp() async {
    try {
      SignUpResult res = await Amplify.Auth.confirmSignUp(
          username: _mailAddressController.text,
          confirmationCode: _verificationController.text);
      print(res.isSignUpComplete);
    } on AuthError catch (error) {
      print(error.cause);
    }
  }

  void _signIn() async {
    try {
      SignInResult res = await Amplify.Auth.signIn(
          username: _mailAddressController.text,
          password: _passwordController.text);
      print(res.isSignedIn);
    } on AuthError catch (error) {
      print(error.cause);
    }
  }
}

```

## Cognitoの設定
__amplifyconfig__はすでにあるCognitoユーザープールを利用する場合の設定値です。__PoolId__、__AppClientId__、__Region__を各自の設定で書き換えてください。

## Amplifyの初期化
アプリ起動時初回にのみ実行されるように__initState__で__WidgetsBinding.instance.addPostFrameCallback((_)__使って初期化コードを書きます。認証用のプラグインとユーザープールを設定します。

## ユーザー登録からログインの処理

[(4)AWS Cognitoへの新規アカウント登録](https://qiita.com/makotomi/items/d2e399d16c0931ad3228)と[(5)AWS Cognitoでログイン](https://qiita.com/makotomi/items/a0b05e8819270072780b)の流れと同じです。
新規アカウントの登録 (**_signUp**)、メール受信した確認コードを入力しアカウント有効化(**_confirmSignUp**)、ログイン(**_signIn**)という流れで同じことができます。

# まとめ
まずはとっかかりとしてここまでとしたいと思います。パスワードをちゃんと入れなくてもSignInができてしまったりして少し怪しい動きをしているので、その辺は次回以降にもう少し見ていきたいと思います。