본문 바로가기
Flutter for Beginners

Flutter Gemini 앱

by Records that rule memory 2025. 4. 22.
728x90

Gemini App icon

Gemini App에서 사용되는 플러그인

dio

dio는 Dart 및 Flutter 앱에서 HTTP 통신을 보다 쉽고 강력하게 처리할 수 있도록 도와주는 비동기 HTTP 클라이언트 라이브러리입니다.

기능 설명
GET, POST, PUT, DELETE 지원 RESTful API에 필요한 모든 메서드 지원
인터셉터 (Interceptor) 요청/응답 전후에 가로채서 처리 가능 (예: 인증 토큰 자동 삽입)
FormData 업로드 파일/폼데이터 업로드에 최적화 (multipart/form-data)
타임아웃 설정 연결, 수신, 요청 타임아웃 각각 설정 가능
진행률 표시 다운로드/업로드 진행 상황 추적 가능
자동 재시도 실패한 요청을 자동으로 재시도 (옵션)
쿠키 관리 내장 CookieJar 또는 사용자 지정 Cookie 설정 가능

기본 사용법

import 'package:dio/dio.dart';

void fetchData() async {
  final dio = Dio(); // Dio 인스턴스 생성

  try {
    final response = await dio.get('https://api.example.com/data');
    print(response.data); // 서버 응답 출력
  } catch (e) {
    print('요청 실패: $e');
  }
}

 

1. POST 요청 (JSON 또는 FormData)

// JSON 데이터 POST
await dio.post('https://example.com/api',
  data: {'name': '홍길동', 'age': 30},
);

// 파일 업로드 (FormData)
final formData = FormData.fromMap({
  'name': '홍길동',
  'profile': await MultipartFile.fromFile('path/to/image.png'),
});
await dio.post('https://example.com/upload', data: formData);

 

2. Interceptor 예시 (토큰 자동 추가)

dio.interceptors.add(InterceptorsWrapper(
  onRequest: (options, handler) {
    options.headers['Authorization'] = 'Bearer YOUR_TOKEN';
    return handler.next(options);
  },
));

 

3. 고급 설정 예시

final dio = Dio(BaseOptions(
  baseUrl: 'https://api.example.com/',
  connectTimeout: const Duration(seconds: 5),
  receiveTimeout: const Duration(seconds: 3),
  headers: {'Accept': 'application/json'},
));

관련 플러그인

플러그인 설명
dio_http_cache 응답 캐싱 지원
dio_cookie_manager 쿠키 자동 관리
pretty_dio_logger 콘솔용 요청/응답 로깅

Hive

HiveFlutter와 Dart 전용의 초고속 키-값(Key-Value) 기반 NoSQL 로컬 데이터베이스입니다.

기능 설명
빠른 속도 네이티브 코드보다 빠르게 동작 (메모리 기반 캐시)
간단한 구조 NoSQL 스타일, Box 단위 저장소
Flutter 친화적 Null-safety, 타입 안전, 모바일 최적화
지속성 저장 기기 로컬에 데이터 영구 저장
확장성 어댑터를 통해 사용자 정의 클래스도 저장 가능
test-friendly 쉽게 모킹 가능, 단위 테스트에 적합

설치

dependencies:
  hive: ^2.2.3
  hive_flutter: ^1.1.0
flutter pub get

기본 사용법

1. 초기화 및 사용

import 'package:hive_flutter/hive_flutter.dart';

void main() async {
  await Hive.initFlutter(); // Flutter용 Hive 초기화
  await Hive.openBox<String>('chat_history'); // 문자열 저장용 Box 열기

  runApp(const MyApp());
}
  • Box: Hive의 핵심 단위
var box = Hive.box<String>('chat_history');

// 쓰기
box.add('Hello, world!');
box.put('latest', 'Hi there!'); // 키 지정도 가능

// 읽기
print(box.getAt(0));      // 인덱스로 가져오기
print(box.get('latest')); // 키로 가져오기

// 삭제
box.deleteAt(0);
box.clear(); // 전체 삭제

 

2. Hive + Flutter UI 연동

2.1. ValueListenableBuilder로 실시간 UI 연결

ValueListenableBuilder(
  valueListenable: Hive.box<String>('chat_history').listenable(),
  builder: (context, Box<String> box, _) {
    return ListView(
      children: box.values.map((v) => Text(v)).toList(),
    );
  },
);

 

2.2. 직접 StreamBuilder와 연결 (custom stream)

