로메오의 블로그

Flutter Firebase login 본문

App & OS/Hybrid

Flutter Firebase login

romeoh 2024. 9. 8. 16:18
반응형

화면디자인

main.dart

import 'package:flutter/material.dart';
import 'firebase_login_screen.dart';
import 'firebase_signup_screen.dart';
import 'firebase_success_screen.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      routes: {
        '/login': (context) => const FirebaseLoginScreen(),
        '/signup': (context) => const FirebaseSignupScreen(),
        '/success': (context) => const FirebaseSuccessScreen(),
      },
      title: 'Navigation Example',
      home: const HomeScreen(),
    );
  }
}

 

 

 

 

 

 

firebase_login_screen.dart

import 'package:flutter/material.dart';

class FirebaseLoginScreen extends StatefulWidget {
  const FirebaseLoginScreen({super.key});

  @override
  // ignore: library_private_types_in_public_api
  _FirebaseLoginPageState createState() => _FirebaseLoginPageState();
}

class _FirebaseLoginPageState extends State<FirebaseLoginScreen> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('Firebase Login'),
        ),

        // body
        body: Padding(
          padding: const EdgeInsets.all(15),
          child: Column(
            children: [
              const TextField(
                decoration: InputDecoration(labelText: 'Email'),
              ),
              const TextField(
                decoration: InputDecoration(labelText: 'Password'),
              ),
              const SizedBox(height: 20),
              ElevatedButton(
                  onPressed: () {
                    Navigator.pushNamed(context, '/success');
                  },
                  child: const Text('로그인')),
              TextButton(
                  onPressed: () {
                    Navigator.pushNamed(context, '/signup');
                  },
                  child: const Text('회원가입 '))
            ],
          ),
        ));
  }
}

 

 

 

 

 

 

 

 

firebase_signup_screen.dart

import 'package:flutter/material.dart';

class FirebaseSignupScreen extends StatefulWidget {
  const FirebaseSignupScreen({super.key});

  @override
  // ignore: library_private_types_in_public_api
  _FirebaseSignupPageState createState() => _FirebaseSignupPageState();
}

class _FirebaseSignupPageState extends State<FirebaseSignupScreen> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('Firebase Login'),
        ),

        // body
        body: Padding(
          padding: const EdgeInsets.all(15),
          child: Column(
            children: [
              const TextField(
                decoration: InputDecoration(labelText: 'Email'),
              ),
              const TextField(
                decoration: InputDecoration(labelText: 'Password'),
              ),
              const TextField(
                decoration: InputDecoration(labelText: 'Confirm Password'),
              ),
              const SizedBox(height: 20),
              TextButton(
                  onPressed: () {
                    Navigator.pushNamed(context, '/signup');
                  },
                  child: const Text('회원가입 '))
            ],
          ),
        ));
  }
}

 

 

 

 

 

 

firebase_success_screen.dart

import 'package:flutter/material.dart';

class FirebaseSuccessScreen extends StatefulWidget {
  const FirebaseSuccessScreen({super.key});

  @override
  // ignore: library_private_types_in_public_api
  _FirebaseSuccessPageState createState() => _FirebaseSuccessPageState();
}

class _FirebaseSuccessPageState extends State<FirebaseSuccessScreen> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('Firebase Login'),
        ),

        // body
        body: Padding(
          padding: const EdgeInsets.all(15),
          child: Column(
            children: [
              const Text(
                "로그인 성공",
                style: TextStyle(fontSize: 20),
              ),
              const SizedBox(height: 20),
              ElevatedButton(
                  onPressed: () {
                    Navigator.pushNamed(context, '/login');
                  },
                  child: const Text('로그아웃'))
            ],
          ),
        ));
  }
}

 

 

 

 

 

 

Firebase tools

## firebase tools 설치
$ npm install -g firebase-tools
$ firebase --version                
13.16.0

## firebase 로그인
$ firebase login

## flutterfire_cli 설치
$ flutter pub global activate flutterfire_cli
Warning: Pub installs executables into $HOME/.pub-cache/bin, which is not on your path.
You can fix that by adding this to your shell's config file (.zshrc, .bashrc, .bash_profile, etc.):

  export PATH="$PATH":"$HOME/.pub-cache/bin"

Activated flutterfire_cli 1.0.0.

 

zshell에 환경변수를 추가하는 warning이 뜹니다.

vim을 이용해서 .zshrc에

