Flutter에서 Amplify Auth를 사용하는 방법

96781 단어 awsiostutorialflutter
올해 목표 중 하나는 Apple App Store에 내 App KidzTokenz를 게시하는 것입니다. 이를 위해 Flutter와 AWSAmplify를 사용할 계획입니다.









모 말라카 | 동기 부여 | 긍정적 인 영향


@mohammedmalaka






작업 & 재미있다


오후 16:51 - 2021년 1월 5일









이 게시물에서는 Auth 카테고리를 Flutter 앱에 통합하고 iOS에서 실행합니다.

증폭 설정



Amplify Admin UI를 사용하여 백엔드를 생성하겠습니다. 이전 게시물(아래 링크)에서 공유한 지침을 사용하여 이름(AuthFlutter)의 프로젝트를 만듭니다.




인증을 구성하고 배포합니다. 확인을 위해 (이메일)을 사용할 예정입니다.



프로젝트 설정



터미널을 사용하여 아래 명령을 실행하여 새 flutter 프로젝트를 만듭니다.


flutter create auth_for_flutter



다음으로 VS Code를 사용하여 프로젝트 폴더를 열겠습니다. 통합 터미널이 ios 폴더에 있는지 확인하십시오.



다음 명령을 실행하면 ios 폴더에 Podfile이 생성됩니다.


sudo gem install cocoapods

pod init



아래와 같이 Podile을 업데이트합니다.


platform :ios, '13.0'

# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'

project 'Runner', {
  'Debug' => :debug,
  'Profile' => :release,
  'Release' => :release,
}

def flutter_root
  generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
  unless File.exist?(generated_xcode_build_settings_path)
    raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
  end

  File.foreach(generated_xcode_build_settings_path) do |line|
    matches = line.match(/FLUTTER_ROOT\=(.*)/)
    return matches[1].strip if matches
  end
  raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end

require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)

flutter_ios_podfile_setup

target 'Runner' do
  use_frameworks!
  use_modular_headers!

  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end

post_install do |installer|
  installer.pods_project.targets.each do |target|
    flutter_additional_ios_build_settings(target)
  end
end




XCode의 프로젝트 네비게이터에서 프로젝트를 선택하고 "정보"탭을 선택합니다. 배포 대상을 13.0 이상으로 설정합니다.



앱의 pubspec.yaml을 열고 "sdk:flutter"줄 아래에 다음 종속성을 추가합니다.


dependencies:
  flutter:
    sdk: flutter
  amplify_core: '<1.0.0'
  amplify_auth_cognito: '<1.0.0'



ios 폴더에서 아래 명령을 실행하십시오.


pod install



필요한 Pod를 설치합니다.



앱의 루트 폴더에 있는 Admin UI에서 풀 명령을 실행하여 위에서 생성한 Amplify 백엔드를 풀다운합니다.



프롬프트된 질문에 답하고 완료되면 아래와 같이 확인 메시지를 받게 됩니다.


Added backend environment config object to your project.
Run 'amplify pull' to sync upstream changes.



앱의 pubspec.yaml을 업데이트하여 사용할 이미지 파일을 추가합니다.


# To add assets to your application, add an assets section, like this:
  assets:
     - assets/images/applogo.png



앱을 실행하여 성공적으로 빌드되는지 확인합니다.



구현



인증 상태에 열거형을 사용할 것입니다. (lib) 폴더에 아래 파일을 생성합니다.

account_screens_enum.dart





enum AccountStatus {
  sign_in,
  sign_up,
  reset_password,
  confirm_code,
  main_screen
}



다음으로 (lib\widgets) 폴더에 위젯을 생성해 보겠습니다.

sign_up.dart



계정을 만들려면.


import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
import 'package:amplify_core/amplify_core.dart';
import 'package:auth_for_flutter/account_screens_enum.dart';
import 'package:auth_for_flutter/widgets/confirm_signup.dart';
import 'package:auth_for_flutter/widgets/error_view.dart';
import 'package:flutter/material.dart';

