다시봄개발 가이드Firebase 연동
Developer Guide v1.0

다시봄 × Firebase
연동 완전 가이드

시니어 라이프케어 메신저 다시봄 앱에 Firebase 인증, Firestore, FCM을 연동하는 단계별 가이드입니다. 전화번호 SMS 인증부터 AI 친구 OpenAI 연동, GPS 위치 서비스까지 모든 과정을 다룹니다.

Flutter 3.xFirebase SDK 2.xFlutterFire CLIOpenAI API
🙌Flutter나 터미널이 처음이신가요?설치부터 차근차근 알려드릴게요!
초보자 가이드 →

개요

다시봄 앱은 Flutter로 개발된 시니어 라이프케어 메신저입니다. 현재 소스코드에는 모의(mock) 구현이 포함되어 있으며, 이 가이드를 따라 실제 Firebase 서비스와 연동하면 프로덕션 수준의 앱을 완성할 수 있습니다.

연동 아키텍처
Firebase Auth
전화번호 SMS 인증
Firestore
채팅 / 사용자 데이터
FCM
푸시 알림
OpenAI API
AI 친구 철수/영희

사전 준비

연동 전 아래 항목을 모두 준비해 주세요.

Flutter SDK 3.0 이상 설치
flutter --version
Dart SDK 3.0 이상 (Flutter에 포함)
dart --version
Firebase CLI 설치
npm install -g firebase-tools
Google 계정 (Firebase 콘솔 접근용)
OpenAI API 키 (AI 친구 연동용)

1

Firebase 프로젝트 생성

Firebase 콘솔에서 새 프로젝트를 만들고 앱을 등록합니다.

  1. 1Firebase 콘솔에 접속하여 프로젝트 추가를 클릭합니다.
  2. 2프로젝트 이름을 dacibom으로 입력하고 Google 애널리틱스를 활성화합니다.
  3. 3프로젝트 생성 후 Android 앱 추가를 클릭합니다. 패키지명은 com.dacibom.app으로 설정합니다.
  4. 4iOS 앱도 동일하게 추가합니다. 번들 ID는 com.dacibom.app을 사용합니다.
패키지명 주의: Android의 applicationId와 Firebase에 등록한 패키지명이 정확히 일치해야 합니다.android/app/build.gradle에서 확인하세요.

2

FlutterFire CLI 설치 및 설정

FlutterFire CLI를 사용하면 Firebase 설정 파일을 자동으로 생성할 수 있습니다.

프로젝트 루트 디렉터리(dacibom/)에서 아래 명령어를 순서대로 실행합니다.

bash
# 1. FlutterFire CLI 전역 설치
dart pub global activate flutterfire_cli

# 2. Firebase CLI 로그인
firebase login

# 3. FlutterFire 설정 (대화형 프롬프트 진행)
flutterfire configure

# → 위에서 생성한 class="token-string">'dacibom' 프로젝트를 선택
# → Android, iOS 플랫폼 모두 선택
# → lib/firebase_options.dart 파일이 자동 생성됩니다
flutterfire configure 실행 시 google-services.json (Android)과GoogleService-Info.plist (iOS)가 자동으로 올바른 위치에 배치됩니다.

생성된 lib/firebase_options.dart를 사용하여 lib/main.dart를 다음과 같이 수정합니다.

dart
import class="token-string">'package:firebase_core/firebase_core.dart';
import class="token-string">'firebase_options.dart'; class=class="token-string">"token-comment">// 자동 생성된 파일

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  class=class="token-string">"token-comment">// Firebase 초기화 (반드시 runApp 전에 호출)
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );

  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => AuthService()),
        ChangeNotifierProvider(create: (_) => AiChatService()),
      ],
      child: const DacibomApp(),
    ),
  );
}

3

전화번호 인증 설정

Firebase 콘솔에서 전화번호 인증을 활성화하고 플랫폼별 설정을 완료합니다.

Firebase 콘솔 설정

  1. 1Firebase 콘솔 → AuthenticationSign-in method 탭으로 이동
  2. 2전화 항목을 클릭하여 사용 설정으로 변경 후 저장
  3. 3테스트 전화번호 추가 (개발 중 실제 SMS 발송 없이 테스트 가능): +82 10-0000-0000 → 코드 123456

Android 설정

android/app/build.gradle에 SHA-1 인증서 지문을 추가해야 합니다.

bash
# SHA-1 지문 확인 (디버그 키스토어)
cd android && ./gradlew signingReport

# 출력된 SHA-1 값을 Firebase 콘솔에 등록:
# 프로젝트 설정 → 앱 → SHA 인증서 지문 추가

iOS 설정

ios/Runner/Info.plist에 URL Scheme을 추가합니다.

xml