Stream<List<String>> chatStream(Box<String> box) {
  final controller = StreamController<List<String>>();
  controller.add(box.values.toList());

  box.listenable().addListener(() {
    controller.add(box.values.toList());
  });

  return controller.stream;
}

Hive 사용 추천 앱

앱 종류 설명
채팅 앱 메시지 기록 로컬 저장
To-Do 앱 할 일 목록 로컬 저장
캐시 앱 JSON API 응답 로컬 캐싱
사용자 설정 저장 테마, 언어 등 설정 저장

google_generative_ai

Google에서 제공하는 Gemini API를 Dart/Flutter에서 직접 사용할 수 있게 해주는 공식 플러그인입니다.

항목 내용
플러그인 이름 google_generative_ai
현재 버전 ^0.4.7 (2025년 기준 최신)
목적 Gemini 모델과 직접 통신 (텍스트 생성, 대화 세션 등)
제공처 Google 공식 (Dart용 Gemini SDK)
사용 가능 모델 gemini-pro, gemini-2.0-flash, gemini-1.5-pro, 등

기본 사용법

1. 모델 초기화

final model = GenerativeModel(
  model: 'gemini-2.0-flash',
  apiKey: 'YOUR_API_KEY', // 또는 dotenv 사용 가능
);

 

2. 메시지 보내기

final response = await model.generateContent([
  Content.text('Flutter로 앱을 만들고 있어요.')
]);

print(response.text); // 결과 출력

 

3. ChatSession으로 대화 유지

final chat = model.startChat();

final response = await chat.sendMessage(
  Content.text('이전 대화 기억해?'),
);

print(response.text);
  • startChat()을 쓰면 대화 문맥이 유지되어 실제 챗봇처럼 작동합니다.

4. Content 생성 방식

Content.text('텍스트만 포함된 메시지');
Content.model('모델 응답으로 저장된 텍스트');
Content.multi([
  TextPart('텍스트'),
  ImagePart(bytes: imageBytes, mimeType: 'image/png'),
]);

 

5. 고급 설정

final model = GenerativeModel(
  model: 'gemini-2.0-pro',
  apiKey: dotenv.env['GEMINI_API_KEY']!,
  generationConfig: GenerationConfig(
    temperature: 0.9,         // 창의성 조절 (0~1)
    maxOutputTokens: 1024,    // 최대 응답 길이
    topK: 40,                 // 확률 기반 샘플링
    topP: 0.95,
  ),
  safetySettings: [
    SafetySetting(HarmCategory.harassment, HarmBlockThreshold.low),
  ],
);

주요 클래스

클래스/함수 설명
GenerativeModel Gemini 모델 정의 (버전, 키, 옵션 포함)
generateContent() 비동기 응답 생성 (한 번 요청)
startChat() 지속적인 대화 세션 생성
ChatSession 대화 상태 추적 객체
Content / TextPart 전송할 메시지 정의용 클래스
GenerationConfig 응답 길이, 창의성 조절
SafetySetting 유해 콘텐츠 필터링 옵션

flutter_markdown