export PATH="$PATH":"$HOME/.pub-cache/bin"

을 추가해줍니다.

 

 

 

$ vim ~/.zshrc

## vim 명령
## i 수정
## esc 수정 종료
## :wq 저장 종료

$ source ~/.zshrc

 

 

 

## 다시 설치 합니다.
$ flutter pub global activate flutterfire_cli
Installed executable flutterfire.
Activated flutterfire_cli 1.0.0.

 

 

 

 

 

flutterfire_cli 프로젝트 구성

$ cd MYPROJEC/FOLDER
$ firebase projects:list

$ flutterfire configure -p <Project ID>
i Found 8 Firebase projects. Selecting project xxxx-27a82.                                                                                                      
? Which platforms should your configuration support (use arrow keys & space to select)? ›                                                                              
✔ android                                                                                                                                                              
✔ ios                                                                                                                                                                  
  macos                                                                                                                                                                
  web                                                                                                                                                                  
  windows

사용할 플랫폼을 스페이스바를 이용해서 선택합니다.

 

 

 

설정을 하면

/lib/firebase_options.dart

/ios/Runner/GoogleService-info.plist

/android/app/google-services.json

파일이 생성됩니다.

 

 

 

flutter plugin 설치

https://firebase.google.com/docs/auth/flutter/start?hl=ko

firebase api 사이트를 참조합니다.

$ flutter pub add firebase_auth
$ flutter pub add firebase_core

 

 

 

 

pubspec.yaml에 dependencies에 추가되었습니다.

dependencies:
  flutter:
    sdk: flutter
  firebase_auth: ^4.16.0
  firebase_core: ^2.24.2

 

 

 

 

 

firebase 초기화

main.dart

import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
...

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();

  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  ...
}

 

 

 

 

 

 

 

 

회원가입

firebase_signup_screen.dart

// ignore_for_file: avoid_print
import 'dart:convert';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';

class FirebaseSignupScreen extends StatefulWidget {
  const FirebaseSignupScreen({super.key});

  @override
  // ignore: library_private_types_in_public_api
  _FirebaseSignupPageState createState() => _FirebaseSignupPageState();
}

class _FirebaseSignupPageState extends State<FirebaseSignupScreen> {
  final _formKey = GlobalKey<FormState>();
  final TextEditingController _emailController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();
  final TextEditingController _confirmPasswordController =
      TextEditingController();

  Future<void> signup() async {
    if (_formKey.currentState!.validate()) {
      if (_passwordController.text != _confirmPasswordController.text) {
        ScaffoldMessenger.of(context)
            .showSnackBar(const SnackBar(content: Text('비밀번호가 다릅니다.')));
      }
    }

    try {
      final credential =
          await FirebaseAuth.instance.createUserWithEmailAndPassword(
        email: _emailController.text,
        password: _passwordController.text,
      );
      Navigator.pushNamed(context, '/success');
    } on FirebaseAuthException catch (e) {
      if (e.code == 'weak-password') {
        print('The password provided is too weak.');
      } else if (e.code == 'email-already-in-use') {
        print('The account already exists for that email.');
      }
    } catch (e) {
      print(e);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('Firebase Login'),
        ),

        // body
        body: Padding(
            padding: const EdgeInsets.all(15),
            child: Form(
              key: _formKey,
              child: Column(
                children: [
                  TextFormField(
                    controller: _emailController,
                    decoration: const InputDecoration(labelText: 'Email'),
                    validator: (value) {
                      if (value!.isEmpty) {
                        return '이메일을 입력하세요.';
                      }
                      return null;
                    },
                  ),
                  TextFormField(
                    controller: _passwordController,
                    decoration: const InputDecoration(labelText: 'Password'),
                    obscureText: true,
                    validator: (value) {
                      if (value!.isEmpty) {
                        return '패스워드를 입력하세요.';
                      }
                      return null;
                    },
                  ),
                  TextFormField(
                    controller: _confirmPasswordController,
                    decoration:
                        const InputDecoration(labelText: 'Confirm Password'),
                    obscureText: true,
                    validator: (value) {
                      if (value!.isEmpty) {
                        return '패스워드를 다시 입력하세요.';
                      }
                      return null;
                    },
                  ),
                  const SizedBox(height: 20),
                  TextButton(onPressed: signup, child: const Text('회원가입 '))
                ],
              ),
            )));
  }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Cloud Firestore 설정