CFBundleURLTypes

  
    CFBundleTypeRole
    Editor
    CFBundleURLSchemes
    
      
      com.googleusercontent.apps.YOUR_CLIENT_ID
    
  

4

auth_service.dart 실제 연동

모의 구현을 Firebase Auth 실제 호출로 교체합니다.

lib/services/auth_service.dart의 두 메서드를 아래 코드로 교체합니다.

dart
import class="token-string">'package:firebase_auth/firebase_auth.dart';
import class="token-string">'package:flutter/material.dart';

class AuthService extends ChangeNotifier {
  final FirebaseAuth _auth = FirebaseAuth.instance;
  bool _isAuthenticated = false;
  String? _verificationId;
  String? _phoneNumber;

  bool get isAuthenticated => _isAuthenticated;
  String? get phoneNumber => _phoneNumber;

  class=class="token-string">"token-comment">// ① SMS 인증 요청
  Future<void> requestSmsCode(String phone) async {
    class=class="token-string">"token-comment">// 한국 번호 형식 변환: 01012345678 → +821012345678
    final formatted = class="token-string">'+82${phone.substring(1)}';
    _phoneNumber = phone;

    await _auth.verifyPhoneNumber(
      phoneNumber: formatted,
      timeout: const Duration(seconds: 60),
      verificationCompleted: (PhoneAuthCredential credential) async {
        class=class="token-string">"token-comment">// Android 자동 인증 처리
        await _auth.signInWithCredential(credential);
        _isAuthenticated = true;
        notifyListeners();
      },
      verificationFailed: (FirebaseAuthException e) {
        debugPrint(class="token-string">'인증 실패: ${e.message}');
      },
      codeSent: (String verificationId, int? resendToken) {
        _verificationId = verificationId;
        notifyListeners();
      },
      codeAutoRetrievalTimeout: (String verificationId) {
        _verificationId = verificationId;
      },
    );
  }

  class=class="token-string">"token-comment">// ② SMS 코드 확인 및 로그인
  Future verifySmsCode(String code) async {
    if (_verificationId == null) return false;

    try {
      final credential = PhoneAuthProvider.credential(
        verificationId: _verificationId!,
        smsCode: code,
      );
      final result = await _auth.signInWithCredential(credential);
      _isAuthenticated = result.user != null;
      notifyListeners();
      return _isAuthenticated;
    } on FirebaseAuthException catch (e) {
      debugPrint(class="token-string">'코드 확인 실패: ${e.message}');
      return false;
    }
  }

  class=class="token-string">"token-comment">// ③ 로그아웃
  Future<void> signOut() async {
    await _auth.signOut();
    _isAuthenticated = false;
    _phoneNumber = null;
    _verificationId = null;
    notifyListeners();
  }
}
중요: main.dart에서 Firebase.initializeApp()이 완료된 후에AuthService가 초기화되어야 합니다. await Firebase.initializeApp()은 반드시runApp() 이전에 호출하세요.

5

Firestore 데이터베이스 설정

채팅 메시지와 사용자 정보를 저장할 Firestore를 설정합니다.

Firestore 활성화

  1. 1Firebase 콘솔 → Firestore Database → 데이터베이스 만들기
  2. 2프로덕션 모드 또는 테스트 모드 선택 (개발 중에는 테스트 모드 권장)
  3. 3리전 선택: asia-northeast3 (서울)

보안 규칙 설정

firestore rules
rules_version = class="token-string">'2';
service cloud.firestore {
  match /databases/{database}/documents {

    class=class="token-string">"token-comment">// 사용자 정보: 본인만 읽기/쓰기
    match /users/{userId} {
      allow read, write: if request.auth != null
                         && request.auth.uid == userId;
    }

    class=class="token-string">"token-comment">// 채팅방: 참여자만 접근 가능
    match /chatRooms/{roomId} {
      allow read, write: if request.auth != null
        && request.auth.uid in resource.data.participants;

      class=class="token-string">"token-comment">// 메시지: 채팅방 참여자만 읽기/쓰기
      match /messages/{messageId} {
        allow read, write: if request.auth != null
          && request.auth.uid in
             get(/databases/$(database)/documents/chatRooms/$(roomId)).data.participants;
      }
    }
  }
}

컬렉션 구조

Firestore
├── users/ ← 사용자 정보
└── {uid}
├── nickname, phoneNumber
├── location (GPS 동네)
└── aiFriendName1, aiFriendName2
└── chatRooms/ ← 채팅방
└── {roomId}
├── participants[], title, type
└── messages/
└── {messageId}
└── senderId, text, timestamp

6

OpenAI AI 친구 실제 연동

철수/영희 AI 친구를 OpenAI GPT API와 연결합니다.

lib/services/ai_chat_service.dartsendMessage 메서드에서 시뮬레이션 코드를 아래 실제 API 호출로 교체합니다.