Flutter 앱에서 마크다운(Markdown) 형식의 텍스트를 위젯으로 렌더링할 수 있도록 도와주는 플러그인입니다. 이 플러그인을 사용하면 **굵은 글씨**, _기울임_, [링크](https://...), 코드 등 마크다운 문법을 자연스럽게 앱에서 표현할 수 있습니다.

항목 설명
플러그인 이름 flutter_markdown
최신 버전 (2025.04 기준) ^0.6.18
제공 기능 마크다운 텍스트 렌더링 (텍스트, 링크, 리스트, 코드, 이미지 등)
공식 문서 https://pub.dev/packages/flutter_markdown

기본 사용법

1. 마크다운 텍스트 렌더링

import 'package:flutter_markdown/flutter_markdown.dart';

MarkdownBody(
  data: '**굵은 글씨**, _기울임_, [링크](https://flutter.dev)',
)

또는 스크롤이 가능한 영역에 렌더링하려면:

Markdown(
  data: '# 제목\n\n**굵은 텍스트** 와 일반 텍스트를 혼합할 수 있어요.',
)

 

2. 스타일 커스터마이징

MarkdownBody(
  data: '## 제목\n_기울임_ **굵게**',
  styleSheet: MarkdownStyleSheet.fromTheme(Theme.of(context)).copyWith(
    h2: const TextStyle(color: Colors.indigo, fontWeight: FontWeight.bold),
    p: const TextStyle(fontSize: 16, height: 1.5),
  ),
)

 

3. 링크 자동 열기

MarkdownBody(
  data: '[Flutter](https://flutter.dev)',
  onTapLink: (text, href, title) {
    print('링크 클릭됨: $href');
  },
)

 

4. 이미지 지원

MarkdownBody(
  data: '![Flutter](https://flutter.dev/images/flutter-logo-sharing.png)',
)

build_runner

Dart/Flutter 생태계에서 코드 생성(code generation)을 자동화하기 위한 핵심 유틸리티 플러그인입니다.

Dart의 코드 생성 도구(code generator) 실행기를 위한 플러그인입니다. 예를 들어 JSON 직렬화, Hive 어댑터, Freezed 모델 등을 자동 생성할 때 사용됩니다.

주로 함께 쓰는 코드 생성 플러그인들

사용하는 기능 함께 사용하는 패키지
JSON 직렬화 json_serializable
immutable 모델 freezed
Hive TypeAdapter hive_generator
Drift ORM drift_dev
GraphQL 모델 graphql_codegen

 

함께 쓰는 예 (예: Hive):

dependencies:
  hive: ^2.2.3
  hive_flutter: ^1.1.0

dev_dependencies:
  build_runner: ^2.4.6
  hive_generator: ^2.0.1

사용 방법

예: HiveAdapter 생성

@HiveType(typeId: 0)
class User {
  @HiveField(0)
  final String name;

  @HiveField(1)
  final int age;

  User(this.name, this.age);
}

 

터미널에서 코드 생성

flutter pub run build_runner build
명령어 설명
build 처음부터 생성
watch 파일 저장 시 자동 갱신 (핫 리로드처럼)
clean 이전 생성된 파일 삭제
flutter pub run build_runner watch

Gemini App 만들기

Gemini API Key 발급

APK Key는 Gemini 1.5/2.0 모델과 직접 통신할 수 있도록 해줍니다.

Google Gemini API Key 발급 절차 (2025년 기준)

 

1.Google AI Studio 접속

 

로그인 - Google 계정

이메일 또는 휴대전화

accounts.google.com

2.  "API Key 만들기" 버튼 클릭

  • 로그인 후, 상단 또는 중앙에 있는 [Create API Key] 버튼 클릭

3. 키 이름 지정 및 발급

  • 키 이름은 자유롭게 (예: gemini_flutter_dev)
  • 생성된 키는 복사하여 안전하게 보관

4. 보안 주의사항

  • 절대 키를 코드에 직접 노출하지 마세요 (특히 GitHub 등 공개 저장소)
  • .env에 저장하고 dotenv로 불러오기:
GEMINI_API_KEY=AIzaSyA...
await dotenv.load();
final key = dotenv.env['GEMINI_API_KEY'];
728x90

App Code

pubspec.yaml

dependencies:
  flutter:
    sdk: flutter
    
  dio: ^5.8.0+1
  flutter_dotenv: ^5.2.1
  hive: ^2.2.3
  hive_flutter: ^1.1.0
  google_generative_ai: ^0.4.7
  flutter_markdown: ^0.6.18

dev_dependencies:
  flutter_test:
    sdk: flutter
    
  build_runner: ^2.4.6
  hive_generator: ^2.0.0

  flutter_launcher_icons: ^0.13.1

flutter_icons:
  android: true
  ios: false
  image_path: "assets/app_icon.png"

flutter:
  assets:
    - .env

app_icon.png
0.38MB

app/src/main/AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- 인터넷 권한 -->
    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:label="Andrew Gemini Chat"
        android:name="${applicationName}"
        android:icon="@mipmap/ic_launcher">
...
  • 네트워크 권한만 추가해주면됩니다.

lib/services/chat_stream.dart

import 'dart:async'; // 비동기 작업과 StreamController 사용을 위한 패키지
import 'package:hive/hive.dart'; // Hive DB 접근을 위한 핵심 패키지
import 'package:hive_flutter/hive_flutter.dart'; // Hive와 Flutter 연동을 위한 패키지

/// 채팅 메시지를 저장한 Hive Box를 감시하고,
/// 변경이 감지될 때마다 최신 메시지 목록(List<String>)을 스트림으로 내보낸다.
Stream<List<String>> chatStream(Box<String> chatBox) {
  // Stream을 수동으로 제어할 수 있는 컨트롤러 생성
  final controller = StreamController<List<String>>();

  // 초기 상태 전송: 현재 Box에 저장된 채팅 메시지 전체를 스트림에 한번 전달
  controller.add(chatBox.values.toList());

  // 이후 변경 감지 등록
  // Box가 listenable하므로 값이 변경될 때마다 알림을 받을 수 있음
  chatBox.listenable().addListener(() {
    // Box 값이 변경되면 다시 최신 메시지 리스트를 스트림으로 전달
    controller.add(chatBox.values.toList());
  });

  // StreamBuilder 등이 구독할 수 있도록 Stream 반환
  return controller.stream;
}

lib/widgets/chat_bubble.dart

import 'package:flutter/material.dart'; // 기본 Flutter UI 위젯 패키지
import 'package:flutter_markdown/flutter_markdown.dart'; // 마크다운 텍스트 렌더링을 위한 패키지

/// 채팅 말풍선을 나타내는 StatelessWidget
/// 메시지가 'You:'로 시작하면 사용자 메시지, 'Gemini:'로 시작하면 봇 응답으로 판단
class ChatBubble extends StatelessWidget {
  final String message; // 'You: 안녕' 또는 'Gemini: 안녕하세요' 형태의 문자열

  const ChatBubble({
    super.key,
    required this.message,
  });

  @override
  Widget build(BuildContext context) {
    // 메시지가 "You:"로 시작하는지 여부 확인 (사용자 메시지 판단용)
    final isUser = message.startsWith("You:");

    // "You:" 또는 "Gemini:" 접두사를 제거하여 실제 메시지 내용 추출
    final content = message.replaceFirst(RegExp(r'^(You|Gemini):\s*'), '');

    // 사용자 메시지면 우측 정렬, 아니면 좌측 정렬
    final alignment = isUser ? Alignment.centerRight : Alignment.centerLeft;

    // 사용자 메시지면 파란색 계열, 봇 응답이면 회색 계열 배경
    final bgColor = isUser ? Colors.blue[100] : Colors.grey[300];

    return Align(
      alignment: alignment, // 말풍선 정렬
      child: Container(
        margin: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 12.0), // 바깥 여백
        padding: const EdgeInsets.all(12.0), // 안쪽 여백
        constraints: const BoxConstraints(maxWidth: 280), // 최대 너비 제한
        decoration: BoxDecoration(
          color: bgColor, // 배경색
          borderRadius: BorderRadius.only(
            // 둥근 테두리 설정 (말풍선 꼬리 느낌 표현)
            topLeft: const Radius.circular(12),
            topRight: const Radius.circular(12),
            bottomLeft: isUser ? const Radius.circular(12) : Radius.zero,
            bottomRight: isUser ? Radius.zero : const Radius.circular(12),
          ),
        ),
        // 마크다운 문법을 렌더링하는 위젯
        child: MarkdownBody(
          data: content, // 실제 출력할 메시지 내용
          styleSheet: MarkdownStyleSheet.fromTheme(Theme.of(context)).copyWith(
            p: const TextStyle(fontSize: 16), // 일반 텍스트 스타일 크기 설정
          ),
        ),
      ),
    );
  }
}

