Notice
Recent Posts
Recent Comments
Link
250x250
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Tags more
Archives
Today
Total
관리 메뉴

혼자서 앱 만드는 개발자 함께하는 AI 세상

[펫버틀러] 반려 동물 고민 상담 앱 - 개발 4 일차 (구글 로그인 등록) 본문

펫버틀러

[펫버틀러] 반려 동물 고민 상담 앱 - 개발 4 일차 (구글 로그인 등록)

혼앱사 2022. 12. 24. 15:28
반응형


3일차 개발 문서 링크 - 지난 개발 FIREBASE 페이지 개발에 https://shsoft.tistory.com/63

  • 로그인 페이지 작업 시 구글로그인을 사용한다.
  • 구글로그인은 기본적으로 구글 권한 Authentication 항목에서 이메일/비밀번호 와 Google선택한다.
  • 플러터에서 관련 pub add 를 추가해야한다.

  • 현재 적용되어있는 firebase_auth 를 추가한다. 기본적으로
  • firebase_core: ^2.3.0 firebase_auth: ^4.1.5 를 추가한다.
  • SNS 구글 로그인
  • 적용 소스 확인

여기서 GoogleSignInAccount? googleUser = await googleSignIn.signIn(); 부분이 구글 로그인을 호출하는 부분이다.

 
 
  Future<bool> handleSignIn() async {
    _status = Status.authenticating;
    notifyListeners();

    GoogleSignInAccount? googleUser = await googleSignIn.signIn();
    if (googleUser != null) {
      GoogleSignInAuthentication? googleAuth = await googleUser.authentication;
      final AuthCredential credential = GoogleAuthProvider.credential(
        accessToken: googleAuth.accessToken,
        idToken: googleAuth.idToken,
      );
      User? firebaseUser =
          (await firebaseAuth.signInWithCredential(credential)).user;
      return checkfirebaseUser(firebaseUser);
    } else {
      _status = Status.authenticateCanceled;
      notifyListeners();
      return false;
    }
  }
  • 계정이 2개 이상 이면 선택 하지만 한 개 일 경우 홈 화면으로 바로 간다.

  • 로그인 페이지 전체 공유
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:petbutler/constants/app_constants.dart';
import 'package:petbutler/constants/color_constants.dart';
import 'package:petbutler/providers/auth_provider.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';

import '../widgets/widgets.dart';
import 'login_add.dart';
import 'login_reset.dart';
import 'pages.dart';

class LoginPage extends StatefulWidget {
  LoginPage({Key? key}) : super(key: key);

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

class LoginPageState extends State<LoginPage> {
  final _idTextEditController = TextEditingController();
  final _passwordTextEditController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    var _idTextField = CupertinoTextField(
      controller: _idTextEditController,
      keyboardType: TextInputType.emailAddress,
      placeholder: "이메일",
      padding: EdgeInsets.all(10),
      style: TextStyle(fontSize: 16),
      decoration: BoxDecoration(
        color: Colors.white,
        border: Border.all(
          color: Colors.black,
          width: 0.5,
        ),
        borderRadius: BorderRadius.circular(12),
      ),
      onChanged: (text) {
        setState(() {});
      },
    );

    var _passwordTextField = CupertinoTextField(
      controller: _passwordTextEditController,
      placeholder: "비밀번호",
      obscureText: true,
      padding: EdgeInsets.all(10),
      style: TextStyle(fontSize: 16),
      decoration: BoxDecoration(
        color: Colors.white,
        border: Border.all(
          color: Colors.black,
          width: 0.5,
        ),
        borderRadius: BorderRadius.circular(12),
      ),
      onChanged: (text) {
        setState(() {});
      },
    );

