guricode

[flutter-sns-project - 5] cloude_firestore ios 빌드 오류, 로그인 UI구현 본문

앱/Flutter&Dart

[flutter-sns-project - 5] cloude_firestore ios 빌드 오류, 로그인 UI구현

agentrakugaki 2025. 9. 1. 11:07

안드로이드에서 패키지 추가 후 맥에서 ios 빌드를 하는데 자꾸 xcode 빌드에서 exit 되는 문제가 있었다.

 

새벽에 이 문제를 해결하려고 했었는데 ...잘되지않아서 개발자 분께 도움을 받았다.

 

문제는 cloude_firestore가 첫 빌드를 할때 시간이 오래걸리는데 

 

xcode빌드를 할때 시간이 너무 오래걸려서 오류로 뱉어내는 것이었다.

 

문제 해결은 간단했다

 

cloude_firestore 초기빌드파일을 수동으로 받아서 다시 빌드를 했더니 해결됐다

 

관련문서 https://github.com/invertase/firestore-ios-sdk-frameworks

 

GitHub - invertase/firestore-ios-sdk-frameworks: ⚡ Precompiled Firestore iOS SDKs extracted from the Firebase iOS SDK reposito

⚡ Precompiled Firestore iOS SDKs extracted from the Firebase iOS SDK repository release downloads for faster build times. - invertase/firestore-ios-sdk-frameworks

github.com

 

 

target 'Runner' do/...
...
pod 'FirebaseFirestore', :git => 'https://github.com/invertase/firestore-ios-sdk-frameworks.git', :tag => '12.0.0'

...

 

이외에 다른 패키지를 추가할때 문제점은 없었다...다행이다.

 

근데 원래는 어제 다 완료를 했어야했는데 오늘 2시쯤 패키지 설치가 끝났다

팀원들에게는 오후에 확인하라고했다.

저녁전까지는 내가 맡은 로그인페이지 UI를 짜고 저녁식사 후 data레이어 설계를 시작해야겠다

 

8시에 usecase분석하기로했다

 

//로그인 페이지 UI

 

일단 로그인 폼을 구현해야해서 TextForm을 사용했다.

  //텍스트폼유효성검사
  final _formKey = GlobalKey<FormState>();

  //로그인폼텍스트컨트롤러 선언
  late final TextEditingController _email;
  late final TextEditingController _password;

 

그리고 intiState에서 초기화해준다

intiState에서 초기화하지 않고 build에서 실행한다면 state가 발생해 매번 build할때마다 컨트롤러가 초기화된다.

그래서 첫 빌드시점인 intiState에서 초기화해줘야한다

 void initState() {
    super.initState();

    _email = TextEditingController();
    _password = TextEditingController();
  }

 

*라이프사이클 참고

메서드/단계 호출 시점 주요 역할

createState 위젯 생성 시 State 객체 생성
initState State가 처음 생성될 때 1회 컨트롤러 초기화, 리스너 등록 등 준비 작업
didChangeDependencies initState 직후 + InheritedWidget 변경 시 외부 의존성(BuildContext, Provider 등) 참조 가능
build 최초 1회 + setState 호출마다 UI 그리기
didUpdateWidget 부모가 새 위젯을 전달했을 때 위젯 속성 변경 감지 후 상태 갱신
setState 상태 변경 시 호출 UI 갱신 트리거
deactivate 위젯이 위젯 트리에서 제거될 때 (다시 붙을 수도 있음) 필요 시 리소스 해제 준비
dispose State가 완전히 제거될 때 1회 컨트롤러, 스트림, 리스너 해제

 

그리고 dispose에서 텍스트컨트롤러를 종료해준다

 @override
  void dispose() {
    _email.dispose();
    _password.dispose();
    super.dispose();
  }

이렇게하지않으면 화면 이동할때도 메모리에 컨트롤러가 남아있어 메모리누수가 발생한다

 

 

그리고 폼에서 검증할 validation 메서드를 작성해준다

 //이메일검증
  String? _validateEmail(String? v) {
    if (v == null || v.isEmpty) return '이메일을 입력해주세요';
    final ok = RegExp(r'^[^@]+@[^@]+\.[^@]+$').hasMatch(v);
    if (!ok) return '이메일 형식이 올바르지 않습니다';
    return null;
  }

  //페스워드검증
  String? _validatePassword(String? v) {
    if (v == null || v.isEmpty) return '비밀번호를 입력해주세요';
    if (v.length < 6) return '비밀번호는 6자 이상이어야 합니다';
    return null;
  }

 

 

정규식은 SQLD공부할때 나왔던 내용인데

 

  • [^@]+ → @ 앞에 한 글자 이상
  • @
  • [^@]+ → @ 뒤에 한 글자 이상
  • \. → . 문자
  • [^@]+ → 마지막에 도메인 글자

 

그리고 로그인 폼 UI를 Form -> TextFormField로 구성한 후

TextFormField에 controller로 각각의 컨트롤러를 넣고

validator에 validation 메서드를 넣으면 된다.

 

이때 validator는 사용자의 입력값 value를 자동으로 String으로 넣어주기때문에 참조할 메서드만 호출해주면된다

validator에 마우스를 갖다대보면 String? 타입이기 때문에 함수실행형태로 전달하게되면 안된다.

 

//로그인폼

Form(
                key: _formKey,
                child: Column(
                  children: [
                    TextFormField(
                      controller: _email,
                      keyboardType: TextInputType.emailAddress,
                      textInputAction: TextInputAction.next, //엔터누르면 다름필드로
                      decoration: InputDecoration(hintText: '이메일을 입력해주세요')
                          .copyWith(
                            enabledBorder: UnderlineInputBorder(
                              borderSide: BorderSide(color: Colors.grey),
                            ),
                            focusedBorder: UnderlineInputBorder(
                              borderSide: BorderSide(color: Colors.grey),
                            ),
                          ),
                      validator: _validateEmail,
                    ),
                    SizedBox(height: 15),
                    TextFormField(
                      controller: _password,
                      obscureText: true,
                      textInputAction:
                          TextInputAction.done, //엔터누르면 완료 ->onFieldSubmitted
                      decoration: InputDecoration(hintText: '비밀번호를 입력해주세요')
                          .copyWith(
                            enabledBorder: UnderlineInputBorder(
                              borderSide: BorderSide(color: Colors.grey),
                            ),
                            focusedBorder: UnderlineInputBorder(
                              borderSide: BorderSide(color: Colors.grey),
                            ),
                          ),
                      validator: _validatePassword,
                      onFieldSubmitted: (_) => _submit(),
                    ),
                    SizedBox(height: 50),
                    Container(
                      width: double.infinity,
                      height: 50,
                      child: ElevatedButton(
                        onPressed: _submit,
                        style: ElevatedButton.styleFrom(
                          backgroundColor: Color(0xFF613EEA),
                          foregroundColor: Colors.white,
                          shape: RoundedRectangleBorder(
                            borderRadius: BorderRadius.circular(10),
                          ),
                        ),
                        child: const Text('로그인'),
                      ),
                    ),
                  ],
                ),
              ),

 

 

이제 firebase auth를 이용해 이메일 로그인을 구현해야한다.