class SignUpView extends StatefulWidget {
  final Function _displayAccountWidget;

  const SignUpView(this._displayAccountWidget);

  @override
  _SignUpViewState createState() => _SignUpViewState();
}

class _SignUpViewState extends State<SignUpView> {
  final emailController = TextEditingController();
  final passwordController = TextEditingController();
  bool _isSignedUp = false;
  DateTime signupDate;

  String _signUpError = "";
  List<String> _signUpExceptions = [];

  @override
  void initState() {
    super.initState();
  }

  void _setError(AuthError error) {
    setState(() {
      _signUpError = error.cause;
      _signUpExceptions.clear();
      error.exceptionList.forEach((el) {
        _signUpExceptions.add(el.exception);
      });
    });
  }

  void _signUp(BuildContext context) async {
    try {
      Map<String, dynamic> userAttributes = {
        "email": emailController.text.trim(),
        "preferred_username": emailController.text.trim(),
        // additional attributes as needed
      };
      SignUpResult res = await Amplify.Auth.signUp(
          username: emailController.text.trim(),
          password: passwordController.text.trim(),
          options: CognitoSignUpOptions(userAttributes: userAttributes));

      print(res.isSignUpComplete);
      setState(() {
        _isSignedUp = true;
      });
    } on AuthError catch (error) {
      _setError(error);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Card(
      elevation: 2,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: <Widget>[
          Expanded(
            child: Padding(
              padding: EdgeInsets.all(10.0),
              child: Column(
                children: [
                  Visibility(
                    visible: !_isSignedUp,
                    child: Column(children: [
                      TextFormField(
                        enableSuggestions: false,
                        decoration: const InputDecoration(
                          icon: Icon(Icons.email),
                          hintText: 'Email',
                          labelText: 'Email *',
                        ),
                        controller: emailController,
                        keyboardType: TextInputType.emailAddress,
                      ),
                      TextFormField(
                        obscureText: true,
                        enableSuggestions: false,
                        autocorrect: false,
                        decoration: const InputDecoration(
                          icon: Icon(Icons.lock),
                          hintText: 'Password',
                          labelText: 'Password *',
                        ),
                        controller: passwordController,
                      ),
                      const Padding(padding: EdgeInsets.all(10.0)),
                      FlatButton(
                        textColor:
                            Colors.black, // Theme.of(context).primaryColor,
                        color: Colors.amber,
                        onPressed: () => _signUp(context),
                        child: Text(
                          'Create Account',
                          style: TextStyle(fontWeight: FontWeight.bold),
                        ),
                      ),
                      FlatButton(
                        height: 5,
                        onPressed: _displaySignIn,
                        child: Text(
                          'Already registered? Sign In',
                          style: Theme.of(context).textTheme.subtitle2,
                        ),
                      ),
                    ]),
                  ),
                  Visibility(
                      visible: _isSignedUp,
                      child: Column(children: [
                        ConfirmSignup(emailController.text.trim(), _setError),
                      ])),
                  ErrorView(_signUpError, _signUpExceptions)
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }

  void _displaySignIn() {
    widget._displayAccountWidget(AccountStatus.sign_in.index);
  }
}





Confirm_signup.dart



가입 확인 코드를 제출합니다.


import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
import 'package:amplify_core/amplify_core.dart';
import 'package:auth_for_flutter/screens/next_screen.dart';
import 'package:flutter/material.dart';

class ConfirmSignup extends StatelessWidget {
  final codeController = TextEditingController();
  final String userName;
  final Function setError;

  ConfirmSignup(this.userName, this.setError);

  void _skip_confirm_signup(BuildContext context) {
    _go_to_NextScreen(context);
  }

  void _confirm_signup(BuildContext context) async {
    try {
      SignUpResult res = await Amplify.Auth.confirmSignUp(
          username: this.userName,
          confirmationCode: codeController.text.trim());

      _go_to_NextScreen(context);
    } on AuthError catch (e) {
      setError(e);
    }
  }

  void _go_to_NextScreen(BuildContext context) {
    Navigator.of(context).pushReplacement(
      MaterialPageRoute(
        builder: (_) {
          return NextScreen();
        },
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      // decoration: BoxDecoration(borderRadius: BorderRadius.circular(20)),
      padding: EdgeInsets.all(5),
      child: Column(
        children: [
          TextFormField(
              controller: codeController,
              decoration: const InputDecoration(
                icon: Icon(Icons.confirmation_number),
                hintText: 'The code we sent you',
                labelText: 'Confirmation Code *',
              )),
          FlatButton(
            textColor: Colors.black, // Theme.of(context).primaryColor,
            color: Colors.amber,
            onPressed: () => _confirm_signup(context),
            child: Text(
              'Confirm Sign Up',
              style: TextStyle(fontWeight: FontWeight.bold),
            ),
          ),
        ],
      ),
    );
  }
}




reset_password.dart



암호 재설정 작업을 요청합니다.


import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
import 'package:amplify_core/amplify_core.dart';
import 'package:auth_for_flutter/account_screens_enum.dart';
import 'package:auth_for_flutter/widgets/confirm_reset_password.dart';
import 'package:auth_for_flutter/widgets/error_view.dart';
import 'package:flutter/material.dart';

class ResetPasswordView extends StatefulWidget {
  final Function _displayAccountWidget;

  const ResetPasswordView(this._displayAccountWidget);

  @override
  _ResetPasswordViewState createState() => _ResetPasswordViewState();
}

class _ResetPasswordViewState extends State<ResetPasswordView> {
  final emailController = TextEditingController();
  bool _isPasswordReset = false;

  String _signUpError = "";
  List<String> _signUpExceptions = [];

  @override
  void initState() {
    super.initState();
  }

  void _setError(AuthError error) {
    setState(() {
      _signUpError = error.cause;
      _signUpExceptions.clear();
      error.exceptionList.forEach((el) {
        _signUpExceptions.add(el.exception);
      });
    });
  }

  void _resetPassword(BuildContext context) async {
    try {
      ResetPasswordResult res = await Amplify.Auth.resetPassword(
        username: emailController.text.trim(),
      );

      setState(() {
        _isPasswordReset = true;
      });
    } on AuthError catch (e) {
      setState(() {
        _signUpError = e.cause;
        _signUpExceptions.clear();
        e.exceptionList.forEach((el) {
          _signUpExceptions.add(el.exception);
        });
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Card(
      elevation: 2,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: <Widget>[
          Expanded(
            child: Padding(
              padding: EdgeInsets.all(10.0),
              child: Column(
                children: [
                  Visibility(
                    visible: !_isPasswordReset,
                    child: Column(children: [
                      TextFormField(
                        enableSuggestions: false,
                        decoration: const InputDecoration(
                          icon: Icon(Icons.email),
                          hintText: 'Email',
                          labelText: 'Email *',
                        ),
                        controller: emailController,
                        keyboardType: TextInputType.emailAddress,
                      ),
                      const Padding(padding: EdgeInsets.all(10.0)),
                      FlatButton(
                        textColor:
                            Colors.black, // Theme.of(context).primaryColor,
                        color: Colors.amber,
                        onPressed: () => _resetPassword(context),
                        child: Text(
                          'Reset Password',
                          style: TextStyle(fontWeight: FontWeight.bold),
                        ),
                      ),
                      FlatButton(
                        height: 5,
                        onPressed: _displayCreateAccount,
                        child: Text(
                          'Create Account',
                          style: Theme.of(context).textTheme.subtitle2,
                        ),
                      ),
                    ]),
                  ),
                  Visibility(
                      visible: _isPasswordReset,
                      child: Column(children: [
                        ConfirmResetPassword(
                            emailController.text.trim(), _setError),
                      ])),
                  ErrorView(_signUpError, _signUpExceptions)
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }

  void _displayCreateAccount() {
    widget._displayAccountWidget(AccountStatus.sign_up.index);
  }
}




Confirm_reset_password.dart



확인 코드와 새 비밀번호를 제출합니다.


import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
import 'package:amplify_core/amplify_core.dart';
import 'package:auth_for_flutter/screens/next_screen.dart';
import 'package:flutter/material.dart';

class ConfirmResetPassword extends StatelessWidget {
  final codeController = TextEditingController();
  final emailController = TextEditingController();
  final passwordController = TextEditingController();
  final String userName;
  final Function setError;

  ConfirmResetPassword(this.userName, this.setError);

  void _confirm_password_reset(BuildContext context) async {
    try {
      await Amplify.Auth.confirmPassword(
          username: this.userName,
          newPassword: passwordController.text.trim(),
          confirmationCode: codeController.text.trim());
      _go_to_NextScreen(context);
    } on AuthError catch (e) {
      setError(e);
    }
  }

  void _go_to_NextScreen(BuildContext context) {
    Navigator.of(context).pushReplacement(
      MaterialPageRoute(
        builder: (_) {
          return NextScreen();
        },
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      // decoration: BoxDecoration(borderRadius: BorderRadius.circular(20)),
      padding: EdgeInsets.all(5),
      child: Column(
        children: [
          TextFormField(
            enableSuggestions: false,
            decoration: const InputDecoration(
              icon: Icon(Icons.email),
              hintText: 'Email',
              labelText: 'Email *',
            ),
            controller: emailController,
            keyboardType: TextInputType.emailAddress,
          ),
          TextFormField(
            obscureText: true,
            enableSuggestions: false,
            autocorrect: false,
            decoration: const InputDecoration(
              icon: Icon(Icons.lock),
              hintText: 'New Password',
              labelText: 'New Password *',
            ),
            controller: passwordController,
          ),
          TextFormField(
              controller: codeController,
              decoration: const InputDecoration(
                icon: Icon(Icons.confirmation_number),
                hintText: 'The code we sent you',
                labelText: 'Confirmation Code *',
              )),
          FlatButton(
            textColor: Colors.black, // Theme.of(context).primaryColor,
            color: Colors.amber,
            onPressed: () => _confirm_password_reset(context),
            child: Text(
              'Reset Password & Sign In',
              style: TextStyle(fontWeight: FontWeight.bold),
            ),
          ),
        ],
      ),
    );
  }
}




sign_in.dart



로그인 작업


import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
import 'package:amplify_core/amplify_core.dart';
import 'package:auth_for_flutter/account_screens_enum.dart';
import 'package:auth_for_flutter/screens/next_screen.dart';
import 'package:auth_for_flutter/widgets/error_view.dart';
import 'package:flutter/material.dart';

class SignInView extends StatefulWidget {
  final Function _displayAccountWidget;

  const SignInView(this._displayAccountWidget);

  @override
  _SignInViewState createState() => _SignInViewState();
}

class _SignInViewState extends State<SignInView> {
  final emailController = TextEditingController();
  final passwordController = TextEditingController();
  String _signUpError = "";
  List<String> _signUpExceptions = [];

  @override
  void initState() {
    super.initState();
  }

  void _setError(AuthError error) {
    setState(() {
      _signUpError = error.cause;
      _signUpExceptions.clear();
      error.exceptionList.forEach((el) {
        _signUpExceptions.add(el.exception);
      });
    });
  }

  void _signIn() async {
    // Sign out before in case a user is already signed in
    // If a user is already signed in - Amplify.Auth.signIn will throw an exception
    try {
      await Amplify.Auth.signOut();
    } on AuthError catch (e) {
      print(e);
    }

    try {
      SignInResult res = await Amplify.Auth.signIn(
          username: emailController.text.trim(),
          password: passwordController.text.trim());
      _go_to_NextScreen(context);
    } on AuthError catch (e) {
      setState(() {
        _signUpError = e.cause;
        _signUpExceptions.clear();
        e.exceptionList.forEach((el) {
          _signUpExceptions.add(el.exception);
        });
      });
    }
  }

  void _go_to_NextScreen(BuildContext context) {
    Navigator.of(context).pushReplacement(
      MaterialPageRoute(
        builder: (_) {
          return NextScreen();
        },
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Card(
      elevation: 2,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: <Widget>[
          Expanded(
            // wrap your Column in Expanded
            child: Padding(
              padding: EdgeInsets.all(10.0),
              child: Column(
                children: [
                  TextFormField(
                    controller: emailController,
                    decoration: const InputDecoration(
                      icon: Icon(Icons.email),
                      hintText: 'Enter your email',
                      labelText: 'Email *',
                    ),
                  ),
                  TextFormField(
                    obscureText: true,
                    controller: passwordController,
                    decoration: const InputDecoration(
                      icon: Icon(Icons.lock),
                      hintText: 'Enter your password',
                      labelText: 'Password *',
                    ),
                  ),
                  const Padding(padding: EdgeInsets.all(10.0)),
                  FlatButton(
                    textColor: Colors.black, // Theme.of(context).primaryColor,
                    color: Colors.amber,
                    onPressed: _signIn,
                    child: const Text(
                      'Sign In',
                      style: TextStyle(fontWeight: FontWeight.bold),
                    ),
                  ),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                    children: <Widget>[
                      FlatButton(
                        height: 5,
                        onPressed: _displayCreateAccount,
                        child: Text(
                          'Create Account',
                          style: Theme.of(context).textTheme.subtitle2,
                        ),
                      ),
                      FlatButton(
                        height: 5,
                        onPressed: _displayResetPassword,
                        child: Text(
                          'Reset Password',
                          style: Theme.of(context).textTheme.subtitle2,
                        ),
                      ),
                    ],
                  ),
                  ErrorView(_signUpError, _signUpExceptions)
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }

  void _displayCreateAccount() {
    widget._displayAccountWidget(AccountStatus.sign_up.index);
  }

  void _displayResetPassword() {
    widget._displayAccountWidget(AccountStatus.reset_password.index);
  }
}




error_view.dart



오류 메시지를 표시합니다.


import 'package:flutter/material.dart';

class ErrorView extends StatelessWidget {
  final String error;
  final List<String> exceptions;

  ErrorView(this.error, this.exceptions);

  @override
  Widget build(BuildContext context) {
    // We do not recognize your username and/or password. Please try again.
    if (error.isNotEmpty || exceptions.length > 0) {
      return Column(children: <Widget>[
        Text('Error: $error',
            textAlign: TextAlign.center,
            overflow: TextOverflow.visible,
            style: TextStyle(
              fontWeight: FontWeight.bold,
              color: Theme.of(context).errorColor,
            )),
        if (exceptions.length > 0) ...[_showExceptions(context)]
      ]);
    } else {
      return Container();
    }
  }

  _showExceptions(context) {
    return Column(
        children: exceptions
            .map((item) => new Text(item + " ",
                style: TextStyle(
                  fontWeight: FontWeight.bold,
                  color: Theme.of(context).errorColor,
                )))
            .toList());
  }
}




앱에는 세 개의 화면이 있습니다. (lib\screens) 폴더에 아래 화면을 생성합니다.

loading_screen.dart





import 'package:flutter/material.dart';

class LoadingScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('BatMan App')),
      body: Container(
        color: Color(0xff90CCE6),
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Container(
                color: Color(0xffE1E5E4),
                height: 200,
                child: Image.asset(
                  'assets/images/applogo.png',
                  fit: BoxFit.cover,
                ),
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Center(
                  child: CircularProgressIndicator(),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}




main_screen.dart





import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
import 'package:amplify_core/amplify_core.dart';
import 'package:auth_for_flutter/account_screens_enum.dart';
import 'package:auth_for_flutter/screens/next_screen.dart';
import 'package:auth_for_flutter/widgets/reset_password.dart';
import 'package:auth_for_flutter/widgets/sign_in.dart';
import 'package:auth_for_flutter/widgets/sign_up.dart';
import 'package:flutter/material.dart';

class MainScreen extends StatefulWidget {
  @override
  _MainScreenState createState() => _MainScreenState();
}

class _MainScreenState extends State<MainScreen> {
  var _accountWidget;

  @override
  initState() {
    super.initState();
    _fetchSession();
  }

  void _fetchSession() async {
    // Sign out before in case a user is already signed in
    try {
      await Amplify.Auth.signOut();
    } on AuthError catch (e) {
      print(e);
    }
    _accountWidget = AccountStatus.sign_in.index;
    _displayAccountWidget(_accountWidget);
  }

  void _go_to_NextScreen(BuildContext context) {
    Navigator.of(context).pushReplacement(
      MaterialPageRoute(
        builder: (_) {
          return NextScreen();
        },
      ),
    );
  }

  void _displayAccountWidget(int accountStatus) {
    setState(() {
      _accountWidget = AccountStatus.values[accountStatus];
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('BatMan App'),
      ),
      body: Container(
        color: Color(0xffE1E5E4),
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Container(
                color: Color(0xffE1E5E4),
                height: 200,
                child: Image.asset(
                  'assets/images/applogo.png',
                  fit: BoxFit.cover,
                ),
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Column(children: [
                  Visibility(
                    visible: _accountWidget == AccountStatus.sign_in,
                    child: SignInView(_displayAccountWidget),
                  ),
                  Visibility(
                    visible: _accountWidget == AccountStatus.sign_up,
                    child: SignUpView(_displayAccountWidget),
                  ),
                  Visibility(
                    visible: _accountWidget == AccountStatus.reset_password,
                    child: ResetPasswordView(_displayAccountWidget),
                  ),
                  Visibility(
                    visible: _accountWidget == AccountStatus.main_screen,
                    child: NextScreen(),
                  ),
                ]),
              ),
            ],
          ),
        ),
      ),
    );
  }
}




next_screen.dart





import 'package:auth_for_flutter/screens/main_screen.dart';
import 'package:flutter/material.dart';

class NextScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('BatMan App')),
      body: Container(
        color: Color(0xffE1E5E4),
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Container(
                color: Color(0xffE1E5E4),
                height: 200,
                child: Image.asset(
                  'assets/images/applogo.png',
                  fit: BoxFit.cover,
                ),
              ),
              Padding(
                padding: const EdgeInsets.all(20.0),
                child: Center(
                  child: Text(
                    'I\'m BATMAN',
                    style: TextStyle(fontWeight: FontWeight.bold, fontSize: 30),
                  ),
                ),
              ),
              Padding(
                padding: const EdgeInsets.all(20.0),
                child: Center(
                  child: RaisedButton(
                    color: Colors.lightBlue,
                    onPressed: () => _signOut(context),
                    child: Text(
                      'Sign Out',
                      style: TextStyle(
                        fontWeight: FontWeight.bold,
                        fontSize: 20,
                      ),
                    ),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }

  void _signOut(BuildContext context) {
    Navigator.of(context).pushReplacement(
      MaterialPageRoute(
        builder: (_) {
          return MainScreen();
        },
      ),
    );
  }
}





앱 실행





코드 확인here

Follow me on for more tips about #coding, #learning, #technology...etc.

Check my Apps on Google Play

Cover image Obi Onyeador on Unsplash

좋은 웹페이지 즐겨찾기