lib/widgets/chat_input_area.dart

import 'package:flutter/material.dart'; // Flutter의 UI 위젯을 위한 핵심 패키지

/// 채팅 입력 영역 위젯
/// - 텍스트 입력 필드와 전송 버튼으로 구성됨
/// - 사용자의 입력을 controller를 통해 관리
/// - 메시지 전송은 onSend 콜백을 통해 처리
class ChatInputArea extends StatelessWidget {
  final TextEditingController controller; // 텍스트 입력 필드의 상태를 관리하는 컨트롤러
  final VoidCallback onSend; // 전송 버튼 클릭 또는 입력 완료 시 실행될 콜백 함수

  const ChatInputArea({
    super.key,
    required this.controller,
    required this.onSend,
  });

  @override
  Widget build(BuildContext context) {
    return Padding(
      // 위젯 외부 여백 설정 (수평 8, 수직 6)
      padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 6.0),
      child: Row(
        children: [
          // 입력창은 가능한 공간을 모두 차지하도록 확장
          Expanded(
            child: TextField(
              controller: controller, // 입력된 텍스트를 제어하는 컨트롤러
              decoration: const InputDecoration(
                hintText: "Type a message...", // 입력창 안에 표시될 힌트 텍스트
              ),
              onSubmitted: (_) => onSend(), // 엔터를 눌렀을 때 메시지 전송
            ),
          ),
          // 전송 버튼 (paper plane 아이콘)
          IconButton(
            icon: const Icon(Icons.send),
            onPressed: onSend, // 클릭 시 메시지 전송 콜백 실행
          ),
        ],
      ),
    );
  }
}