API 키 보안: OpenAI API 키는 절대 클라이언트 코드에 직접 포함하지 마세요. Firebase Cloud Functions 또는 별도 백엔드 서버를 통해 프록시하는 것을 강력히 권장합니다.
dart
class=class="token-string">"token-comment">// pubspec.yaml에 추가: dart_openai: ^4.1.0
import class="token-string">'package:dart_openai/dart_openai.dart';

class=class="token-string">"token-comment">// main.dart에서 초기화 (Firebase 초기화 이후)
OpenAI.apiKey = const String.fromEnvironment(class="token-string">'OPENAI_API_KEY');

class=class="token-string">"token-comment">// ai_chat_service.dart - sendMessage 메서드 교체
Future<void> sendMessage(
  String roomId,
  String text,
  String currentUserId,
  String aiType,
  String aiName,
) async {
  class=class="token-string">"token-comment">// 1. 사용자 메시지 추가
  final userMsg = ChatMessage(
    id: DateTime.now().millisecondsSinceEpoch.toString(),
    roomId: roomId,
    senderId: currentUserId,
    text: text,
    timestamp: DateTime.now(),
    isMe: true,
  );
  _messages.add(userMsg);
  notifyListeners();

  try {
    class=class="token-string">"token-comment">// 2. 대화 히스토리 구성 (최근 10개 메시지)
    final history = _messages.takeLast(10).map((msg) =>
      OpenAIChatCompletionChoiceMessageModel(
        role: msg.isMe
          ? OpenAIChatMessageRole.user
          : OpenAIChatMessageRole.assistant,
        content: [
          OpenAIChatCompletionChoiceMessageContentItemModel.text(msg.text)
        ],
      )
    ).toList();

    class=class="token-string">"token-comment">// 3. OpenAI API 호출
    final response = await OpenAI.instance.chat.create(
      model: class="token-string">'gpt-4o-mini',
      messages: [
        class=class="token-string">"token-comment">// 시스템 프롬프트 (페르소나 설정)
        OpenAIChatCompletionChoiceMessageModel(
          role: OpenAIChatMessageRole.system,
          content: [
            OpenAIChatCompletionChoiceMessageContentItemModel.text(
              getPersonaPrompt(aiName, aiType)
            )
          ],
        ),
        ...history,
      ],
      maxTokens: 300,
      temperature: 0.8,
    );

    final aiText = response.choices.first.message.content?.first.text ?? class="token-string">'';

    class=class="token-string">"token-comment">// 4. AI 응답 메시지 추가
    _messages.add(ChatMessage(
      id: (DateTime.now().millisecondsSinceEpoch + 1).toString(),
      roomId: roomId,
      senderId: class="token-string">'ai_$aiType',
      text: aiText,
      timestamp: DateTime.now(),
      isMe: false,
    ));
    notifyListeners();

  } catch (e) {
    debugPrint(class="token-string">'OpenAI API 오류: $e');
    class=class="token-string">"token-comment">// 오류 시 fallback 메시지
    _messages.add(ChatMessage(
      id: (DateTime.now().millisecondsSinceEpoch + 1).toString(),
      roomId: roomId,
      senderId: class="token-string">'ai_$aiType',
      text: class="token-string">'잠시 연결이 불안정합니다. 조금 후에 다시 말씀해 주세요.',
      timestamp: DateTime.now(),
      isMe: false,
    ));
    notifyListeners();
  }
}

API 키 환경 변수 설정 (--dart-define 방식)

bash
# 개발 실행 시
flutter run --dart-define=OPENAI_API_KEY=sk-your-key-here

# 빌드 시
flutter build apk --dart-define=OPENAI_API_KEY=sk-your-key-here

7

GPS 위치 서비스 설정

원터치 GPS 동네 설정 기능을 위한 플랫폼별 권한 설정입니다.

Android 권한 설정

xml

class="token-string">"http:class="token-commentclass="token-string">">//schemas.android.com/apk/res/android">

  
  class="token-string">"android.permission.ACCESS_FINE_LOCATION" />
  class="token-string">"android.permission.ACCESS_COARSE_LOCATION" />

  
    ...
  

iOS 권한 설정

xml

NSLocationWhenInUseUsageDescription
동네 설정을 위해 현재 위치를 사용합니다.

NSLocationAlwaysAndWhenInUseUsageDescription
동네 설정을 위해 현재 위치를 사용합니다.

mypage_screen.dart 위치 서비스 연동

dart
class=class="token-string">"token-comment">// pubspec.yaml에 추가:
class=class="token-string">"token-comment">// geolocator: ^11.1.0
class=class="token-string">"token-comment">// geocoding: ^3.0.0

import class="token-string">'package:geolocator/geolocator.dart';
import class="token-string">'package:geocoding/geocoding.dart';