Firestore Database를 추가합니다.

 

 

 

 

$ flutter pub add cloud_firestore

cloud_firestore를 추가합니다.

 

 

 

 

firebase_signup_screen.dart

...
import 'package:cloud_firestore/cloud_firestore.dart';

class FirebaseSignupScreen extends StatefulWidget {
  ...
}

class _FirebaseSignupPageState extends State<FirebaseSignupScreen> {
  final _formKey = GlobalKey<FormState>();
  final TextEditingController _emailController = TextEditingController();
  final TextEditingController _nameController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();
  final TextEditingController _confirmPasswordController =
      TextEditingController();

  Future<void> signup() async {
    if (_formKey.currentState!.validate()) {
      if (_passwordController.text != _confirmPasswordController.text) {
        ScaffoldMessenger.of(context)
            .showSnackBar(const SnackBar(content: Text('비밀번호가 다릅니다.')));
      }
    }

    try {
      final credential =
          await FirebaseAuth.instance.createUserWithEmailAndPassword(
        email: _emailController.text,
        password: _passwordController.text,
      );

      var db = FirebaseFirestore.instance;
      final user = <String, String>{
        "name": _nameController.text,
        "email": _emailController.text,
      };

      db
          .collection("users")
          .doc(credential.user!.uid)
          .set(user)
          .onError((e, _) => print("Error writing document: $e"));

      Navigator.pushNamed(context, '/success');
    } on FirebaseAuthException catch (e) {
      if (e.code == 'weak-password') {
        print('The password provided is too weak.');
      } else if (e.code == 'email-already-in-use') {
        print('The account already exists for that email.');
      }
    } catch (e) {
      print(e);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('Firebase Login'),
        ),

        // body
        body: Padding(
            padding: const EdgeInsets.all(15),
            child: Form(
              key: _formKey,
              child: Column(
                children: [
                  TextFormField(
                    controller: _emailController,
                    decoration: const InputDecoration(labelText: 'Email'),
                    validator: (value) {
                      if (value!.isEmpty) {
                        return '이메일을 입력하세요.';
                      }
                      return null;
                    },
                  ),
                  TextFormField(
                    controller: _nameController,
                    decoration: const InputDecoration(labelText: 'Name'),
                    validator: (value) {
                      if (value!.isEmpty) {
                        return '이름을 입력하세요.';
                      }
                      return null;
                    },
                  ),
                  TextFormField(
                    controller: _passwordController,
                    decoration: const InputDecoration(labelText: 'Password'),
                    obscureText: true,
                    validator: (value) {
                      if (value!.isEmpty) {
                        return '패스워드를 입력하세요.';
                      }
                      return null;
                    },
                  ),
                  TextFormField(
                    controller: _confirmPasswordController,
                    decoration:
                        const InputDecoration(labelText: 'Confirm Password'),
                    obscureText: true,
                    validator: (value) {
                      if (value!.isEmpty) {
                        return '패스워드를 다시 입력하세요.';
                      }
                      return null;
                    },
                  ),
                  const SizedBox(height: 20),
                  TextButton(onPressed: signup, child: const Text('회원가입 '))
                ],
              ),
            )));
  }
}

 

 

 

 

 

 

 

회원가입시 이메일 인증

firebase_signup_screen.dart

...

class _FirebaseSignupPageState extends State<FirebaseSignupScreen> {
  ...

  Future<void> signup() async {
    ...

    try {
      final credential =
          await FirebaseAuth.instance.createUserWithEmailAndPassword(
        email: _emailController.text,
        password: _passwordController.text,
      );

      var db = FirebaseFirestore.instance;
      final user = <String, String>{
        "name": _nameController.text,
        "email": _emailController.text,
      };

      credential.user!.sendEmailVerification();

      db
          .collection("users")
          .doc(credential.user!.uid)
          .set(user)
          .onError((e, _) => print("Error writing document: $e"));

      Navigator.pushNamed(context, '/login');
    } on FirebaseAuthException catch (e) {
      if (e.code == 'weak-password') {
        print('The password provided is too weak.');
      } else if (e.code == 'email-already-in-use') {
        print('The account already exists for that email.');
      }
    } catch (e) {
      print(e);
    }
  }

  ...

 

 

 

 

 

 

 

로그인

firebase_login_screen.dart

// ignore_for_file: avoid_print
import 'dart:convert';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';

class FirebaseLoginScreen extends StatefulWidget {
  const FirebaseLoginScreen({super.key});