    AuthProvider authProvider = Provider.of<AuthProvider>(context);
    switch (authProvider.status) {
      case Status.authenticateError:
        Fluttertoast.showToast(msg: "Sign in fail");
        break;
      case Status.authenticateCanceled:
        Fluttertoast.showToast(msg: "Sign in canceled");
        break;
      case Status.authenticated:
        Fluttertoast.showToast(msg: "Sign in success");
        break;
      default:
        break;
    }
    return Scaffold(
        resizeToAvoidBottomInset: false,
        body: Container(
          height: MediaQuery.of(context).size.height * 1.50,
          child: SingleChildScrollView(
            padding: EdgeInsets.all(20.0),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.start,
              children: [
                SizedBox(
                  height: 150.0,
                ),
                Image.asset(
                  "images/pet/intro/intro_login2.png",
                  //width: 80,
                  height: 200,
                ),
                SizedBox(
                  height: 10.0,
                ),
                Text('펫버틀러 로그인',
                    style: TextStyle(
                        color: Colors.black,
                        fontWeight: FontWeight.bold,
                        fontSize: 15.0)),
                SizedBox(
                  height: 10.0,
                ),
                Padding(
                  //padding: const EdgeInsets.only(left:15.0,right: 15.0,top:0,bottom: 0),
                  padding: EdgeInsets.symmetric(horizontal: 15),
                  child: _idTextField,
                ),
                Padding(
                    padding: EdgeInsets.only(
                        left: 15.0, right: 15.0, top: 15, bottom: 0),
                    //padding: EdgeInsets.symmetric(horizontal: 15),
                    child: _passwordTextField),
                SizedBox(
                  height: 10.0,
                ),
                Container(
                  height: 45,
                  width: 250,
                  decoration: BoxDecoration(
                      color: Color.fromARGB(255, 244, 85, 85),
                      borderRadius: BorderRadius.circular(20)),
                  // ignore: deprecated_member_use
                  child: TextButton(
                    onPressed: () async {
                      try {
                        User? googleUser;

                        googleUser = (await authProvider.firebaseAuth
                                .signInWithEmailAndPassword(
                                    email: _idTextEditController.text,
                                    password: _passwordTextEditController.text))
                            .user;

                        if (googleUser?.emailVerified == true) {
                          authProvider
                              .checkfirebaseUser(googleUser)
                              .then((isSuccess) {
                            Navigator.pushReplacement(
                              context,
                              MaterialPageRoute(
                                builder: (context) => HomePage(),
                              ),
                            );
                          });
                        } else {
                          Fluttertoast.showToast(
                              msg: '이메일 확인 필요합니다. 메일확인부탁드립니다.');
                        }

                        //userData = (await _auth.signInWithEmailAndPassword(email: userName.toString(), password: userPassword.toString())).user;

                      } on FirebaseAuthException catch (e) {
                        print(e);
                        if (e.code == 'user-not-found') {
                          Fluttertoast.showToast(msg: '등록되지 않은 이메일입니다');
                        } else if (e.code == 'wrong-password') {
                          Fluttertoast.showToast(msg: '비밀번호가 틀렸습니다');
                        } else {
                          Fluttertoast.showToast(msg: "이메일 비밀번호가 입력되지않았습니다.");
                        }
                      }
                    },
                    child: const Text(
                      '로그인',
                      style: TextStyle(color: Colors.white, fontSize: 20),
                    ),
                  ),
                ),
                SizedBox(
                  height: 10,
                ),
                Text('SNS 소셜 로그인',
                    style: TextStyle(
                        color: Colors.black,
                        fontWeight: FontWeight.bold,
                        fontSize: 15.0)),
                SizedBox(
                  height: 10.0,
                ),
                Container(
                  height: 40,
                  width: 250,
                  decoration: BoxDecoration(
                      color: Colors.black,
                      borderRadius: BorderRadius.circular(20)),
                  // ignore: deprecated_member_use
                  child: ElevatedButton(
                    onPressed: () async {
                      authProvider.handleSignIn().then((isSuccess) {
                        if (isSuccess) {
                          Navigator.pushReplacement(
                            context,
                            MaterialPageRoute(
                              builder: (context) => HomePage(),
                            ),
                          );
                        }
                      }).catchError((error, stackTrace) {
                        Fluttertoast.showToast(msg: error.toString());
                        authProvider.handleException();
                      });
                    },
                    style: ElevatedButton.styleFrom(
                      padding: EdgeInsets.all(10),
                      primary: Color.fromARGB(255, 62, 136, 246),
                      //shadowColor: Colors.black, 그림자 추가하는 속성

                      minimumSize: Size.fromHeight(50), // 높이만 50으로 설정
                      elevation: 1.0,
                      shape: RoundedRectangleBorder(
                          // shape : 버튼의 모양을 디자인 하는 기능
                          borderRadius: BorderRadius.circular(20.0)),
                    ),
                    child: Row(
                      //spaceEvenly: 요소들을 균등하게 배치하는 속성
                      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                      children: [
                        Image.asset('images/glogo.png'),
                        Text(
                          '구글 로그인 하기',
                          style: TextStyle(
                              color: Colors.white,
                              fontWeight: FontWeight.bold,
                              fontSize: 15.0),
                        ),
                        Opacity(
                          opacity: 0.0,
                          child: Image.asset('images/glogo.png'),
                        ),
                      ],
                    ),
                  ),
                ),
                Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    ElevatedButton(
                      onPressed: () {
                        Navigator.push(
                          context,
                          MaterialPageRoute(
                              builder: (context) => LoginADDPage()),
                        );
                      },
                      style: ElevatedButton.styleFrom(
                        primary: Color.fromARGB(255, 116, 120, 126),
                        elevation: 1.0,
                        shape: RoundedRectangleBorder(
                            borderRadius: BorderRadius.circular(20.0)),
                      ),
                      child: const Text(
                        ' 회 원 가 입 ',
                        style: TextStyle(
                            color: Colors.white,
                            fontWeight: FontWeight.bold,
                            fontSize: 15),
                      ),
                    ),
                    SizedBox(width: 10),
                    ElevatedButton(
                      onPressed: () {
                        Navigator.push(
                          context,
                          MaterialPageRoute(
                              builder: (context) => LoginResetPage()),
                        );
                      },
                      style: ElevatedButton.styleFrom(
                        primary: Color.fromARGB(255, 116, 120, 126),
                        elevation: 1.0,
                        shape: RoundedRectangleBorder(
                            borderRadius: BorderRadius.circular(20.0)),
                      ),
                      child: const Text(
                        '비밀번호 재설정',
                        style: TextStyle(
                            color: Colors.white,
                            fontWeight: FontWeight.bold,
                            fontSize: 15),
                      ),
                    ),
                  ],
                )
              ],
            ),
          ),
        ));
  }
}

 

    
   /* 
    Scaffold(
        appBar: AppBar(
          title: Text(
            AppConstants.loginTitle,
            style: TextStyle(color: ColorConstants.primaryColor),
          ),
          centerTitle: true,
        ),
        body: Stack(
          children: <Widget>[
            Center(
              child: Image.asset(
                "images/app_icon.png",
                width: 100,
                height: 100,
              ),
            ),
            Center(
              child: TextButton(
                
                onPressed: () async {
                  authProvider.handleSignIn().then((isSuccess) {
                    if (isSuccess) {
                      Navigator.pushReplacement(
                        context,
                        MaterialPageRoute(
                          builder: (context) => HomePage(),
                        ),
                      );
                    }
                  }).catchError((error, stackTrace) {
                    Fluttertoast.showToast(msg: error.toString());
                    authProvider.handleException();
                  });
                },
                child: Text(
                  'Sign in with Google',
                  style: TextStyle(fontSize: 16, color: Colors.white),
                ),
                style: ButtonStyle(
                  backgroundColor: MaterialStateProperty.resolveWith<Color>(
                    (Set<MaterialState> states) {
                      if (states.contains(MaterialState.pressed))
                        return Color(0xffdd4b39).withOpacity(0.8);
                      return Color(0xffdd4b39);
                    },
                  ),
                  splashFactory: NoSplash.splashFactory,
                  padding: MaterialStateProperty.all<EdgeInsets>(
                    EdgeInsets.fromLTRB(30, 15, 30, 15),
                  ),
                ),
              ),
            ),
            // Loading
            Positioned(
              child: authProvider.status == Status.authenticating
                  ? LoadingView()
                  : SizedBox.shrink(),
            ),
          ],
        ));
  }
}
*/
  • 권한관련 페이지 공유
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:petbutler/constants/constants.dart';
import 'package:petbutler/models/models.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:shared_preferences/shared_preferences.dart';

