Flutter 프로젝트 뼈대 세우기 🎯 이번 단계에서 배울 것
flutter create가 만들어 주는 기본 파일과 폴더 구조 파악
.gitignore, analysis_options.yaml, pubspec.yaml 등 핵심 설정 파일 역할 이해
Android, iOS, Web, Desktop(Windows·macOS·Linux) 플랫폼별 초기 코드 살펴보기
기본 위젯 테스트 템플릿(test/widget_test.dart)이 어떤 구조로 생성되는지 확인
📂 파일 구조 1 2 3 4 5 6 7 새로 만들어지는 파일 - .gitignore / .metadata - README.md / analysis_options.yaml - pubspec.yaml / pubspec.lock - android/**, ios/**, linux/**, macos/**, web/**, windows/** 플랫폼 코드 전체 - lib/main.dart (기본 앱 진입점) - test/widget_test.dart (위젯 테스트 템플릿)
📝 1단계: Flutter 프로젝트 생성하기 실행한 명령 (터미널):
🔍 코드 상세 설명 1. 버전 관리 제외 목록(.gitignore)
1 2 3 4 5 6 7 # Flutter/Dart/Pub related **/doc/api/ **/ios/Flutter/.last_build_id .dart_tool/ .flutter-plugins .pub-cache/ .build/
자동 생성·빌드 산출물은 버전 관리에서 제외해 저장소가 가벼워집니다.
플랫폼별 빌드 아티팩트를 올리지 않아 협업 시 충돌을 줄일 수 있습니다.
2. 분석 규칙(analysis_options.yaml)
1 2 3 4 5 include: package:flutter_lints/flutter.yaml linter: rules: avoid_print: false
Flutter 공식 린트 세트를 포함하여 코드 일관성을 유지합니다.
기본 규칙에서 print 허용으로 초반 디버깅을 쉽게 합니다.
3. 프로젝트 메타 정보(pubspec.yaml)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 name: toonflix publish_to: 'none' description: A new Flutter project. environment: sdk: '>=2.18.2 <3.0.0' dependencies: flutter: sdk: flutter cupertino_icons: ^1.0.2 dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^2.0.0
패키지 이름과 설명이 프로젝트를 대표합니다.
SDK 범위와 기본 의존성(flutter, cupertino_icons)이 명시되었습니다.
테스트와 린트 패키지는 개발 단계에서만 사용됩니다.
4. 플랫폼별 진입 파일 예시
1 2 3 class MainActivity : FlutterActivity () {}
1 2 3 4 5 6 7 8 9 10 11 @UIApplicationMain class AppDelegate : FlutterAppDelegate { override func application ( _ application : UIApplication , didFinishLaunchingWithOptions launchOptions : [UIApplication .LaunchOptionsKey : Any ]? ) -> Bool { GeneratedPluginRegistrant .register(with: self ) return super .application(application, didFinishLaunchingWithOptions: launchOptions) } }
Android는 FlutterActivity를 상속해 Flutter 엔진을 구동합니다.
iOS는 FlutterAppDelegate를 확장하여 플러그인 등록 코드를 포함합니다.
비교 예시:
1 2 3 4 5 # Flutter/Dart/Pub related # ← 새 항목 추가 전 (doc/api 등의 빌드 산출물이 추적됨) # Flutter/Dart/Pub related # ← 새 항목 추가 후 .build/ 등이 무시되어 깃 기록이 깔끔해짐
시각화:
1 2 3 4 5 6 7 8 9 10 ┌─ 프로젝트 루트 │ ├─ lib/ → Dart 소스 │ ├─ android/ → Kotlin & Gradle │ ├─ ios/ → Swift & Xcode 설정 │ ├─ macos/ → macOS Runner │ ├─ linux/ → GTK Runner │ ├─ windows/ → Win32 Runner │ ├─ web/ → 웹 정적 자산 │ └─ test/ → 위젯 테스트 기본 템플릿 └──────────────────────────────────────────
🎨 화면 미리보기 1 2 3 4 5 6 터미널 ┌──────────────────────────────────────┐ │ flutter create toonflix │ │ → Running "flutter pub get" │ │ → "toonflix" created successfully. │ └──────────────────────────────────────┘
📊 동작 흐름 1 2 3 4 5 1. flutter create toonflix 실행 2. Flutter SDK가 템플릿 파일 복사 3. pubspec.yaml 기반으로 의존성 다운로드(pub get) 4. 플랫폼별 Runner 프로젝트 생성 5. 기본 테스트 및 분석 설정 파일 생성
✅ 체크리스트
💡 연습 과제
프로젝트 설명 수정: pubspec.yaml의 description을 본인 프로젝트 목적에 맞게 수정해보세요.
린트 규칙 추가: analysis_options.yaml에 prefer_const_constructors와 같은 규칙을 더해보고 경고 변화를 확인하세요.
플랫폼 빌드 시도: 안드로이드 스튜디오나 Xcode로 Runner 프로젝트를 열어 빌드 과정을 체험해보세요.
Hello World 화면 구성 🎯 이번 단계에서 배울 것
Flutter 앱의 진입점(main()과 runApp) 이해
StatelessWidget, MaterialApp, Scaffold의 역할 파악
AppBar, Center, Text 위젯으로 기본 UI 구성하기
자동 생성된 위젯 테스트 템플릿이 현재 코드와 어떻게 어긋나는지 확인
📂 파일 구조 1 2 3 4 5 수정되는 파일 - lib/main.dart (커스텀 Hello World UI 구성) 기본 유지 파일 - test/widget_test.dart (Counter 예제 테스트 템플릿)
📝 1단계: Hello World UI 빌드하기 전체 코드 (lib/main.dart):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import 'package:flutter/material.dart' ;void main() { runApp(App()); } class App extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: Text('Hello flutter!' ), ), body: Center( child: Text('Hello world!' ), ), ), ); } }
🔍 코드 상세 설명 1. main() 함수와 runApp
1 2 3 void main() { runApp(App()); }
Dart 애플리케이션의 진입점으로, 앱 실행 시 가장 먼저 호출됩니다.
runApp은 전달한 위젯(App)을 위젯 트리의 루트로 등록하고 렌더링을 시작합니다.
2. StatelessWidget으로 화면 정의
1 2 3 4 5 6 class App extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp(...); } }
상태 변화가 필요 없는 정적인 화면 데이터에 적합합니다.
build 메서드는 UI 트리를 반환하며, Flutter가 이 반환값을 사용해 화면을 그립니다.
3. MaterialApp과 Scaffold 구조
1 2 3 4 5 6 return MaterialApp( home: Scaffold( appBar: AppBar(title: Text('Hello flutter!' )), body: Center(child: Text('Hello world!' )), ), );
MaterialApp은 Material Design 스타일의 전역 설정(네비게이션, 테마 등)을 제공합니다.
Scaffold는 상단 앱바, 본문 영역 등 기본 레이아웃 뼈대를 제공합니다.
4. UI 구성 위젯
1 2 3 4 5 6 appBar: AppBar( title: Text('Hello flutter!' ), ), body: Center( child: Text('Hello world!' ), ),
AppBar는 화면 제목 영역을, Center는 자식 위젯을 중앙에 배치합니다.
Text 위젯으로 간단한 문자열을 출력합니다.
비교 예시:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class MyApp extends StatelessWidget { Widget build(BuildContext context) { return MaterialApp( home: MyHomePage(title: 'Flutter Demo Home Page' ), ); } } class App extends StatelessWidget { Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: Text('Hello flutter!' )), body: Center(child: Text('Hello world!' )), ), ); } }
시각화:
1 2 3 4 5 6 7 ┌─────────────────────────────┐ │ Hello flutter! [ ] │ AppBar ├─────────────────────────────┤ │ │ │ Hello world! │ Center → Text │ │ └─────────────────────────────┘
🎨 화면 미리보기 1 2 3 4 5 6 위젯 트리 App └── MaterialApp └── Scaffold ├── AppBar → Text('Hello flutter!') └── Center → Text('Hello world!')
📊 동작 흐름 1 2 3 4 5 1. 사용자가 앱을 실행 2. Flutter 엔진이 main()을 호출 3. runApp(App())으로 루트 위젯 등록 4. App.build() → MaterialApp → Scaffold → UI 구성 5. 화면에 Hello World UI 렌더링
✅ 체크리스트
💡 연습 과제
테마 적용: MaterialApp에 theme: ThemeData(primarySwatch: Colors.blue)를 추가해 색상을 바꿔보세요.
텍스트 스타일 변경: Text('Hello world!')에 style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)를 적용해보세요.
테스트 갱신: test/widget_test.dart에서 MyApp 대신 App을 pump하도록 수정해 보고 테스트를 실행해보세요.
자동 생성 테스트 코드 이해하기 🎯 이번 단계에서 배울 것
Flutter가 기본으로 제공하는 위젯 테스트 구조 파악
현재 UI와 테스트 코드의 불일치 원인 분석
WidgetTester를 활용해 상호작용을 검증하는 흐름 이해
📂 파일 구조 1 2 검토할 파일 - test/widget_test.dart
📝 1단계: 기본 테스트 읽어보기 전체 코드 (test/widget_test.dart):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import 'package:flutter/material.dart' ;import 'package:flutter_test/flutter_test.dart' ;import 'package:toonflix/main.dart' ;void main() { testWidgets('Counter increments smoke test' , (WidgetTester tester) async { await tester.pumpWidget(const MyApp()); expect(find.text('0' ), findsOneWidget); expect(find.text('1' ), findsNothing); await tester.tap(find.byIcon(Icons.add)); await tester.pump(); expect(find.text('0' ), findsNothing); expect(find.text('1' ), findsOneWidget); }); }
🔍 코드 상세 설명 1. testWidgets 흐름
pumpWidget으로 테스트 대상 위젯을 렌더링하고 프레임을 강제로 갱신합니다.
find.text, find.byIcon으로 위젯을 검색하고 expect로 검증합니다.
2. 현재 실패하는 이유
커밋된 실제 코드에는 MyApp이 존재하지 않고 App 클래스만 있습니다.
Counter 버튼 UI도 삭제되었으므로 '0', '1', Icons.add를 찾을 수 없어 테스트가 실패합니다.
비교 예시:
1 2 await tester.pumpWidget(const MyApp()); await tester.pumpWidget(App());
시각화:
1 2 3 4 5 6 7 8 9 10 테스트 기대 UI ┌─ AppBar: "Flutter Demo" ─────────────┐ │ 0 │ │ [+] button │ └──────────────────────────────────────┘ 실제 UI (현재 프로젝트) ┌─ AppBar: "Hello flutter!" ───────────┐ │ Hello world! │ └──────────────────────────────────────┘
🎨 화면 미리보기 1 2 3 테스트 실행 예상 결과 - 기본 코드 유지: green (모든 검증 통과) - 현재 코드 상태: red (위젯 탐색 실패로 AssertionError)
📊 동작 흐름 1 2 3 1. WidgetTester가 MyApp을 렌더링하려 시도 2. MyApp 클래스를 찾지 못해 런타임 오류 발생 또는 3. (MyApp을 만든 후라도) '+' 아이콘과 Counter 텍스트 부재로 expect 실패
✅ 체크리스트
💡 연습 과제
테스트 업데이트: pumpWidget(App())으로 교체하고, “Hello world!” 텍스트가 존재하는지 검사하도록 테스트를 바꿔보세요.
추가 검증 작성: AppBar 제목이 “Hello flutter!”인지 확인하는 단언문을 추가해보세요.
위젯 찾기 연습: find.byType(AppBar) 등을 사용하여 원하는 위젯을 찾는 방법을 연습해보세요.
📚 전체 흐름 정리
flutter create 명령으로 모든 플랫폼 폴더와 설정 파일이 생성되었습니다.
lib/main.dart를 수정하여 간단한 Hello World UI를 구성했습니다.
자동 생성된 테스트는 아직 Counter 예제를 기준으로 하므로 현 상태에서는 실패합니다.
✅ 최종 점검 리스트
출처 : https://nomadcoders.co/flutter-for-beginners