lib/widgets/chat_message_list.dart

import 'package:flutter/material.dart'; // 기본 위젯 라이브러리
import 'package:hive/hive.dart'; // Hive DB를 사용하기 위한 패키지
import 'package:andrew_chat_gpt/services/chat_stream.dart'; // 채팅 스트림 함수
import 'chat_bubble.dart'; // 각 메시지를 표현하는 말풍선 위젯

/// 실시간 채팅 메시지 목록을 보여주는 위젯
/// - Hive Box로부터 실시간 메시지를 감지하여 표시
/// - 메시지 업데이트 시 자동 스크롤 처리 지원
class ChatMessageList extends StatelessWidget {
  final Box<String> chatBox; // 채팅 메시지를 저장한 Hive 박스
  final ScrollController scrollController; // 자동 스크롤 처리를 위한 컨트롤러
  final VoidCallback onMessagesUpdated; // 새 메시지 등장 시 실행할 콜백 (예: 스크롤)

  const ChatMessageList({
    super.key,
    required this.chatBox,
    required this.scrollController,
    required this.onMessagesUpdated,
  });

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<List<String>>(
      stream: chatStream(chatBox), // Hive Box의 변경을 감지하는 스트림
      builder: (context, snapshot) {
        // snapshot에 데이터가 있으면 채팅 목록으로 가져오고, 없으면 빈 리스트
        final chats = snapshot.data ?? [];

        // 새 데이터가 들어오면 지정된 콜백 실행 (ex. 스크롤 아래로)
        if (snapshot.hasData) onMessagesUpdated();

        // 채팅 메시지 리스트 출력
        return ListView.builder(
          controller: scrollController, // 외부에서 전달받은 스크롤 컨트롤러로 스크롤 위치 조작
          itemCount: chats.length, // 채팅 수 만큼 아이템 생성
          itemBuilder: (_, index) => ChatBubble(message: chats[index]), // 각 메시지는 ChatBubble 위젯으로 표시
        );
      },
    );
  }
}

lib/screen/chat_screen.dart

import 'package:flutter/material.dart'; // 기본 Flutter UI 패키지
import 'package:flutter_dotenv/flutter_dotenv.dart'; // .env 환경변수 사용
import 'package:google_generative_ai/google_generative_ai.dart'; // Gemini API 사용
import 'package:hive/hive.dart'; // Hive DB 사용

import '../widgets/chat_input_area.dart'; // 입력창 위젯
import '../widgets/chat_message_list.dart'; // 채팅 목록 위젯

/// 메인 채팅 화면 - Gemini API와 연동되어 대화를 처리하는 StatefulWidget
class ChatScreen extends StatefulWidget {
  const ChatScreen({super.key});

  @override
  State<ChatScreen> createState() => _ChatScreenState();
}

class _ChatScreenState extends State<ChatScreen> {
  // 텍스트 입력 필드용 컨트롤러
  late final TextEditingController _controller;

  // 자동 스크롤을 위한 컨트롤러
  late final ScrollController _scrollController;

  // Hive 저장소에서 불러온 채팅 박스
  late final Box<String> _chatBox;

  // Gemini 모델 객체
  late final GenerativeModel _model;

  // Gemini와의 세션 (대화 컨텍스트 포함)
  late ChatSession _chatSession;

  @override
  void initState() {
    super.initState();
    _controller = TextEditingController();
    _scrollController = ScrollController();
    _chatBox = Hive.box<String>('chat_history');
    _initializeChatSession(); // 모델 초기화 및 세션 설정
  }

  /// Gemini 모델 생성 및 대화 세션 초기화
  void _initializeChatSession() {
    _model = GenerativeModel(
      model: 'gemini-2.0-flash',
      apiKey: dotenv.env['GEMINI_API_KEY']!, // .env에서 API 키 로드
    );
    _chatSession = _model.startChat(); // 새로운 대화 세션 시작
    _restoreSessionFromDB(); // DB에서 이전 대화 내역 복원
  }

  /// Hive에 저장된 메시지 내역을 기반으로 Gemini 세션에 재전송
  void _restoreSessionFromDB() {
    final messages = _chatBox.values.toList();
    for (final msg in messages) {
      if (msg.startsWith("You:")) {
        final text = msg.replaceFirst("You:", "").trim();
        _chatSession.sendMessage(Content.text(text)); // 사용자 메시지 복원
      } else if (msg.startsWith("Gemini:")) {
        final text = msg.replaceFirst("Gemini:", "").trim();
        _chatSession.sendMessageStream(Content.text(text)); // Gemini 응답 복원
      }
    }
  }

