Firebase Auth pub 설치
$ flutter pub add firebase_auth
Bash
복사
main.dart
import 'dart:io';
import 'package:chai_booster/Pages/LoginPage.dart';
import 'package:chai_booster/Pages/RootPage.dart';
import 'package:chai_booster/Providers/Auth/AuthProvider.dart';
import 'package:chai_booster/Routers.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(App());
}
class App extends StatefulWidget {
_AppState createState() => _AppState();
}
class _AppState extends State<App> {
// Set default `_initialized` and `_error` state to false
bool _initialized = false;
bool _error = false;
// Define an async function to initialize FlutterFire
void initializeFlutterFire() async {
try {
// Wait for Firebase to initialize and set `_initialized` state to true
await Firebase.initializeApp();
setState(() {
_initialized = true;
});
} catch(e) {
setState(() {
_error = true;
});
}
}
void initState() {
initializeFlutterFire();
super.initState();
}
Widget build(BuildContext context) {
if(_error || !_initialized) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Text('에러'),
),
)
);
}
return MaterialApp(
home: MultiProvider(
providers: [
ChangeNotifierProvider<AuthProvider>(create: (_) => AuthProvider())
],
child: RootPage(),
)
);
}
}
Dart
복사
AuthProvider.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/foundation.dart';
class AuthProvider with ChangeNotifier {
FirebaseAuth _auth = FirebaseAuth.instance;
User _user;
AuthProvider() {
_prepareUser();
}
User getUser() {
return _user;
}
void _prepareUser() {
_user = _auth.currentUser;
}
void signInAnonymously() async {
final authResult = await _auth.signInAnonymously();
setUser(authResult.user);
}
void setUser(User user) {
_user = user;
notifyListeners();
}
void signOut() async {
await _auth.signOut();
setUser(null);
}
void withdrawalAccount() async {
await getUser().delete();
setUser(null);
}
}
Dart
복사
Home.dart
import 'package:chai_booster/Providers/Auth/AuthProvider.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:provider/provider.dart';
class HomePage extends StatefulWidget {
HomePage({
Key key, this.title
}) : super(key: key);
final String title;
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
AuthProvider authProvider;
Widget build(BuildContext context) {
authProvider = Provider.of<AuthProvider>(context);
return Scaffold(
body: Center(
child: SizedBox(
child: ElevatedButton(
onPressed: () => {
authProvider.withdrawalAccount()
},
child: Text('회원탈'),
),
width: double.infinity,
height: 44,
),
),
);
}
}
Dart
복사
LoginPage.dart
import 'package:chai_booster/Providers/Auth/AuthProvider.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:provider/provider.dart';
class LoginPage extends StatefulWidget {
LoginPage({
Key key, this.title
}) : super(key: key);
final String title;
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
AuthProvider authProvider;
void _asdf() {
}
Widget build(BuildContext context) {
authProvider = Provider.of<AuthProvider>(context);
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Text(
'ㅇㅕ기는 로그인 화면이 될거야',
),
SizedBox(height: 80),
Padding(
padding: EdgeInsets.symmetric(horizontal: 20),
child: SizedBox(
child: ElevatedButton(
onPressed: () => {
authProvider.signInAnonymously()
},
child: Text('카카오톡 로그인'),
),
width: double.infinity,
height: 44,
)
),
SizedBox(height: 12,)
,
Padding(
padding: EdgeInsets.symmetric(horizontal: 20),
child: SizedBox(
child: ElevatedButton(
onPressed: _asdf,
child: Text('애플 로그인'),
),
width: double.infinity,
height: 44,
)
)
],
),
),
);
}
}
Dart
복사
Firebase Auth 추가 처리
Firebase Auth 를 이용해 인증을 처리하는 경우 인증 값은 FirebaseSDK에 의해 keychain에 저장됩니다. keychain의 생명주기는 앱과 다릅니다. 앱이 삭제되더라도 인증 값은 디바이스 내에 남아있고, 이 때문에 앱을 재설치 하더라도 이전 인증 값을 이용해 로그인을 시도하도 local 개발환경의 경우 로그인에 실패하게 됩니다.
Fiirebase Auth의 인증 키 생명주기는 사용자에게는 혼란을, 개발환경에서는 오류를 발생시킵니다.
업그레이드 된 AuthProvider.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/foundation.dart';
import 'package:shared_preferences/shared_preferences.dart';
class AuthProvider with ChangeNotifier {
FirebaseAuth _auth = FirebaseAuth.instance;
User _user;
AuthProvider() {
_prepareUser();
}
User getUser() {
return _user;
}
void _prepareUser() async {
final pref = await SharedPreferences.getInstance();
bool isFirstLaunched = pref.getBool('isFirstLaunched') ?? false;
if (!isFirstLaunched) {
await FirebaseAuth.instance.signOut();
}
await pref.setBool('isFirstLaunched', true);
_user = _auth.currentUser;
setUser(_auth.currentUser);
}
void signInAnonymously() async {
final authResult = await _auth.signInAnonymously();
setUser(authResult.user);
}
void setUser(User user) {
_user = user;
notifyListeners();
}
void signOut() async {
await _auth.signOut();
setUser(null);
}
void withdrawalAccount() async {
await getUser().delete();
setUser(null);
}
}
Dart
복사
앱의 첫 실행인지 여부 판단을 위해 Shared Preference 패키지를 사용합니다.
_prepareUser() 내부에서 앱의 첫 실행 판단을 통해서, 첫 실행의 경우 signOut() 함수를 호출함으로써 keychain 에 남아있던 인증 정보를 초기화 합니다.
Trouble Shooting
androd: com.google.firebase.FirebaseException: An internal error has occurred
iOS의 경우 firebase auth 를 flutter pub 으로 설치하면 cocoapod 까지 잘 연계되어 설치되었습니다. android의 경우 gradle 까지 작업은 되지 않아 gradle 파일을 직접 수정해줘야 합니다.
수정이 필요한 부분은 Firebase 버전마다 다를 수 있으므로 Firebase doc 을 링크합니다.