오늘은 Firebase 와 Flutter를 연동하여 가입하고, 로그인, 로그아웃을 하는 기능을 살펴보도록 하자.
여기서 다룰 것은 Firebase 세팅, 가입/탈퇴 기능, 로그인/로그아웃 기능, GetX로 로그인 상태 관리 등이다.
Firebase란 완전 관리형 백엔드 서비스이다. 구글에서 만든 서비스로 연결된 모든 기기에서 실시간으로 데이터를 동기화하는 실시간 데이터베이스를 제공한다.
개발자가 모바일 및 웹 애플리케이션을 모두 쉽게 생성, 실행 및 확장할 수 있도록 한다. 실시간 데이터베이스, 인증, 스토리지, 호스팅 및 기타 기능을 제공하며 모두 단일 플랫폼에서 관리된다.
Firebase 의 콘솔로 이동
첫 단계에서 프로젝트 이름을 설정해 준 후, 4단계까지 계속, 동의 후 계속을 클릭한다. 위치는 대한민국으로 설정한다.
생성된 프로젝트의 콘솔로 이동하여 [빌드] 메뉴를 확인해보자. 우리는 여기서 Authentication, Cloud Firestore, Storage를 주로 사용하게 될 것이다.
이제 앱에 Firebase를 추가하여 시작하기 아래에 있는 안드로이드 버튼을 클릭하여 다음 단계를 진행하자.
firebase를 연동할 패키지 이름을 등록한다. "?" 마크를 확인해보면 app수준의 build.gradle 파일의 applicationId 를 등록하는 곳임을 알 수 있다.
2단계에서는 google-services.json을 다운로드 하여 앱 수준의 루트 디렉토리에 넣어 준다. 즉 android/app 폴더에 다운로드한 json파일을 넣어 주면 된다.
귀염둥이 chatGPT에게 물어보았다.
다음은 Firebase SDK 를 추가 해 준다. 단, app수준의 build.gradle 파일이 아닌, 프로젝트 수준의 build.gradle 파일임을 꼭 확인해 준다.
앱 수준의 build.gradle에서는 다음과 같이 추가해 준다.
plugins {
id 'com.android.application'
// Add the Google services Gradle plugin
id 'com.google.gms.google-services'
...
}
dependencies {
// Import the Firebase BoM
implementation platform('com.google.firebase:firebase-bom:31.2.3')
// TODO: Add the dependencies for Firebase products you want to use
// When using the BoM, don't specify versions in Firebase dependencies
// https://firebase.google.com/docs/android/setup#available-libraries
}
Note. 요금제
테스트시 무료 요금제를 사용하여 시작한다. 테스트 용도의 앱이니 사용량이 적어 청구금이 없을테니 걱정말고 사용하자!
프로젝트 삭제가 필요한 경우에는 , 프로젝트 개요 -> 톱니바퀴 -> 프로젝트 설정 -> 하단의 프로젝트 삭제를 통하여 삭제한다.
flutter firebase 로 이동하여 install 한다.
위의 package를 설치 후 오류가 난다면 아래와 같이 처리한다.
android {
...
defaultConfig {
...
multiDexEnabled true//add this
}
}
dependencies {
...
implementation 'com.android.support:multidex:2.0.1'//add this
}
이제 flutter 에서 sign up 기능을 구현해보자.
firebase 콘솔로 돌아가 Authentication 의 Sign-in method 로 이동한다. 여기에서 가입 방법을 추가할 수 있는데, 이메일/비밀번호를 클릭하여 활성화 해준다.
만약 이 과정을 스킵하면 com.google.firebase.FirebaseException: An internal error has occurred. [ CONFIGURATION_NOT_FOUND ] 라는 에러 메세지가 발생한다.
현재는 email 과 비밀번호만 필요하지만 차후 기능 추가를 위해 아래와 같이 UI을 구성하였다.
아래 코드같이 커스텀 TextField 를 만들어 layout 을 정의하였다.
AuthTextFormField(
controller: controller.emailController,
hintText: translation(context).email_address,
labelText: translation(context).email_address,
keyboardType: TextInputType.emailAddress,
onSaved: (input) => {controller.email = input!},
validator: (input) {
return controller.validateEmail(input!);
},
buttonText: translation(context).auth_code,
),
- Property
controller : TextEditingController
hintText : field에 보여지는 힌트
labelText : 박스에 상단부에 노출되는 텍스트
keyboardType : 포커스시 올라오는 키보드 타입
onSaved : _formkey의 currentState.save() 가 호출된때 호출된다.
validator : field의 값이 유효한지 체크
buttonText : suffix 의 TextButton의 텍스트
property controller에는 GetController에서 정의한 emailController를 주입하여 주었다.
RegistController에서는 TextField의 유효성을 검사하고 TextEditingController 의 생성 및 해제하는 코드를 작성하였다.
아래는 GetController 코드이다.
class RegistController extends GetxController {
...
final GlobalKey<FormState> loginFormKey = GlobalKey<FormState>();
late TextEditingController emailController,
passwordController,
confirmedPasswordController;
void onInit() {
super.onInit();
emailController = TextEditingController();
passwordController = TextEditingController();
confirmedPasswordController = TextEditingController();
//init에서 생성
}
...
void onClose() {
emailController.dispose();
passwordController.dispose();
confirmedPasswordController.dispose();
//Close에서 해제
super.onClose();
}
...
String? validateEmail(String value) {
if (!GetUtils.isEmail(value)) {
return 'Provide valid Email';
}
return null;
}
...
}
AuthHandler에서는 FirebaseAuth를 컨트롤 하는 작업을 모아 두었다. 앱의 어느 부분에서나 접근이 가능해야 하므로 GetService를 extends하여 만들어 주었다.
import 'package:firebase_auth/firebase_auth.dart';
class AuthHandler extends GetxService {
static AuthHandler get to => Get.find(); //이제 어디서나 호출가능(instance)
late Rx<User?> _user;
FirebaseAuth authentication = FirebaseAuth.instance;
void onReady() {
super.onReady();
_user = Rx<User?>(authentication.currentUser);
_user.bindStream(authentication.userChanges());
//로그인 or 로그아웃과 같은 변화를 실시간 감지
}
void register(String email, password) async {
try {
await authentication.createUserWithEmailAndPassword(
email: email, password: password);
} catch (e) {
Get.snackbar(
'[ERROR]',
'',
backgroundColor: Colors.red,
titleText: Text('Registratio is failed.'),
messageText: Text(e.toString()),
);
print(e.toString());
}
}
}
이제 resigterView로 이동하여 회원가입 버튼의 onPressed에 아래와 같이 호출하면 firebase에 등록되는 것을 확일 할 수 있다.
AuthHandler.to.register(
controller.emailController.text.tr,
controller.passwordController.text.tr);
파이어베이스에 잘 저장이 되는 것을 확인하였다.
그리고 비밀번호는 반드시 6글자 이상이어야 한다. 아니면 error 메세지를 보게 됨.