Future<void> _setLocation() async {
  class=class="token-string">"token-comment">// 1. 권한 확인
  LocationPermission permission = await Geolocator.checkPermission();
  if (permission == LocationPermission.denied) {
    permission = await Geolocator.requestPermission();
    if (permission == LocationPermission.denied) return;
  }

  class=class="token-string">"token-comment">// 2. 현재 위치 획득
  final position = await Geolocator.getCurrentPosition(
    desiredAccuracy: LocationAccuracy.medium,
  );

  class=class="token-string">"token-comment">// 3. 좌표 → 행정구역 변환
  final placemarks = await placemarkFromCoordinates(
    position.latitude,
    position.longitude,
  );

  if (placemarks.isNotEmpty) {
    final place = placemarks.first;
    class=class="token-string">"token-comment">// 예: class="token-string">"포항시 북구"
    final location = class="token-string">'${place.locality} ${place.subLocality}';

    class=class="token-string">"token-comment">// 4. Firestore에 저장
    await FirebaseFirestore.instance
        .collection(class="token-string">'users')
        .doc(currentUserId)
        .update({class="token-string">'location': location});

    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text(class="token-string">'동네가 "$location"으로 설정되었습니다.')),
    );
  }
}

8

FCM 푸시 알림 설정

새 메시지 수신 시 푸시 알림을 전송하는 FCM을 설정합니다.

FCM 초기화 코드

dart
class=class="token-string">"token-comment">// lib/services/notification_service.dart(신규 파일 생성)
import class="token-string">'package:firebase_messaging/firebase_messaging.dart';
import class="token-string">'package:flutter_local_notifications/flutter_local_notifications.dart';

class NotificationService {
  final FirebaseMessaging _messaging = FirebaseMessaging.instance;

  Future<void> initialize() async {
    class=class="token-string">"token-comment">// 1. 알림 권한 요청
    await _messaging.requestPermission(
      alert: true,
      badge: true,
      sound: true,
    );

    class=class="token-string">"token-comment">// 2. FCM 토큰 획득 (Firestore에 저장)
    final token = await _messaging.getToken();
    if (token != null) {
      await _saveTokenToFirestore(token);
    }

    class=class="token-string">"token-comment">// 3. 포그라운드 메시지 처리
    FirebaseMessaging.onMessage.listen((RemoteMessage message) {
      _showLocalNotification(message);
    });

    class=class="token-string">"token-comment">// 4. 백그라운드 메시지 핸들러 등록
    FirebaseMessaging.onBackgroundMessage(_backgroundHandler);
  }

  Future<void> _saveTokenToFirestore(String token) async {
    final uid = FirebaseAuth.instance.currentUser?.uid;
    if (uid == null) return;
    await FirebaseFirestore.instance
        .collection(class="token-string">'users')
        .doc(uid)
        .update({class="token-string">'fcmToken': token});
  }
}

class=class="token-string">"token-comment">// 백그라운드 핸들러 (최상위 함수로 선언 필수)
@pragma(class="token-string">'vm:entry-point')
Future<void> _backgroundHandler(RemoteMessage message) async {
  await Firebase.initializeApp();
  debugPrint(class="token-string">'백그라운드 메시지: ${message.messageId}');
}

Android 설정

xml


class="token-string">"com.google.firebase.messaging.FirebaseMessagingService"
  android:exported=class="token-string">"false">
  
    class="token-string">"com.google.firebase.MESSAGING_EVENT" />
  
iOS APNs 설정 필요: iOS에서 FCM을 사용하려면 Apple Developer 계정에서 APNs 인증 키(.p8)를 생성하고 Firebase 콘솔 → 프로젝트 설정 → 클라우드 메시징 → Apple 앱 구성에 업로드해야 합니다.

최종 체크리스트

Firebase 프로젝트 생성 및 Android/iOS 앱 등록
flutterfire configure 실행 → firebase_options.dart 생성
main.dart에 Firebase.initializeApp() 추가
Firebase Auth 전화번호 인증 활성화
Android SHA-1 지문 등록
iOS URL Scheme 설정
auth_service.dart 실제 Firebase 코드로 교체
Firestore 데이터베이스 생성 및 보안 규칙 설정
ai_chat_service.dart OpenAI API 연동
Android/iOS 위치 권한 설정
FCM 초기화 및 백그라운드 핸들러 등록
iOS APNs 인증 키 Firebase 콘솔 업로드
프로덕션 Firestore 보안 규칙 강화권장
OpenAI API 키 백엔드 프록시 처리권장
🌸
다시봄 Firebase 연동 완료!

모든 단계를 완료하면 전화번호 인증, AI 친구 채팅, GPS 동네 설정, 푸시 알림이
실제 Firebase 서비스와 연동된 프로덕션 앱이 완성됩니다.