  @override
  // ignore: library_private_types_in_public_api
  _FirebaseLoginPageState createState() => _FirebaseLoginPageState();
}

class _FirebaseLoginPageState extends State<FirebaseLoginScreen> {
  final _formKey = GlobalKey<FormState>();
  final TextEditingController _emailController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();

  Future<void> _login() async {
    try {
      final credential = await FirebaseAuth.instance.signInWithEmailAndPassword(
        email: _emailController.text,
        password: _passwordController.text,
      );

      if (credential.user!.emailVerified) {
        Navigator.pushNamed(context, '/success');
      } else {
        credential.user!.sendEmailVerification();
        ScaffoldMessenger.of(context)
            .showSnackBar(const SnackBar(content: Text("이메일을 확인하세요.")));
      }
    } on FirebaseAuthException catch (e) {
      if (e.code == 'user-not-found') {
        print('No user found for that email.');
      } else if (e.code == 'wrong-password') {
        print('Wrong password provided for that user.');
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('Firebase Login'),
        ),

        // body
        body: Padding(
            padding: const EdgeInsets.all(15),
            child: Form(
              key: _formKey,
              child: Column(
                children: [
                  TextFormField(
                    decoration: const InputDecoration(labelText: 'Email'),
                    controller: _emailController,
                    validator: (value) {
                      if (value!.isEmpty) {
                        return '이메일을 입력하세요.';
                      }
                      return null;
                    },
                  ),
                  TextFormField(
                    decoration: const InputDecoration(labelText: 'Password'),
                    controller: _passwordController,
                    validator: (value) {
                      if (value!.isEmpty) {
                        return '비밀번호를 입력하세요.';
                      }
                      return null;
                    },
                  ),
                  const SizedBox(height: 20),
                  ElevatedButton(onPressed: _login, child: const Text('로그인')),
                  TextButton(
                      onPressed: () {
                        Navigator.pushNamed(context, '/signup');
                      },
                      child: const Text('회원가입 '))
                ],
              ),
            )));
  }
}

 

 

 

 

 

 

 

데이터 전달 (argument)

firebase_login_screen.dart

...

class _FirebaseLoginPageState extends State<FirebaseLoginScreen> {
  ...

  Future<void> _login() async {
    try {
      final credential = await FirebaseAuth.instance.signInWithEmailAndPassword(
        email: _emailController.text,
        password: _passwordController.text,
      );

      Navigator.pushNamed(context, '/success', arguments: credential.user);

      /*if (credential.user!.emailVerified) {
        Navigator.pushNamed(context, '/success');
      } else {
        credential.user!.sendEmailVerification();
        ScaffoldMessenger.of(context)
            .showSnackBar(const SnackBar(content: Text("이메일을 확인하세요.")));
      }*/
    } on FirebaseAuthException catch (e) {
      ...
    }
  }

  ...

 

 

 

firebase_success_screen.dart

...
import 'package:firebase_auth/firebase_auth.dart';

....

class _FirebaseSuccessPageState extends State<FirebaseSuccessScreen> {
  @override
  Widget build(BuildContext context) {
    final user = ModalRoute.of(context)?.settings.arguments as User;

    return Scaffold(
        ...
        body: Padding(
          padding: const EdgeInsets.all(15),
          child: Column(
            children: [
              Text(
                "로그인 성공 ${user.email}",
                style: const TextStyle(fontSize: 20),
              ),
              ...
            ],
          ),
        ));
  }
}

 

 

 

 

 

 

 

provider

$ flutter pub add provider

 

 

 

 

/lib/provider/login_provider.dart

import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';

class LoginProvider with ChangeNotifier {
  User? _user;
  User? get user => _user;

  Future<void> signInWithEmailAndPassword(String email, String password) async {
    try {
      final credential = await FirebaseAuth.instance.signInWithEmailAndPassword(
        email: email,
        password: password,
      );

      _user = credential.user;
      notifyListeners();
    } catch (e) {
      throw Exception(e);
    }
  }

  Future<void> signOut() async {
    await FirebaseAuth.instance.signOut();
    _user = null;
    notifyListeners();
  }
}

 

 

 

main.dart

...
import 'package:provider/provider.dart';
import 'provider/login_provider.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();

