본문 바로가기
Flutter/Snippet

플러터에서 Google 로그인을 이용해 유저 정보를 관리하는 방법

by Maccrey Coding 2024. 8. 29.
반응형

 

Flutter로 앱을 개발할 때, 구글 로그인(Google Sign-In)을 사용하여 사용자의 인증과 유저 정보를 관리할 수 있습니다.

구글 로그인을 통해 유저의 기본 정보를 받아와서 Firebase Firestore에 저장하거나, 앱 내에서 활용할 수 있습니다.

이번 포스팅에서는 Flutter에서 구글 로그인을 설정하고, 유저 정보를 Firestore에 저장 및 관리하는 방법을 단계별로 설명하겠습니다.

1. 프로젝트 설정

Flutter에서 구글 로그인을 구현하려면 몇 가지 사전 작업이 필요합니다.

1.1 Firebase 프로젝트 생성 및 설정

  1. Firebase Console에서 새로운 프로젝트를 생성합니다.
  2. Firebase 프로젝트에 Android 및 iOS 앱을 추가합니다.
  3. google-services.json(Android) 및 GoogleService-Info.plist(iOS) 파일을 Flutter 프로젝트에 각각 추가합니다.
  4. Firebase Authentication에서 'Google' 제공자를 활성화합니다.

1.2 pubspec.yaml에 필요한 패키지 추가

다음 패키지를 pubspec.yaml 파일에 추가합니다.

dependencies:
  firebase_core: latest_version
  firebase_auth: latest_version
  google_sign_in: latest_version
  cloud_firestore: latest_version

2. 구글 로그인 구현

2.1 Firebase 초기화

main.dart 파일에서 Firebase를 초기화합니다.

import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:your_project_name/app.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(MyApp());
}

2.2 구글 로그인 로직 구현

구글 로그인을 처리하는 로직을 서비스 클래스로 분리합니다.

import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:your_project_name/models/user_model.dart';
import 'package:your_project_name/services/firestore_service.dart';

class AuthService {
  final FirebaseAuth _auth = FirebaseAuth.instance;
  final GoogleSignIn _googleSignIn = GoogleSignIn();
  final FirestoreService _firestoreService = FirestoreService();

  Future<UserModel?> signInWithGoogle() async {
    try {
      final GoogleSignInAccount? googleUser = await _googleSignIn.signIn();
      if (googleUser == null) {
        // 사용자가 로그인 취소
        return null;
      }

      final GoogleSignInAuthentication googleAuth = await googleUser.authentication;
      final AuthCredential credential = GoogleAuthProvider.credential(
        accessToken: googleAuth.accessToken,
        idToken: googleAuth.idToken,
      );

      final UserCredential result = await _auth.signInWithCredential(credential);
      final User? user = result.user;

      if (user != null) {
        // Firestore에 유저가 이미 존재하는지 확인
        UserModel? existingUser = await _firestoreService.getUser(user.uid);

        if (existingUser == null) {
          // Firestore에 유저 정보가 없다면 새로운 유저 정보 저장
          UserModel newUser = UserModel(
            uid: user.uid,
            email: user.email!,
            nickname: user.displayName ?? "New User",
            profileImageUrl: user.photoURL,
          );
          await _firestoreService.saveUser(newUser);
          return newUser;
        } else {
          return existingUser;
        }
      }
    } catch (e) {
      print(e.toString());
      return null;
    }
    return null;
  }

  Future<void> signOut() async {
    await _auth.signOut();
    await _googleSignIn.signOut();
  }
}

이제 이 AuthService 클래스를 사용하여 구글 로그인을 앱에서 처리할 수 있습니다

3. 유저 정보 관리

구글 로그인을 통해 가져온 유저 정보를 Firestore에 저장하고, 필요할 때 불러오는 로직을 구현합니다.

3.1 Firestore 서비스 작성

lib/services/firestore_service.dart 파일을 생성하고, 유저 정보를 Firestore에 저장하고 불러오는 로직을 작성합니다.

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:your_project_name/models/user_model.dart';

class FirestoreService {
  final FirebaseFirestore _db = FirebaseFirestore.instance;

  // Firestore에 유저 정보 저장
  Future<void> saveUser(UserModel user) async {
    await _db.collection('users').doc(user.uid).set(user.toMap());
  }

  // Firestore에서 유저 정보 불러오기
  Future<UserModel?> getUser(String uid) async {
    DocumentSnapshot doc = await _db.collection('users').doc(uid).get();
    if (doc.exists) {
      return UserModel.fromMap(doc.data() as Map<String, dynamic>, doc.id);
    }
    return null;
  }

  // 유저 정보 업데이트
  Future<void> updateUser(UserModel user) async {
    await _db.collection('users').doc(user.uid).update(user.toMap());
  }
}

3.2 유저 모델 정의

유저 정보를 관리하기 위한 모델을 정의합니다.

class UserModel {
  final String uid;
  final String email;
  final String? nickname;
  final String? profileImageUrl;

  UserModel({
    required this.uid,
    required this.email,
    this.nickname,
    this.profileImageUrl,
  });