enum Status {
  uninitialized,
  authenticated,
  authenticating,
  authenticateError,
  authenticateException,
  authenticateCanceled,
}

class AuthProvider extends ChangeNotifier {
  final GoogleSignIn googleSignIn;
  final FirebaseAuth firebaseAuth;
  final FirebaseFirestore firebaseFirestore;
  final SharedPreferences prefs;

  Status _status = Status.uninitialized;

  Status get status => _status;

  AuthProvider({
    required this.firebaseAuth,
    required this.googleSignIn,
    required this.prefs,
    required this.firebaseFirestore,
  });

  String? getUserFirebaseId() {
    return prefs.getString(FirestoreConstants.id);
  }

  Future<bool> isLoggedIn() async {
    //bool isLoggedIn = await googleSignIn.isSignedIn();
    if (prefs.getString(FirestoreConstants.id)?.isNotEmpty == true) {
      return true;
    } else {
      return false;
    }
  }

//벨루 프로토콜

  Future<bool> handleSignIn() async {
    _status = Status.authenticating;
    notifyListeners();

    GoogleSignInAccount? googleUser = await googleSignIn.signIn();
    if (googleUser != null) {
      GoogleSignInAuthentication? googleAuth = await googleUser.authentication;
      final AuthCredential credential = GoogleAuthProvider.credential(
        accessToken: googleAuth.accessToken,
        idToken: googleAuth.idToken,
      );
      User? firebaseUser =
          (await firebaseAuth.signInWithCredential(credential)).user;
      return checkfirebaseUser(firebaseUser);
    } else {
      _status = Status.authenticateCanceled;
      notifyListeners();
      return false;
    }
  }