  runApp(ChangeNotifierProvider(
    create: (_) => LoginProvider(),
    child: const MyApp(),
  ));
}

...

 

 

 

 

firebase_login_screen.dart

...
import 'package:provider/provider.dart';
import 'provider/login_provider.dart';

...

class _FirebaseLoginPageState extends State<FirebaseLoginScreen> {
  final _formKey = GlobalKey<FormState>();
  final TextEditingController _emailController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();

  Future<void> _login() async {
    try {
      await Provider.of<LoginProvider>(context, listen: false)
          .signInWithEmailAndPassword(
              _emailController.text, _passwordController.text);

      Navigator.pushNamed(context, '/success');
    } on FirebaseAuthException catch (e) {
      if (e.code == 'user-not-found') {
        print('No user found for that email.');
      } else if (e.code == 'wrong-password') {
        print('Wrong password provided for that user.');
      }
    }
  }

  ...

 

 

 

 

 

firebase_success_screen.dart

// ignore_for_file: avoid_print
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'provider/login_provider.dart';

class FirebaseSuccessScreen extends StatefulWidget {
  const FirebaseSuccessScreen({super.key});

  @override
  // ignore: library_private_types_in_public_api
  _FirebaseSuccessPageState createState() => _FirebaseSuccessPageState();
}

class _FirebaseSuccessPageState extends State<FirebaseSuccessScreen> {
  @override
  Widget build(BuildContext context) {
    final user = Provider.of<LoginProvider>(context).user;

    return Scaffold(
        appBar: AppBar(
          title: const Text('Firebase Login'),
        ),

        // body
        body: Padding(
          padding: const EdgeInsets.all(15),
          child: Column(
            //mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(
                "로그인 성공 ${user?.email}",
                style: const TextStyle(fontSize: 20),
              ),
              const SizedBox(height: 20),
              ElevatedButton(
                  onPressed: () async {
                    await Provider.of<LoginProvider>(context, listen: false)
                        .signOut();
                    Navigator.pushNamed(context, '/login');
                  },
                  child: const Text('로그아웃'))
            ],
          ),
        ));
  }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

Splash 화면

/lib/splash_screen.dart

import 'package:flutter/material.dart';

class SplashScreen extends StatefulWidget {
  const SplashScreen({super.key});

  @override
  State<SplashScreen> createState() => _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen> {
  @override
  Widget build(BuildContext context) {
    return const Scaffold(
        body: Center(
      child: FlutterLogo(size: 100),
    ));
  }
}

 

 

 

main.dart

....
import 'package:whereisthis/splash_screen.dart';

...

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      ...
      initialRoute: '/splash',
      routes: {
        '/splash': (context) => const SplashScreen(),
        '/login': (context) => const FirebaseLoginScreen(),
        '/signup': (context) => const FirebaseSignupScreen(),
        '/success': (context) => const FirebaseSuccessScreen(),
      },
    );
  }
}

 

 

 

 

 

splash에서 로그인 정보 확인

login_provider.dart

import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';

class LoginProvider with ChangeNotifier {
  User? _user;
  User? get user => _user;

  Future<void> signInWithEmailAndPassword(String email, String password) async {
    try {
      final credential = await FirebaseAuth.instance.signInWithEmailAndPassword(
        email: email,
        password: password,
      );

      _user = credential.user;
      notifyListeners();
    } catch (e) {
      throw Exception(e);
    }
  }

  Future<void> signOut() async {
    await FirebaseAuth.instance.signOut();
    _user = null;
    notifyListeners();
  }

  void currentUser() {
    _user = FirebaseAuth.instance.currentUser;
    notifyListeners();
  }
}

 

 

 

 

splash_screen.dart

import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:provider/provider.dart';
import 'provider/login_provider.dart';

class SplashScreen extends StatefulWidget {
  const SplashScreen({super.key});

  @override
  State<SplashScreen> createState() => _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen> {
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    SchedulerBinding.instance.addPostFrameCallback((_) {
      _initialize();
    });
  }

  Future<void> _initialize() async {
    await Future.delayed(const Duration(seconds: 2));
    //Provider.of<LoginProvider>(context).currentUser;
    context.read<LoginProvider>().currentUser();
    User? user = context.read<LoginProvider>().user;

    if (user != null) {
      Navigator.pushReplacementNamed(context, '/success');
    } else {
      Navigator.pushReplacementNamed(context, '/login');
    }
  }

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
        body: Center(
      child: FlutterLogo(size: 100),
    ));
  }
}

 

 

 

 

 

 

 

 

 

