구글 로그인

김동연·2025년 6월 1일

개발기록일지(Flutter)

목록 보기
12/32

구글 로그인

프로젝트를 하면서 필수적으로 구현하는 것이 로그인 기능이다. 그 중에서 가장 자주쓰면서 기본적이고 쉽게 만들 수 있는 것이 구글 로그인이다. 구현하는 방법은 파이어베이스를 통해 이루어진다.

파이어베이스

  • 현재는 iOS를 바탕으로 프로젝트를 진행하고 있기 때문에 안드로이드는 여유가 된다면 해볼 것이다.
  • 파이어베이스에서 필요한 파일들이 있는데, 이것을 각각 프로젝트 내부에 포함시켜야한다.(파일 위치에 유의하자)
  • 각각의 코드들은 firebase 사이트에서 찾아봐야한다.

Firebase_options.dart => lib

Firebase.json => 루트 디렉토리

google_service_Info.plist => ios/Runner 디렉토리 안

  • Firebase에서 가장 기본적인 세팅은 끝났다. 이제 코드 내에서 해결할 부분이다.

1. 의존성 설치

먼저 FirebaseFlutter 프로젝트를 Riverpod으로 관리하기 위해 필요한 패키지를 설치하자.

flutter pub add firebase_core      # Firebase 초기화를 위한 필수 패키지
flutter pub add firebase_auth      # Firebase 인증 (로그인/회원가입) 기능을 위한 패키지
flutter pub add google_sign_in     # Google 계정으로 로그인하기 위한 Google SDK 연동 패키지
flutter pub add cloud_firestore    # Firestore 데이터베이스에 접근하고 읽고 쓰기 위한 패키지
flutter pub add flutter_riverpod   # 상태 관리를 위한 Riverpod 라이브러리 

2. Firebase 초기화

  • 파이어베이스의 연동이 끝났으면 초기화를 먼저 해준다.
void main() async {
  WidgetsFlutterBinding.ensureInitialized(); // 비동기 초기화를 위한 바인딩 (필수) 
  await Firebase.initializeApp();   // Firebase 초기화 (필수)
  runApp(const ProviderScope(child: MyApp()));  // 앱 실행 + Riverpod ProviderScope 전역 상태 관리 컨테이너 등록
}
  • WidgetsFlutterBinding.ensureInitialized();
    • 비동기 초기화 작업으로 Flutter 엔진과 바인딩을 먼저 초기화
    • 주로 Firebase, SharedPreferences, Hive 같은 비동기 초기화가 필요한 라이브러리 사용 전 반드시 호출
    • 이걸 안 하면 Firebase.initializeApp() 등에서 runtime error 발생할 수 있음
  • await Firebase.initializeApp();

    • Firebase SDK를 Flutter 앱에 연결하는 초기화 코드(firebase_core 패키지를 설치했을 때 꼭 앱 시작 전에 한 번만 호출해야 함)
    • 이 코드를 통해 Firebase Auth, Firestore 등 다른 기능도 함께 연결됨
  • runApp(const ProviderScope(child: MyApp()));

    • 앱 전체에서 Riverpod Provider를 사용하기 위해 ProviderScope()로 감싸야함.

## 로그인 관련 서비스 구현
구글 로그인 → Firebase Auth → 유저 정보 Firestore 저장
```dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:cloud_firestore/cloud_firestore.dart';

/// Google 로그인 → Firebase 인증 → Firestore 유저 저장을 담당하는 서비스 클래스
class AuthService {
  final _auth = FirebaseAuth.instance; // Firebase 인증 인스턴스
  final _firestore = FirebaseFirestore.instance; // Firestore 인스턴스

  /// Google 계정으로 로그인하는 메서드
  Future<User?> signInWithGoogle() async {
    try {
      // 1. 사용자에게 Google 계정 선택 UI를 보여주고, 선택된 계정 정보를 가져옴
      final googleUser = await GoogleSignIn().signIn();
      if (googleUser == null) return null; // 사용자가 취소했을 경우

      // 2. 인증 토큰(access token + id token)을 가져옴
      final googleAuth = await googleUser.authentication;

      // 3. Firebase에서 사용할 수 있는 Google 인증 자격 정보 생성
      final credential = GoogleAuthProvider.credential(
        accessToken: googleAuth.accessToken,
        idToken: googleAuth.idToken,
      );

      // 4. FirebaseAuth에 Google 자격 증명을 넘겨 로그인 처리
      final userCredential = await _auth.signInWithCredential(credential);
      final user = userCredential.user; // 로그인된 사용자 정보
      if (user == null) return null;

      // 5. Firestore에 사용자 정보 저장 (이미 존재하면 merge)
      await _firestore.collection('users').doc(user.uid).set({
        'userId': user.uid,
        'displayName': user.displayName ?? '',
        'photoUrl': user.photoURL ?? '',
        'loginProviders': user.providerData.map((e) => e.providerId).toList(),
        'createdAt': FieldValue.serverTimestamp(),
      }, SetOptions(merge: true));

      // 6. 로그인된 Firebase 사용자 반환
      return user;
    } catch (e) {
      print('Login Error: $e'); // 오류 출력
      return null; // 실패 시 null 반환
    }
  }
}

/// Riverpod Provider로 AuthService를 전역에서 사용할 수 있게 등록
final authServiceProvider = Provider((ref) => AuthService());

3. 로그인 UI & ViewModel 구성

  • 필요와 복잡도에 따라 ViewModel 사용 여부가 달라진다. 아래의 코드안에 간단한 UI와 ViewModel을 구성했다.
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:your_project_name/core/service/auth_service.dart';

/// Google 로그인 버튼을 포함한 로그인 화면 위젯
class LoginScreen extends ConsumerWidget {
  const LoginScreen({super.key});

  
  Widget build(BuildContext context, WidgetRef ref) {
    // Provider에서 AuthService 인스턴스를 읽어옴
    final authService = ref.read(authServiceProvider);

    return Scaffold(
      appBar: AppBar(title: const Text('로그인')), // 상단 앱바
      body: Center(
        child: ElevatedButton.icon(
          onPressed: () async {
            // 버튼을 누르면 로그인 시도
            final user = await authService.signInWithGoogle();
            if (user != null) {
              // 로그인 성공 시 환영 메시지 출력
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(content: Text('환영합니다, ${user.displayName}!')),
              );
              // TODO: 홈 화면 등으로 이동
            }
          },
          icon: const Icon(Icons.login), // 버튼 왼쪽 아이콘
          label: const Text('Google로 로그인'), // 버튼 텍스트
        ),
      ),
    );
  }
}

나머지

이 외에 유저 모델을 만들어서 구글 로그인이 성공한 것을 바탕으로 Firebase에 저장해야한다. 아래는 예시이며 최종코드가 아니다.

  /// Google 로그인 실행 후 Firestore에 사용자 데이터 저장
  Future<UserCredential?> signInWithGoogle() async {
    final userCredential = await _authService.signInWithGoogle();
    final user = userCredential?.user;
    }
    
  //최초 로그인시 파이어스토어에 저장
  if (user != null) {
      final userModel = UserModel(
        userId: user.uid,
        displayName: user.displayName ?? 'NoName',
        email: user.email ?? 'unknown@email.com',
        photoUrl: user.photoURL ?? '',
        loginProviders: 'google',
      );
  

0개의 댓글