  Future<bool> checkfirebaseUser(User? firebaseUser) async {
    if (firebaseUser != null) {
      final QuerySnapshot result = await firebaseFirestore
          .collection(FirestoreConstants.pathUserCollection)
          .where(FirestoreConstants.id, isEqualTo: firebaseUser.uid)
          .get();
      final List<DocumentSnapshot> documents = result.docs;
      if (documents.length == 0) {
        // Writing data to server because here is a new user
        firebaseFirestore
            .collection(FirestoreConstants.pathUserCollection)
            .doc(firebaseUser.uid)
            .set({
          FirestoreConstants.nickname: firebaseUser.displayName,
          FirestoreConstants.photoUrl: firebaseUser.photoURL,
          FirestoreConstants.id: firebaseUser.uid,
          'createdAt': DateTime.now().millisecondsSinceEpoch.toString(),
          FirestoreConstants.chattingWith: null
        });

        // Write data to local storage
        User? currentUser = firebaseUser;
        await prefs.setString(FirestoreConstants.id, currentUser!.uid);
        await prefs.setString(
            FirestoreConstants.nickname, currentUser.displayName ?? "");
        await prefs.setString(
            FirestoreConstants.photoUrl, currentUser.photoURL ?? "");
      } else {
        // Already sign up, just get data from firestore
        DocumentSnapshot documentSnapshot = documents[0];
        UserChat userChat = UserChat.fromDocument(documentSnapshot);
        // Write data to local
        await prefs.setString(FirestoreConstants.id, userChat.id);
        await prefs.setString(FirestoreConstants.nickname, userChat.nickname);
        await prefs.setString(FirestoreConstants.photoUrl, userChat.photoUrl);
        await prefs.setString(FirestoreConstants.aboutMe, userChat.aboutMe);
      }
      _status = Status.authenticated;
      notifyListeners();
      return true;
    } else {
      _status = Status.authenticateError;
      notifyListeners();
      return false;
    }
  }

  void handleException() {
    _status = Status.authenticateException;
    notifyListeners();
  }

  Future<void> handleSignOut() async {
    _status = Status.uninitialized;
    await firebaseAuth.signOut();
    await googleSignIn.disconnect();
    await googleSignIn.signOut();
  }
}

728x90
반응형
Comments