Google 로그인

$ flutter pub add google_sign_in
$ flutter pub add font_awesome_flutter

 

 

 

 

 

 

 

 

 

 

 

https://developers.google.com/android/guides/client-auth?hl=ko

 

 

 

 

 

$ keytool -list -v -alias androiddebugkey -keystore ~/.android/debug.keystore
password 

## password는 android 입력

keystore 생성

 

 

 

 

생성된 keystore를 디지털 지문 추가해서 SHA-1과 SHA-256을 추가합니다.

 

 

 

 

 

 

import 'dart:convert';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:provider/provider.dart';
import 'provider/login_provider.dart';

class FirebaseLoginScreen extends StatefulWidget {
  const FirebaseLoginScreen({super.key});

  @override
  // ignore: library_private_types_in_public_api
  _FirebaseLoginPageState createState() => _FirebaseLoginPageState();
}

class _FirebaseLoginPageState extends State<FirebaseLoginScreen> {
  final _formKey = GlobalKey<FormState>();
  final TextEditingController _emailController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();

  Future<void> _login() async {
    try {
      await Provider.of<LoginProvider>(context, listen: false)
          .signInWithEmailAndPassword(
              _emailController.text, _passwordController.text);

      Navigator.pushNamed(context, '/success');
    } on FirebaseAuthException catch (e) {
      if (e.code == 'user-not-found') {
        print('No user found for that email.');
      } else if (e.code == 'wrong-password') {
        print('Wrong password provided for that user.');
      }
    }
  }

  Future<UserCredential> signInWithGoogle() async {
    // Trigger the authentication flow
    final GoogleSignInAccount? googleUser = await GoogleSignIn().signIn();

    // Obtain the auth details from the request
    final GoogleSignInAuthentication? googleAuth =
        await googleUser?.authentication;

    // Create a new credential
    final credential = GoogleAuthProvider.credential(
      accessToken: googleAuth?.accessToken,
      idToken: googleAuth?.idToken,
    );

    // Once signed in, return the UserCredential
    return await FirebaseAuth.instance.signInWithCredential(credential);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('Firebase Login'),
        ),

        // body
        body: Padding(
            padding: const EdgeInsets.all(15),
            child: Form(
              key: _formKey,
              child: Column(
                children: [
                  TextFormField(
                    decoration: const InputDecoration(labelText: 'Email'),
                    controller: _emailController,
                    validator: (value) {
                      if (value!.isEmpty) {
                        return '이메일을 입력하세요.';
                      }
                      return null;
                    },
                  ),
                  TextFormField(
                    decoration: const InputDecoration(labelText: 'Password'),
                    controller: _passwordController,
                    validator: (value) {
                      if (value!.isEmpty) {
                        return '비밀번호를 입력하세요.';
                      }
                      return null;
                    },
                  ),
                  const SizedBox(height: 20),
                  ElevatedButton(onPressed: _login, child: const Text('로그인')),
                  Center(
                    child: ElevatedButton.icon(
                        onPressed: signInWithGoogle,
                        icon: const FaIcon(FontAwesomeIcons.google),
                        label: const Text('Google')),
                  ),
                  TextButton(
                      onPressed: () {
                        Navigator.pushNamed(context, '/signup');
                      },
                      child: const Text('회원가입 '))
                ],
              ),
            )));
  }
}

https://firebase.google.com/docs/auth/flutter/federated-auth?hl=ko

 

 

 

 

 

ios simulator에서는 구글 로그인 테스트 불가

 

 

 

 

 

 

 

 

 

 

Kakao 로그인

https://developers.kakao.com/console/app

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

keyhash 생성

https://developers.kakao.com/docs/latest/ko/android/getting-started

$ keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore -storepass android -keypass android | openssl sha1 -binary | openssl base64

 

 

 

 

 

플랫폼 생성및 키 해시 입력

 

 

 

 

카카오 로그인 활성화 설정

 

 

 

 

 

 

프로젝트 설정

https://developers.kakao.com/docs/latest/ko/flutter/getting-started

 

 

 

 

 

 

 

 

 

$ flutter pub add kakao_flutter_sdk_user

 

 

 

 

 

 

 

https://developers.kakao.com/docs/latest/ko/kakaologin/flutter

 

 

 

 

 

 

 

 