  factory UserModel.fromMap(Map<String, dynamic> data, String uid) {
    return UserModel(
      uid: uid,
      email: data['email'] ?? '',
      nickname: data['nickname'],
      profileImageUrl: data['profileImageUrl'],
    );
  }

  Map<String, dynamic> toMap() {
    return {
      'email': email,
      'nickname': nickname,
      'profileImageUrl': profileImageUrl,
    };
  }

  UserModel copyWith({String? nickname, String? profileImageUrl}) {
    return UserModel(
      uid: uid,
      email: email,
      nickname: nickname ?? this.nickname,
      profileImageUrl: profileImageUrl ?? this.profileImageUrl,
    );
  }
}

4. UI에서 구글 로그인 연동

사용자가 버튼을 클릭하면 구글 로그인을 통해 인증을 처리하고, Firestore에 유저 정보를 저장하는 간단한 UI를 구현합니다.

import 'package:flutter/material.dart';
import 'package:your_project_name/services/auth_service.dart';
import 'package:your_project_name/models/user_model.dart';

class LoginScreen extends StatelessWidget {
  final AuthService _authService = AuthService();

  @override
  Widget build(BuildContext context) {
    return Scaffold(    
      appBar: AppBar(
        title: Text('Google Sign-In'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () async {
            UserModel? user = await _authService.signInWithGoogle();
            if (user != null) {
              // 로그인 성공 시, 유저 정보를 확인하고 다음 화면으로 이동
              Navigator.push(
                context,
                MaterialPageRoute(builder: (context) => UserProfileScreen(user: user)),
              );
            } else {
              // 로그인 실패 시, 에러 메시지 표시
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(content: Text('Failed to sign in with Google')),
              );
            }
          },
          child: Text('Sign in with Google'),
        ),
      ),
    );
  }
}

4.1 유저 프로필 화면

로그인 후, 유저의 정보를 보여주는 프로필 화면을 구현합니다.

import 'package:flutter/material.dart';
import 'package:your_project_name/models/user_model.dart';
import 'package:your_project_name/services/auth_service.dart';
import 'package:your_project_name/services/firestore_service.dart';

class UserProfileScreen extends StatelessWidget {
  final UserModel user;
  final AuthService _authService = AuthService();
  final FirestoreService _firestoreService = FirestoreService();

  UserProfileScreen({required this.user});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('${user.nickname}\'s Profile'),
        actions: [
          IconButton(
            icon: Icon(Icons.logout),
            onPressed: () async {
              await _authService.signOut();
              Navigator.of(context).popUntil((route) => route.isFirst);
            },
          )
        ],
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            if (user.profileImageUrl != null)
              Center(
                child: CircleAvatar(
                  radius: 50,
                  backgroundImage: NetworkImage(user.profileImageUrl!),
                ),
              ),
            SizedBox(height: 20),
            Text(
              'Nickname: ${user.nickname}',
              style: TextStyle(fontSize: 18),
            ),
            SizedBox(height: 10),
            Text(
              'Email: ${user.email}',
              style: TextStyle(fontSize: 18),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () async {
                // 예시로 유저 닉네임을 업데이트하는 기능
                UserModel updatedUser = user.copyWith(nickname: 'Updated Nickname');
                await _firestoreService.updateUser(updatedUser);
                ScaffoldMessenger.of(context).showSnackBar(
                  SnackBar(content: Text('Nickname updated successfully!')),
                );
              },
              child: Text('Update Nickname'),
            ),
          ],
        ),
      ),
    );
  }
}

5. 맺음말

이제 구글 로그인을 통해 사용자의 정보를 Firebase Firestore에 저장하고, 관리하는 방법을 구현했습니다.

사용자는 구글 로그인을 통해 앱에 로그인하고, 기본적인 프로필 정보를 확인하거나 업데이트할 수 있습니다.

확장 포인트

  1. 추가 유저 정보 관리: 기본적인 유저 정보 외에도, 사용자 선호도, 활동 로그 등을 추가적으로 저장하고 관리할 수 있습니다.
  2. 유저 정보 보안: Firestore 규칙을 설정하여, 사용자 본인만 자신의 정보를 읽고 쓸 수 있도록 설정할 수 있습니다.
  3. 소셜 로그인 추가: 구글 로그인 외에도 Facebook, Apple 등 다양한 소셜 로그인 제공자를 추가할 수 있습니다.
  4. UI 개선: 로그인 및 프로필 화면을 보다 직관적이고, 사용자 친화적으로 디자인할 수 있습니다.

이 포스팅에서는 구글 로그인을 사용해 유저 정보를 관리하는 방법을 소개했지만, 이를 바탕으로 다양한 확장 기능을 추가하여 더욱 완성도 높은 앱을 만들 수 있습니다.

공감과 댓글은 저에게 큰 힘이 됩니다.

Starting Google Play App Distribution! "Tester Share" for Recruiting 20 Testers for a Closed Test.

 

Tester Share [테스터쉐어] - Google Play 앱

Tester Share로 Google Play 앱 등록을 단순화하세요.

play.google.com

 

 

반응형