こんにちは、CX事業本部 Delivery部の若槻です。
前々回はFlutterアプリでMaterialAppを使って画面を切り替える方法を確認しました。
また前回は四苦八苦しながらもCognito user poolでHoeted UIを使えるようにする実装を行いました。
今回は、これらの合わせ技として、Flutter(iOS)アプリでAmzon Cognitoの認証状態に応じて画面を切り替える実装をしてみました。
実装
実装していきます。
ちなみにFlutter上でのHosted UIの実装部分は高橋雄大さんの次のエントリを大いに参考にさせて頂きました。
iOSのプロパティ設定
iOSのプロパティ設定にアプリのURL(User pool clientのコールバックURLに指定した<myapp>://
という記述の<myapp>
)を追加します。
ios/Runner/info.plist
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
</dict>
</array>
Amplifyパッケージのインストール
flutter pub add amplify_auth_cognito
flutter pub add amplify_flutter
コンフィグファイル作成
Amplifyの設定ファイルamplifyconfiguration.dart
を作成します。User poolの情報を設定値として指定します。
lib/amplifyconfiguration.dart
const amplifyconfig = '''{
"auth": {
"plugins": {
"awsCognitoAuthPlugin": {
"CognitoUserPool": {
"Default": {
"PoolId": "<COGNITO USER POOL ID>",
"AppClientId": "<COGNITO USER POOL APP CLIENT ID>",
"Region": "<REGION>"
}
},
"Auth": {
"Default": {
"OAuth": {
"WebDomain": "<COGNITO WEB DOMAIN>",
"AppClientId": "<COGNITO USER POOL APP CLIENT ID>",
"SignInRedirectURI": "<myapp>://",
"SignOutRedirectURI": "<myapp>://",
"Scopes": [
"email",
"openid",
"profile"
]
}
}
}
}
}
}
}''';
注意点として、WebDomain
で指定する値は<myapp>.auth.<region>.amazoncognito.com
となります。(`https://`は含めないように注意)
認証間利用プロバイダー
認証状態の管理はproviderを使用しています。AmplifyのSDKを使用したサインイン/サインアウトのFutureもプロバイダー内で実装しています。
lib/auth_provider.dart
import 'package:flutter/material.dart';
import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
import 'package:amplify_flutter/amplify_flutter.dart';
import 'amplifyconfiguration.dart';
class AuthProvider extends ChangeNotifier {
bool signedIn = false;
Future<void> _configure() async {
if (!Amplify.isConfigured) {
await Amplify.addPlugin(AmplifyAuthCognito());
await Amplify.configure(amplifyconfig);
}
try {
await Amplify.Auth.getCurrentUser();
signedIn = true;
} on AuthException {
signedIn = false;
}
notifyListeners();
}
AuthProvider() {
_configure();
}
Future<void> signIn() async {
try {
await Amplify.Auth.signInWithWebUI();
signedIn = true;
} on AuthException {
signedIn = false;
}
notifyListeners();
}
Future<void> signOut() async {
try {
await Amplify.Auth.signOut();
signedIn = false;
} on AuthException {
signedIn = true;
}
notifyListeners();
}
}
サインイン画面
サインイン画面です。ログインボタンが表示されます。
lib/signin_screen.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import './auth_provider.dart';
class AuthScreen extends StatefulWidget {
const AuthScreen({Key? key}) : super(key: key);
@override
State<AuthScreen> createState() => _AuthScreenState();
}
class _AuthScreenState extends State<AuthScreen> {
@override
Widget build(BuildContext context) {
final AuthProvider authProvider = context.watch<AuthProvider>();
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('My App')),
body: Center(
child: Center(
child: ElevatedButton(
child: const Text('Login'),
onPressed: () {
authProvider.signIn();
})),
),
),
);
}
}
ホーム画面
サインイン後にアクセスできるホーム画面です。ログアウトボタンが表示されます。
lib/home_screen.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import './auth_provider.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
@override
Widget build(BuildContext context) {
final AuthProvider authProvider = context.watch<AuthProvider>();
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('My App')),
body: Center(
child: Center(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
),
child: const Text('ログアウト'),
onPressed: () {
authProvider.signOut();
})),
),
));
}
}
認証状態に応じた画面の切り替え
認証状態に応じて画面を切り替える実装はmain.dart
でプロバイダーの値を元に行っています。
lib/main.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import './auth_provider.dart';
import './signin_screen.dart';
import './home_screen.dart';
void main() => runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => AuthProvider()),
],
child: const MyApp(),
),
);
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
final AuthProvider authProvider = context.watch<AuthProvider>();
return MaterialApp(
home: authProvider.signedIn ? const HomeScreen() : const AuthScreen());
}
}
動作確認
iOS Simulatorでアプリを起動します。
flutter run -d 2CA618C6-E1DF-42E2-B555-541EE8A289B3
アプリが起動しました。未ログインなのでサインイン画面が表示されています。
Login
ボタンをクリックするとCognitoのHosted UIが表示されます。サインアップまたはサインインを行います。
サインインに成功するとホーム画面が表示されました。
Logout
ボタンをクリックすると、サインアウトが行われてサインイン画面に戻りました。
おわりに
Flutter(iOS)アプリでAmzon Cognitoの認証状態に応じて画面を切り替える実装をしてみました。
今回のアプリは2画面だけでしたが、実際のアプリはさらに柔軟な画面遷移を行うことになります。次回以降でまた実装を紹介します。
以上