  /// 입력한 메시지를 Gemini API에 전송하고, 응답을 DB에 저장
  Future<void> _sendMessage() async {
    final input = _controller.text.trim();
    if (input.isEmpty) return;

    final userMessage = 'You: $input';
    _chatBox.add(userMessage); // 입력 메시지 DB 저장
    _controller.clear(); // 입력 필드 초기화

    try {
      final response = await _chatSession.sendMessage(Content.text(input));
      final reply = 'Gemini: ${response.text ?? "No response."}';
      _chatBox.add(reply); // Gemini 응답 저장
    } catch (e) {
      final error = 'Gemini: Error - $e';
      _chatBox.add(error); // 에러 메시지 저장
    }
  }

  /// 새 메시지가 추가되었을 때 자동 스크롤 처리
  void _scrollToBottom() {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (_scrollController.hasClients) {
        _scrollController.animateTo(
          _scrollController.position.maxScrollExtent,
          duration: const Duration(milliseconds: 300),
          curve: Curves.easeOut,
        );
      }
    });
  }

  /// 새 채팅 시작: 기존 메시지 삭제 및 새 세션 시작
  Future<void> _startNewChat() async {
    await _chatBox.clear(); // DB 초기화
    setState(() {
      _chatSession = _model.startChat(); // 세션 초기화
    });
  }

  @override
  void dispose() {
    _controller.dispose();
    _scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Gemini Chat")), // 앱 상단 제목 바
      body: Stack(
        children: [
          Column(
            children: [
              // 채팅 메시지 목록
              Expanded(
                child: ChatMessageList(
                  chatBox: _chatBox,
                  scrollController: _scrollController,
                  onMessagesUpdated: _scrollToBottom,
                ),
              ),
              const Divider(height: 1), // 구분선
              // 입력창 영역
              ChatInputArea(
                controller: _controller,
                onSend: _sendMessage,
              ),
            ],
          ),
          // 우측 하단 새 채팅 버튼 (FAB)
          Positioned(
            bottom: 100,
            right: 16,
            child: FloatingActionButton.small(
              onPressed: _startNewChat,
              tooltip: '새 채팅',
              child: const Icon(Icons.refresh),
            ),
          ),
        ],
      ),
    );
  }
}

lib/main.dart

import 'package:andrew_chat_gpt/screen/chat_screen.dart'; // 메인 채팅 화면 위젯
import 'package:flutter/material.dart'; // Flutter UI 위젯의 핵심 패키지
import 'package:flutter_dotenv/flutter_dotenv.dart'; // .env 환경변수 로드용 패키지
import 'package:hive_flutter/hive_flutter.dart'; // Hive와 Flutter 연동을 위한 패키지

/// 앱 실행 진입점
void main() async {
  // Flutter에서 비동기 초기화를 위해 필요한 준비 작업 (runApp 전에)
  WidgetsFlutterBinding.ensureInitialized();

  // .env 파일 로딩 (.env 파일에서 API KEY 등 비밀 정보 읽기)
  await dotenv.load();

  // Hive DB 초기화 (Flutter 앱 환경에 맞게 설정)
  await Hive.initFlutter();

  // 채팅 기록을 저장할 박스 오픈 (문자열 형태로 저장)
  await Hive.openBox<String>('chat_history');

  // 앱 실행
  runApp(const GeminiApp());
}

/// 전체 애플리케이션을 감싸는 루트 위젯
class GeminiApp extends StatelessWidget {
  const GeminiApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Gemini Chat', // 앱 타이틀 (시스템 상에서 보일 수 있음)
      theme: ThemeData(
        primarySwatch: Colors.indigo, // 앱 전체 테마 색상 설정
      ),
      home: const ChatScreen(), // 첫 화면으로 ChatScreen 지정
      debugShowCheckedModeBanner: false, // 우측 상단 디버그 배너 숨김
    );
  }
}

Gemini 채팅 화면

728x90

'Flutter for Beginners' 카테고리의 다른 글

Flutter 게시판 with Hive  (0) 2025.04.23
Flutter 포토 스티커  (0) 2025.04.21
Flutter Google Map  (0) 2025.04.18
Flutter 영상통화  (0) 2025.04.15
Flutter 비디오 플레이어  (0) 2025.04.10