2. flutter with supabase
최종 업데이트 : 2025-02-09
import 'package:flutter/material.dart';
void main() {
runApp(const MainApp());
}
class MainApp extends StatelessWidget {
const MainApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: AuthPage(),
);
}
}
class AuthPage extends StatefulWidget {
const AuthPage({super.key});
@override
State<AuthPage> createState() => _AuthPageState();
}
class _AuthPageState extends State<AuthPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: [
const Text("이메일"),
],
),
),
);
}
}
state개념은 별도로 공부하심을 추천드립니다.
Scaffold 를 이용하여 body를 설정하겠습니다.
Center를 이용해 가운데 배치를 하고
column을 이용해 위젯을 세로로 배치하겠습니다.
Text를 이용해 텍스트를 출력하겠습니다.
const Text("이메일"),
const Text("패스워드"),
const Text("패스워드확인"),
TextButton(
onPressed: () {},
child: const Text("회원가입"),
),
TextButton(
onPressed: () {},
child: const Text("로그인"),
),
사용될 기본컨트롤을 배치합니다.
class _AuthPageState extends State<AuthPage> {
final TextEditingController _emailController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
final TextEditingController _passwordCheckController =
TextEditingController();
const Text("이메일"),
TextField(
controller: _emailController,
),
const Text("패스워드"),
TextField(
controller: _passwordController,
),
const Text("패스워드확인"),
TextField(
controller: _passwordCheckController,
),
TextButton(
onPressed: () {},
child: const Text("회원가입"),
),
TextButton(
onPressed: () {},
child: const Text("로그인"),
),
입력필드들을 추가하여 다시한번 확인해봅니다.
bool _isPasswordVisible = false;
bool _isPasswordCheckVisible = false;
const Text("패스워드"),
TextField(
controller: _passwordController,
obscureText: !_isPasswordVisible,
decoration: InputDecoration(
suffixIcon: IconButton(
icon: Icon(
_isPasswordVisible
? Icons.visibility
: Icons.visibility_off,
),
onPressed: () {
setState(() {
_isPasswordVisible = !_isPasswordVisible;
});
},
),
),
),
const Text("패스워드확인"),
TextField(
controller: _passwordCheckController,
obscureText: !_isPasswordCheckVisible,
decoration: InputDecoration(
suffixIcon: IconButton(
icon: Icon(
_isPasswordCheckVisible
? Icons.visibility
: Icons.visibility_off,
),
onPressed: () {
setState(() {
_isPasswordCheckVisible = !_isPasswordCheckVisible;
});
},
),
),
),
패스워드필드임으로 obscureText을 사용합니다.
_isPasswordVisible와 _isPasswordCheckVisible의 기본값이 false임으로
!를 넣어 반대값을 사용하여 true로 obscureText를 활성화함을 이해해야합니다.
decoration을 넣어 해당 TextField flet의 can_reveal_password기능을 만듭니다.
onPressed를 이용해 해당 decoration이 눌러졌을시 변경되도록 합니다.
원하는 기능이 제대로 되었는지 실행해서 확인해봅니다.
void _showSnackBar(String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(message)),
);
}
snackbar를 추가해줍니다.
Future<void> signupRequest() {
if (_emailController.text.isEmpty ||
_passwordController.text.isEmpty ||
_passwordCheckController.text.isEmpty) {
_showSnackBar("이메일, 패스워드, 패스워드확인란을 입력해주세요.");
return;
}
}
TextButton(
onPressed: signupRequest,
child: const Text("회원가입"),
),
회원가입을 위해 signupRequest를 만들고
회원가입을 위한 조건을 설정하고 실행하여 간단히 테스트해봅니다.
config.dart
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
class Config {
static String get supabaseUrl => dotenv.env['SUPABASE_URL'] ?? '';
static String get supabaseKey => dotenv.env['SUPABASE_KEY'] ?? '';
static Future<void> initialize() async {
await dotenv.load(fileName: ".env");
await Supabase.initialize(
url: supabaseUrl,
anonKey: supabaseKey,
);
}
}
final supabase = Supabase.instance.client;
main.dart
import 'package:app_flutter/config.dart';
import 'package:email_validator/email_validator.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Config.initialize();
runApp(const MainApp());
}
Future<void> signupRequest() async {
if (_emailController.text.isEmpty ||
_passwordController.text.isEmpty ||
_passwordCheckController.text.isEmpty) {
_showSnackBar("이메일, 패스워드, 패스워드확인란을 입력해주세요.");
return;
}
if (_passwordController.text != _passwordCheckController.text) {
_showSnackBar("패스워드가 일치하지 않습니다.");
return;
}
if (_passwordController.text.length < 6) {
_showSnackBar("패스워드는 6자리 이상이어야 합니다.");
return;
}
if (!EmailValidator.validate(_emailController.text)) {
_showSnackBar("이메일형식으로 입력해주세요.");
return;
}
try {
final response = await supabase.auth.signUp(
email: _emailController.text,
password: _passwordController.text,
);
_showSnackBar("${response.user!.email} 회원가입에 성공하였습니다.");
} catch (e) {
debugPrint("$e");
_showSnackBar("오류 발생: $e");
}
}
supabase를 사용하기위해 config.dart파일을 만들고
해당 파일을 불러와서 사용합니다.
await Config.initialize(); 실행시 초기화를 대기하기위해 await을 사용하고
main() 뒤에도 async를 넣어 비동기함수로 설정합니다.
WidgetsFlutterBinding.ensureInitialized();
비동기코드인 Config.initialize()을 실행하기전에 프레임워크를 초기화합니다.
email 검사의 경우 EmailValidator를 사용합니다.
supabase.auth.signInWithPassword을 사용하기 위해 앞에 await을 추가하고
signinRequest() 뒤에도 async 를 추가합니다.
비동기로 해당 함수가 작동할때 여러번 호출하더라도
await인 함수를 결과가 나올때까지 대기하게됩니다.
flet에서는 아무것도 붙이지 않은 동기함수로 설정되어있음으로
이는 따로 한번 공부해보시는게 좋습니다.
Future<void> signinRequest() async {
if (_emailController.text.isEmpty || _passwordController.text.isEmpty) {
_showSnackBar("이메일, 패스워드를 입력해주세요.");
return;
}
if (_passwordController.text.length < 6) {
_showSnackBar("패스워드는 6자리 이상이어야 합니다.");
return;
}
if (!EmailValidator.validate(_emailController.text)) {
_showSnackBar("이메일형식으로 입력해주세요.");
return;
}
try {
final response = await supabase.auth.signInWithPassword(
email: _emailController.text,
password: _passwordController.text,
);
_showSnackBar("${response.user!.email} 로그인에 성공하였습니다.");
} catch (e) {
debugPrint("$e");
_showSnackBar("오류 발생: $e");
}
}
supabase.auth.signInWithPassword까지 적용하여
정상 로그인까지 확인합니다.