// ignore_for_file: avoid_print
import 'dart:convert';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:kakao_flutter_sdk_user/kakao_flutter_sdk_user.dart';
import 'package:provider/provider.dart';
import 'provider/login_provider.dart';

class FirebaseLoginScreen extends StatefulWidget {
  const FirebaseLoginScreen({super.key});

  @override
  // ignore: library_private_types_in_public_api
  _FirebaseLoginPageState createState() => _FirebaseLoginPageState();
}

class _FirebaseLoginPageState extends State<FirebaseLoginScreen> {
  final _formKey = GlobalKey<FormState>();
  final TextEditingController _emailController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();

  Future<void> _login() async {
    try {
      await Provider.of<LoginProvider>(context, listen: false)
          .signInWithEmailAndPassword(
              _emailController.text, _passwordController.text);

      Navigator.pushNamed(context, '/success');
    } on FirebaseAuthException catch (e) {
      if (e.code == 'user-not-found') {
        print('No user found for that email.');
      } else if (e.code == 'wrong-password') {
        print('Wrong password provided for that user.');
      }
    }
  }

  Future<UserCredential> signInWithGoogle() async {
    // Trigger the authentication flow
    final GoogleSignInAccount? googleUser = await GoogleSignIn().signIn();

    // Obtain the auth details from the request
    final GoogleSignInAuthentication? googleAuth =
        await googleUser?.authentication;

    // Create a new credential
    final credential = GoogleAuthProvider.credential(
      accessToken: googleAuth?.accessToken,
      idToken: googleAuth?.idToken,
    );

    // Once signed in, return the UserCredential
    return await FirebaseAuth.instance.signInWithCredential(credential);
  }

  Future<void> kakaoTalkLogin() async {
    if (await isKakaoTalkInstalled()) {
      try {
        await UserApi.instance.loginWithKakaoTalk();
        print('카카오톡으로 로그인 성공');
      } catch (error) {
        print('카카오톡으로 로그인 실패 $error');
      }
    } else {
      try {
        await UserApi.instance.loginWithKakaoAccount();
        print('카카오계정으로 로그인 성공');
      } catch (error) {
        print('카카오계정으로 로그인 실패 $error');
      }
    }
  }

  Future<void> kakaoTalkLogout() async {
    try {
      await UserApi.instance.unlink();
      print('카카오톡으로 로그아웃 성공');
    } catch (error) {}
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('Firebase Login'),
        ),

        // body
        body: Padding(
            padding: const EdgeInsets.all(15),
            child: Form(
              key: _formKey,
              child: Column(
                children: [
                  TextFormField(
                    decoration: const InputDecoration(labelText: 'Email'),
                    controller: _emailController,
                    validator: (value) {
                      if (value!.isEmpty) {
                        return '이메일을 입력하세요.';
                      }
                      return null;
                    },
                  ),
                  TextFormField(
                    decoration: const InputDecoration(labelText: 'Password'),
                    controller: _passwordController,
                    validator: (value) {
                      if (value!.isEmpty) {
                        return '비밀번호를 입력하세요.';
                      }
                      return null;
                    },
                  ),
                  const SizedBox(height: 20),
                  ElevatedButton(onPressed: _login, child: const Text('로그인')),
                  const SizedBox(height: 20),
                  Center(
                    child: ElevatedButton.icon(
                        onPressed: signInWithGoogle,
                        icon: const FaIcon(FontAwesomeIcons.google),
                        label: const Text('Google')),
                  ),
                  const SizedBox(height: 20),
                  ElevatedButton(
                      onPressed: kakaoTalkLogin, child: const Text('카카오 로그인')),
                  const SizedBox(height: 20),
                  ElevatedButton(
                      onPressed: kakaoTalkLogout,
                      child: const Text('카카오 로그아웃')),
                  const SizedBox(height: 20),
                  TextButton(
                      onPressed: () {
                        Navigator.pushNamed(context, '/signup');
                      },
                      child: const Text('회원가입 '))
                ],
              ),
            )));
  }
}

 

 

 

main.dart

...
import 'package:kakao_flutter_sdk_user/kakao_flutter_sdk_user.dart';


Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();

  KakaoSdk.init(nativeAppKey: 'e20945d788dXXXXXXX615f625e49');

  runApp(ChangeNotifierProvider(
    create: (_) => LoginProvider(),
    child: const MyApp(),
  ));
}

class MyApp extends StatelessWidget {
  ...
}

 

 

 

 

 

 

 

 

반응형
Comments