Skip to main content

Flutter 명령어 치트시트와 추천 패키지

Views 56약 11분생성형 AI 활용

터미널은 무서운 도구가 아니라 가장 빠른 길이다

Flutter를 처음 배울 때는 대부분 IDE의 실행 버튼을 누른다. Android Studio나 VS Code의 초록색 재생 버튼은 친절하고 편하다. 하지만 앱을 조금만 더 진지하게 만들기 시작하면 결국 터미널을 열게 된다. 패키지를 추가하고, 테스트를 돌리고, 빌드 파일을 만들고, 갑자기 꼬인 캐시를 청소해야 하기 때문이다.

중요한 사실이 하나 있다. IDE가 마법을 부리는 것이 아니다. IDE도 내부적으로는 flutter run, flutter pub get, flutter test 같은 명령어를 호출한다. Flutter 공식 문서에서도 flutter 명령줄 도구는 개발자나 IDE가 Flutter와 상호작용하는 공식 도구이며, Dart 관련 작업은 필요에 따라 dart 명령줄 도구를 사용할 수 있다고 설명한다.1

이 장은 외우기 위한 장이 아니다. 앱을 만들다가 "이럴 때 어떤 명령어였지?" 하고 막혔을 때 빠르게 펼쳐 보는 작업대다. 마치 요리할 때 냉장고 문에 붙여 둔 레시피처럼, 개발 중 자주 쓰는 명령어와 실전 패키지를 한눈에 정리해 보자.

Flutter 명령어 치트시트와 추천 패키지

Flutter CLI 기본 명령어

Flutter 명령어는 크게 네 가지 순간에 자주 등장한다. 프로젝트를 처음 만들 때, 앱을 실행할 때, 문제가 생겼을 때, 출시용 빌드를 만들 때다. 아래 표는 가장 자주 쓰는 명령어를 목적과 실행 시점 중심으로 정리한 것이다.

명령어목적언제 쓰나
flutter --help사용 가능한 Flutter 명령어 목록 확인명령어가 기억나지 않을 때
flutter --versionFlutter SDK 버전 확인버그 리포트, 팀 버전 확인, 문서와 버전 비교 시
flutter doctor개발 환경 진단설치 직후, 에뮬레이터나 빌드가 안 될 때
flutter devices연결된 기기 목록 확인실행할 기기를 고르기 전
flutter create my_app새 프로젝트 생성앱 또는 패키지를 처음 만들 때
flutter run앱 실행개발 중 기기나 에뮬레이터에서 앱을 띄울 때
flutter analyze정적 분석 실행커밋 전, CI에서 코드 품질 확인 시
flutter test테스트 실행기능 수정 후, 배포 전
flutter clean빌드 캐시와 임시 파일 삭제이상한 빌드 오류, 의존성 꼬임, 플랫폼 빌드 실패 시

가장 먼저 익숙해져야 할 명령어는 flutter doctor다. 이름 그대로 의사처럼 현재 개발 환경을 진단한다. Android toolchain, Xcode, Chrome, 연결 기기, IDE 플러그인 상태를 검사하고 부족한 부분을 알려 준다. 설치 직후에는 무조건 한 번 실행하고, 알 수 없는 빌드 오류가 날 때도 습관처럼 실행해 보자.

flutter doctor

더 자세한 진단이 필요하면 -v 옵션을 붙인다.

flutter doctor -v

새 프로젝트를 만들 때는 flutter create를 사용한다.

flutter create my_notes_app
cd my_notes_app
flutter run

앱의 패키지 이름, 즉 Android의 applicationId와 iOS의 bundle identifier에 영향을 주는 조직 도메인을 지정하고 싶다면 --org 옵션을 함께 쓴다.

flutter create --org com.example my_notes_app

실행 가능한 기기가 여러 개라면 먼저 목록을 확인한다.

flutter devices

그다음 특정 기기를 지정해 실행할 수 있다.

flutter run -d chrome
flutter run -d emulator-5554

실제 개발에서는 아래 흐름을 가장 자주 반복한다.

flutter create my_app
cd my_app
flutter pub get
flutter analyze
flutter test
flutter run

이 흐름은 단순하지만 강력하다. 프로젝트를 만들고, 의존성을 받고, 코드를 검사하고, 테스트하고, 실행한다. 작은 개인 프로젝트든 팀 프로젝트든 기본 리듬은 거의 같다.

Debug, Profile, Release 실행 감각 잡기

Flutter 앱은 실행 모드에 따라 성격이 달라진다. 개발 중에는 대부분 Debug 모드를 사용한다. Hot Reload가 가능하고 디버깅 정보가 풍부한 대신, 성능은 출시 앱과 다를 수 있다.

Profile 모드는 성능 측정을 위한 모드다. 디버그 기능은 줄이고 실제 실행 성능에 가까운 상태에서 프레임 드롭, 렌더링 비용, 메모리 사용량 등을 확인할 수 있다.

Release 모드는 사용자가 스토어에서 내려받는 앱에 가까운 모드다. 디버깅 편의 기능은 빠지고, 최적화가 적용된다.

실행 방식명령어용도
Debug 실행flutter run일반 개발, Hot Reload
Profile 실행flutter run --profile성능 측정, DevTools 분석
Release 실행flutter run --release출시 환경에 가까운 동작 확인

성능을 이야기할 때 "제 폰에서는 좀 느린데요?"라는 말만으로는 부족하다. Debug 모드에서 느린 것인지, Release 모드에서도 느린 것인지 먼저 확인해야 한다. 특히 애니메이션, 긴 리스트, 이미지가 많은 화면은 Profile 모드에서 DevTools와 함께 보는 습관을 들이면 좋다.

pub 명령어로 의존성 관리하기

Flutter 프로젝트는 혼자 모든 기능을 직접 구현하지 않는다. 라우팅은 go_router, 상태관리는 flutter_riverpod, API 통신은 http나 dio, Firebase 연동은 Firebase 패키지를 사용한다. 이런 외부 패키지를 관리하는 도구가 pub이다.

Dart 공식 문서는 pub이 Dart의 패키지 관리 도구이며, Flutter 앱이나 Flutter 전용 코드가 있는 디렉터리에서는 dart pub 대신 flutter pub을 사용하라고 안내한다.2 쉽게 말해 일반 Dart 패키지에서는 dart pub, Flutter 앱에서는 flutter pub을 기본으로 생각하면 된다.

명령어목적언제 쓰나
flutter pub getpubspec.yaml에 적힌 패키지 내려받기프로젝트를 처음 받았을 때, 의존성 수정 후
flutter pub add 패키지명패키지 추가새 라이브러리를 설치할 때
flutter pub add dev:패키지명개발용 패키지 추가코드 생성기, 린트, 테스트 도구 추가 시
flutter pub remove 패키지명패키지 제거더 이상 쓰지 않는 라이브러리를 정리할 때
flutter pub outdated오래된 패키지 확인업데이트 가능 여부 점검 시
flutter pub upgrade가능한 범위에서 패키지 업그레이드정기 업데이트, 보안 업데이트 후
flutter pub deps의존성 트리 확인충돌 원인을 찾을 때

패키지를 추가할 때 pubspec.yaml을 직접 열어도 되지만, 보통은 명령어가 더 안전하고 빠르다.

flutter pub add go_router
flutter pub add flutter_riverpod
flutter pub add http

개발할 때만 필요한 패키지는 dev_dependencies에 넣어야 한다. 예를 들어 코드 생성에 쓰는 build_runner나 테스트 목(mock) 라이브러리는 앱 실행 파일에 직접 포함될 필요가 없다.

flutter pub add dev:build_runner
flutter pub add dev:json_serializable
flutter pub add dev:flutter_lints

패키지를 삭제할 때는 pubspec.yaml에서 줄만 지우지 말고 명령어를 쓰면 실수를 줄일 수 있다.

flutter pub remove http

오래된 패키지를 확인하려면 다음 명령어를 사용한다.

flutter pub outdated

업데이트를 적용하려면 다음 명령어를 실행한다.

flutter pub upgrade

다만 upgrade는 만능 버튼이 아니다. 앱이 잘 돌아가던 상태에서 여러 패키지를 한꺼번에 올리면 예상하지 못한 깨짐이 생길 수 있다. 실전에서는 업데이트 전후로 flutter test, flutter analyze를 함께 실행하는 것이 좋다.

flutter pub outdated
flutter pub upgrade
flutter analyze
flutter test

flutter와 dart 명령어 구분하기

초보자가 자주 헷갈리는 부분이 있다. 어떤 때는 flutter를 쓰고, 어떤 때는 dart를 쓴다. 기준은 생각보다 단순하다.

Flutter 앱 프로젝트 안에서 앱 실행, 빌드, 테스트, 패키지 관리를 할 때는 flutter를 쓴다. 반면 순수 Dart CLI 도구를 실행하거나 코드 생성기를 돌릴 때는 dart run을 자주 쓴다.

상황추천 명령어예시
Flutter 앱 의존성 설치flutter pub getflutter pub get
Flutter 앱 테스트flutter testflutter test test/note_test.dart
Flutter 앱 실행flutter runflutter run -d chrome
코드 생성기 실행dart rundart run build_runner build
순수 Dart 패키지 의존성 설치dart pub getdart pub get
전역 CLI 도구 활성화dart pub global activatedart pub global activate fvm

예를 들어 freezed와 json_serializable을 사용하는 프로젝트에서는 코드를 생성해야 한다. 이때는 보통 다음 명령어를 사용한다.

dart run build_runner build --delete-conflicting-outputs

파일이 바뀔 때마다 자동으로 다시 생성하고 싶다면 watch를 쓴다.

dart run build_runner watch --delete-conflicting-outputs

이 명령어를 하루 종일 켜 두면 모델 파일을 수정할 때마다 생성 파일이 자동으로 갱신된다. 마치 주방에서 계속 돌아가는 커피머신 같다. 필요할 때마다 새 커피를 내려 준다.

분석, 포맷, 테스트 명령어

출시 가능한 앱은 "내 기기에서만 대충 돌아가는 앱"이 아니다. 코드 스타일이 일정하고, 명백한 오류가 없고, 핵심 로직이 테스트로 보호되어야 한다. 이때 자주 쓰는 명령어가 분석, 포맷, 테스트 명령어다.

flutter analyze

flutter analyze는 Dart 분석기를 실행해 잠재적인 오류, 타입 문제, 사용하지 않는 import, 권장하지 않는 코드 패턴을 찾아 준다. 팀 프로젝트라면 Pull Request를 올리기 전에 반드시 실행하는 습관을 들이자.

코드 포맷은 Dart 도구를 사용한다.

dart format lib test

현재 디렉터리 전체를 포맷하고 싶다면 다음처럼 실행한다.

dart format .

테스트는 범위에 따라 다르게 실행할 수 있다.

flutter test
flutter test test/unit/note_repository_test.dart
flutter test test/widget/note_list_screen_test.dart

커버리지 파일을 만들고 싶다면 --coverage 옵션을 붙인다.

flutter test --coverage

테스트가 많아질수록 이 명령어들은 귀찮은 절차가 아니라 안전벨트가 된다. 기능을 하나 고쳤는데 로그인, 검색, 오프라인 캐시가 동시에 깨지는 일을 막아 주기 때문이다.

clean은 최후의 망치처럼 사용하기

Flutter 개발을 하다 보면 이상한 순간이 온다. 분명 코드는 맞는데 빌드가 실패한다. 패키지를 지웠는데 계속 남아 있는 것처럼 보인다. Android에서는 안 되고 iOS에서는 된다. 어제는 됐는데 오늘은 안 된다.

이때 많은 개발자가 flutter clean을 떠올린다.

flutter clean
flutter pub get

flutter clean은 build/와 .dart_tool/ 같은 빌드 관련 산출물을 삭제한다. 그래서 캐시가 꼬였을 때 효과가 있다. 하지만 모든 문제를 해결하는 마법 주문은 아니다. 실행 후에는 패키지를 다시 받아야 하므로 보통 flutter pub get과 함께 사용한다.

자주 사용하는 정리 루틴은 다음과 같다.

flutter clean
flutter pub get
flutter run

iOS에서 CocoaPods 문제가 함께 있다면 iOS 디렉터리에서 pods를 다시 설치해야 할 수도 있다.

cd ios
pod install
cd ..
flutter run

다만 습관적으로 매번 clean을 실행하면 개발 속도가 느려진다. 평소에는 pub get, analyze, test를 먼저 확인하고, 캐시나 빌드 산출물이 의심될 때 clean을 꺼내자. 망치는 필요할 때 강력하지만, 나사를 조일 때마다 망치를 들 필요는 없다.

플랫폼별 배포 빌드 명령어

이제 앱을 사용자에게 전달할 차례다. Flutter는 플랫폼별로 다른 산출물을 만든다. Android는 APK 또는 AAB, iOS는 IPA, Web은 정적 파일 묶음이 대표적이다.

플랫폼명령어산출물기본 위치
Android APKflutter build apk --release.apkbuild/app/outputs/flutter-apk/app-release.apk
Android App Bundleflutter build appbundle --release.aabbuild/app/outputs/bundle/release/app-release.aab
iOS 앱 빌드flutter build ios --releaseiOS 앱 번들build/ios/iphoneos/Runner.app
iOS IPAflutter build ipa --release.ipabuild/ios/ipa/*.ipa
Webflutter build web --releaseHTML/CSS/JS 정적 파일build/web

Android에 직접 설치해서 테스트할 때는 APK가 편하다.

flutter build apk --release

Google Play에 올릴 때는 일반적으로 AAB를 사용한다.

flutter build appbundle --release

iOS는 Xcode 설정, 인증서, 프로비저닝 프로파일이 함께 맞아야 한다. App Store Connect나 TestFlight 업로드를 생각한다면 IPA 빌드를 사용한다.

flutter build ipa --release

웹 배포 파일은 다음 명령어로 만든다.

flutter build web --release

빌드 결과물은 build/web에 생성된다. 이 폴더를 Firebase Hosting, GitHub Pages, Netlify, Vercel 같은 정적 호스팅에 올릴 수 있다.

Debug 빌드와 Release 빌드는 다르게 봐야 한다. Debug 빌드는 개발 편의를 위해 디버깅 정보와 Hot Reload 환경을 포함한다. Release 빌드는 최적화되어 크기와 성능이 실제 사용자 환경에 가깝다. "출시 전에 마지막으로 한 번만 확인하자"라는 순간에는 반드시 Release 빌드로 확인하자.

상황별 빠른 처방전

앱 개발 중에는 명령어를 문법별로 찾기보다 상황별로 찾는 일이 더 많다. 아래 표는 실제 작업 중 자주 만나는 장면을 기준으로 정리한 빠른 처방전이다.

상황실행할 명령어
새 Flutter 앱 만들기flutter create my_app
조직 도메인 포함해 앱 만들기flutter create --org com.mycompany my_app
개발 환경 확인flutter doctor -v
연결 기기 확인flutter devices
Chrome에서 실행flutter run -d chrome
Android 에뮬레이터에서 실행flutter run -d emulator-5554
패키지 설치flutter pub get
패키지 추가flutter pub add package_name
개발용 패키지 추가flutter pub add dev:package_name
패키지 제거flutter pub remove package_name
오래된 패키지 확인flutter pub outdated
패키지 업그레이드flutter pub upgrade
코드 분석flutter analyze
코드 포맷dart format .
전체 테스트flutter test
커버리지 포함 테스트flutter test --coverage
캐시 정리flutter clean && flutter pub get
Android APK 빌드flutter build apk --release
Android AAB 빌드flutter build appbundle --release
iOS IPA 빌드flutter build ipa --release
Web 빌드flutter build web --release

명령어를 많이 아는 것보다 중요한 것은 실행 시점을 아는 것이다. flutter doctor는 환경이 의심될 때, flutter analyze는 코드 품질이 의심될 때, flutter clean은 캐시가 의심될 때, flutter test는 기능이 깨졌는지 확인할 때 사용한다.

실전 앱의 기본 패키지 지도

Flutter 생태계는 넓다. pub.dev에는 수많은 패키지가 있고, 같은 문제를 해결하는 패키지도 여러 개다. 입문자에게 가장 어려운 선택은 "무엇을 써야 하는가"다. 여기서는 이 책에서 배운 실전 앱 구조를 기준으로 기본 패키지 지도를 정리한다.

분야추천 패키지주 용도
라우팅go_router선언적 라우팅, 인증 기반 리다이렉트, 중첩 라우팅
상태관리flutter_riverpod상태관리, 의존성 주입, 비동기 상태 처리
REST APIhttp가볍고 단순한 HTTP 통신
REST APIdio인터셉터, 취소 토큰, 파일 업로드 등 고급 HTTP 통신
불변 모델freezed불변 객체, union/sealed 스타일 모델링
JSON 직렬화json_serializablefromJson, toJson 코드 생성
간단 저장소shared_preferences테마, 온보딩 여부 같은 간단한 설정값 저장
보안 저장소flutter_secure_storage토큰, 민감 정보 저장
로컬 DBdriftSQLite 기반 구조화 데이터 저장
이미지 캐싱cached_network_image네트워크 이미지 캐싱과 로딩/에러 UI
Firebase 초기화firebase_coreFirebase 앱 초기화
Firebase 인증firebase_auth이메일, 소셜 로그인, 익명 로그인 등
Firebase DBcloud_firestore문서형 실시간 데이터베이스
Firebase 파일firebase_storage이미지, 첨부 파일 업로드
Firebase 알림firebase_messagingFCM 푸시 알림
오류 추적firebase_crashlytics실제 사용자 환경의 크래시 수집

패키지를 고를 때는 인기도만 보지 말고 세 가지를 함께 보자. 최근 업데이트가 있는지, 문서와 예제가 충분한지, 현재 앱의 복잡도에 맞는지다. 작은 앱에 너무 무거운 도구를 넣으면 개발이 느려지고, 큰 앱에 너무 단순한 도구만 쓰면 유지보수가 어려워진다.

라우팅: go_router

작은 앱에서는 Navigator.push만으로도 충분하다. 하지만 로그인 여부에 따라 첫 화면이 달라지고, 하단 탭마다 독립적인 탐색 스택이 있고, 웹에서 URL까지 맞춰야 한다면 이야기가 달라진다. 이때 go_router가 좋은 선택이 된다.

설치 명령어는 간단하다.

flutter pub add go_router

go_router는 화면 이동을 코드 여기저기 흩뿌리는 대신, 앱의 경로 구조를 한곳에서 선언하게 해 준다. 예를 들어 /login, /notes, /notes/:id, /settings처럼 앱의 지도를 먼저 그려 놓고, UI에서는 그 경로로 이동한다.

인증 기반 앱에서는 리다이렉트가 특히 중요하다. 사용자가 로그인하지 않았는데 /notes로 들어가려 하면 /login으로 보내고, 이미 로그인한 사용자가 /login에 접근하면 /notes로 보내는 식이다. 이 구조를 잘 잡아 두면 "뒤로 가기 했더니 로그인 화면이 다시 나와요" 같은 문제를 줄일 수 있다.

상태관리와 의존성 주입: flutter_riverpod

flutter_riverpod은 상태관리뿐 아니라 의존성 주입에도 많이 사용된다. 의존성 주입은 쉽게 말해 "필요한 객체를 직접 만들지 않고 바깥에서 넣어 주는 방식"이다. 예를 들어 화면이 ApiClient()를 직접 생성하는 대신, provider를 통해 NoteRepository를 받아 쓰게 만들면 테스트와 교체가 쉬워진다.

설치 명령어는 다음과 같다.

flutter pub add flutter_riverpod

Riverpod 공식 문서에서는 Flutter 앱에 flutter_riverpod을 추가하고, 앱 루트를 ProviderScope로 감싼 뒤 provider를 읽는 기본 흐름을 안내한다.3 pub.dev의 flutter_riverpod 설명에서도 Riverpod은 비동기 코드의 로딩과 오류 상태 처리를 돕고, 로직을 UI에서 분리하며, 테스트 가능하고 확장 가능한 코드를 만들 수 있게 한다고 소개한다.4

가장 기본적인 구조는 다음과 같다.

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

final counterProvider = StateProvider<int>((ref) => 0);

void main() {
  runApp(
    const ProviderScope(
      child: MyApp(),
    ),
  );
}

class MyApp extends ConsumerWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterProvider);

    return MaterialApp(
      home: Scaffold(
        body: Center(child: Text('count: $count')),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            ref.read(counterProvider.notifier).state++;
          },
          child: const Icon(Icons.add),
        ),
      ),
    );
  }
}

실전에서는 단순 카운터보다 API, 인증, 로컬 저장소, Repository를 provider로 묶는 일이 많다.

final apiClientProvider = Provider<ApiClient>((ref) {
  return ApiClient();
});

final noteRepositoryProvider = Provider<NoteRepository>((ref) {
  final apiClient = ref.watch(apiClientProvider);
  return NoteRepository(apiClient);
});

이렇게 해 두면 화면은 NoteRepository가 정확히 어떻게 만들어지는지 몰라도 된다. 나중에 REST API에서 Firebase로 바꾸거나, 테스트에서 가짜 Repository로 교체할 때도 구조가 훨씬 편해진다.

API 통신: http와 dio

REST API를 연결할 때 가장 먼저 고민하는 패키지는 http와 dio다. 둘 다 훌륭하지만 성격이 다르다.

http는 단순하고 가볍다. GET, POST, PUT, DELETE 요청을 직접 다루기 좋고, 입문자가 HTTP의 기본 흐름을 이해하기에 적합하다.

flutter pub add http
import 'dart:convert';
import 'package:http/http.dart' as http;

Future<List<dynamic>> fetchNotes() async {
  final response = await http.get(
    Uri.parse('https://example.com/notes'),
  );

  if (response.statusCode != 200) {
    throw Exception('노트 목록을 불러오지 못했습니다.');
  }

  return jsonDecode(response.body) as List<dynamic>;
}

dio는 실전 앱에서 필요한 고급 기능이 풍부하다. 요청/응답 인터셉터, 인증 토큰 자동 추가, 파일 업로드, 요청 취소, 타임아웃 설정 등을 구조적으로 관리하기 쉽다.

flutter pub add dio

앱이 작고 API가 단순하다면 http로 충분하다. 로그인 토큰 갱신, 공통 헤더, 에러 변환, 파일 업로드가 많다면 dio가 편하다.

모델링과 JSON: freezed, json_serializable

처음에는 JSON을 직접 Map<String, dynamic>으로 다뤄도 된다. 하지만 모델 필드가 늘어나고 API 응답이 많아지면 직접 작성한 fromJson, toJson은 실수의 온상이 된다. 필드명을 바꿨는데 JSON 키를 수정하지 않거나, nullable 처리를 놓치거나, 복사 메서드를 매번 손으로 작성하게 된다.

이때 freezed와 json_serializable을 함께 사용하면 좋다.

flutter pub add freezed_annotation json_annotation
flutter pub add dev:build_runner
flutter pub add dev:freezed
flutter pub add dev:json_serializable

예를 들어 노트 모델은 다음처럼 작성할 수 있다.

import 'package:freezed_annotation/freezed_annotation.dart';

part 'note.freezed.dart';
part 'note.g.dart';

@freezed
abstract class Note with _$Note {
  const factory Note({
    required String id,
    required String title,
    required String content,
    required DateTime updatedAt,
    @Default(<String>[]) List<String> tags,
  }) = _Note;

  factory Note.fromJson(Map<String, dynamic> json) => _$NoteFromJson(json);
}

그다음 코드 생성기를 실행한다.

dart run build_runner build --delete-conflicting-outputs

파일 변경을 감시하고 자동 생성하려면 다음 명령어를 사용한다.

dart run build_runner watch --delete-conflicting-outputs

이 조합의 장점은 단순히 코드가 줄어드는 데 있지 않다. 모델을 불변으로 다루고, JSON 변환을 자동화하고, copyWith로 상태를 안전하게 갱신할 수 있다는 데 있다. 상태관리와 궁합이 매우 좋다.

데이터 저장과 캐싱 패키지 선택하기

앱에는 서버에 저장할 데이터도 있고, 기기에 잠깐 저장할 데이터도 있다. 모든 데이터를 같은 방식으로 저장하면 안 된다. 테마 설정과 로그인 토큰, 오프라인 노트 캐시는 성격이 완전히 다르다.

용도추천 패키지예시
간단한 설정값shared_preferences다크 모드 여부, 온보딩 완료 여부, 마지막 선택 탭
민감 정보flutter_secure_storage액세스 토큰, 리프레시 토큰, 사용자 식별 정보
구조화된 로컬 DBdrift노트 목록, 검색 가능한 캐시, 오프라인 데이터
네트워크 이미지 캐싱cached_network_image프로필 이미지, 첨부 이미지, 썸네일

shared_preferences는 작고 단순한 값에 적합하다.

flutter pub add shared_preferences

예를 들어 온보딩을 한 번 봤는지 저장하는 정도라면 충분하다. 하지만 인증 토큰처럼 민감한 값은 여기에 저장하지 않는 것이 좋다.

토큰과 민감 정보는 flutter_secure_storage를 사용한다.

flutter pub add flutter_secure_storage

구조화된 데이터가 많다면 drift를 고려하자.

flutter pub add drift sqlite3_flutter_libs path_provider path
flutter pub add dev:drift_dev build_runner

drift는 SQLite를 Dart답게 사용할 수 있게 도와준다. 노트, 태그, 첨부파일, 동기화 상태처럼 관계가 있는 데이터를 저장하기 좋다.

이미지는 cached_network_image가 자주 쓰인다.

flutter pub add cached_network_image

네트워크 이미지를 매번 새로 내려받으면 데이터도 낭비되고 화면도 느려진다. 캐싱 패키지를 사용하면 이미 본 이미지를 재사용하고, 로딩 중 UI와 에러 UI도 더 쉽게 처리할 수 있다.

Firebase 패키지 조합하기

Firebase는 하나의 거대한 패키지가 아니라 기능별 패키지들의 조합에 가깝다. 먼저 firebase_core로 Firebase를 초기화하고, 필요한 기능을 하나씩 붙인다.

목적패키지역할
기본 초기화firebase_coreFirebase 앱 연결의 출발점
로그인firebase_auth이메일/비밀번호, 소셜 로그인, 익명 로그인
문서형 데이터cloud_firestore컬렉션과 문서 기반 데이터 저장
파일 업로드firebase_storage이미지, 첨부 파일 저장
푸시 알림firebase_messagingFCM 기반 알림 수신
크래시 수집firebase_crashlytics출시 후 오류 추적

기본 설치 예시는 다음과 같다.

flutter pub add firebase_core
flutter pub add firebase_auth
flutter pub add cloud_firestore
flutter pub add firebase_storage
flutter pub add firebase_messaging
flutter pub add firebase_crashlytics

앱 시작 시 Firebase를 초기화한다.

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

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

로그인 기반 앱에서는 사용자별 데이터 분리가 중요하다. Firestore에 노트를 저장한다면 대략 다음과 같은 경로를 생각할 수 있다.

users/{uid}/notes/{noteId}

이 구조는 보안 규칙을 작성할 때도 자연스럽다. 현재 로그인한 사용자의 uid와 경로의 uid가 같을 때만 읽고 쓰게 만들 수 있기 때문이다.

Firebase 패키지는 강력하지만, 많이 붙일수록 초기 설정과 플랫폼별 설정도 늘어난다. 처음부터 모든 기능을 설치하지 말고, 인증이 필요하면 firebase_auth, 문서 데이터가 필요하면 cloud_firestore, 이미지 업로드가 필요하면 firebase_storage처럼 목적에 맞게 추가하자.

추천 패키지 설치 세트

프로젝트를 새로 만들 때마다 패키지를 하나씩 기억하기 어렵다. 아래 조합은 이 책에서 만든 개인 지식 노트 앱 같은 실전 앱을 시작할 때 참고할 만한 기본 세트다.

라우팅과 상태관리 중심의 최소 세트는 다음과 같다.

flutter pub add go_router flutter_riverpod

REST API 앱 기본 세트는 다음과 같다.

flutter pub add go_router flutter_riverpod dio
flutter pub add freezed_annotation json_annotation
flutter pub add dev:build_runner dev:freezed dev:json_serializable

로컬 저장과 캐싱까지 포함하면 다음처럼 확장할 수 있다.

flutter pub add shared_preferences flutter_secure_storage cached_network_image
flutter pub add drift sqlite3_flutter_libs path_provider path
flutter pub add dev:drift_dev build_runner

Firebase 기반 앱이라면 다음 조합을 많이 사용한다.

flutter pub add firebase_core firebase_auth cloud_firestore firebase_storage
flutter pub add firebase_messaging firebase_crashlytics

여기서 중요한 것은 "추천 세트를 무조건 다 설치하라"가 아니다. 패키지는 앱에 들어가는 가구와 같다. 언젠가 필요할 것 같다는 이유로 모든 가구를 들이면 집이 좁아진다. 지금 필요한 기능부터 설치하고, 앱이 성장할 때 하나씩 추가하자.

패키지 선택 기준

좋은 패키지는 앱 개발 속도를 크게 높인다. 반대로 맞지 않는 패키지는 몇 달 뒤 발목을 잡는다. 패키지를 고를 때는 다음 기준을 확인하자.

기준확인할 것
유지보수최근 업데이트 날짜, 이슈 응답, Flutter 최신 버전 대응
안정성다운로드 수, 좋아요 수, pub.dev 점수, 실제 사용 사례
문서화README, 예제 코드, API 문서, 마이그레이션 가이드
플랫폼 지원Android, iOS, Web, macOS, Windows, Linux 지원 여부
의존성 무게불필요하게 많은 하위 패키지를 끌고 오지 않는지
라이선스상업적 사용이 가능한 라이선스인지

특히 멀티플랫폼 앱을 만든다면 플랫폼 지원 여부를 꼭 확인해야 한다. 모바일에서는 잘 되는 패키지가 Web에서는 제한적일 수 있고, Desktop에서는 추가 설정이 필요할 수 있다. 카메라, 파일, 위치, 알림처럼 네이티브 기능에 가까운 패키지일수록 이 차이가 커진다.

팀 프로젝트에서 명령어를 표준화하기

혼자 개발할 때는 머릿속에 명령어를 넣어 두어도 된다. 하지만 팀 프로젝트에서는 "각자 알아서 실행"이 위험해질 수 있다. 누군가는 flutter pub upgrade를 자주 하고, 누군가는 몇 달째 같은 lock 파일을 쓰고, 누군가는 코드 생성 명령어를 잊어버린다.

이럴 때는 README에 자주 쓰는 명령어를 명확히 적어 두자.

## Development

```bash
flutter pub get
dart run build_runner build --delete-conflicting-outputs
flutter analyze
flutter test
flutter run

Build

flutter build appbundle --release
flutter build ipa --release

더 나아가 Makefile이나 스크립트 도구를 사용할 수도 있다.

```makefile
setup:
	flutter pub get
	dart run build_runner build --delete-conflicting-outputs

check:
	flutter analyze
	flutter test

build-android:
	flutter build appbundle --release

그러면 팀원은 긴 명령어를 외우지 않아도 된다.

make setup
make check
make build-android

명령어 표준화는 사소해 보이지만 협업의 피로를 크게 줄인다. 좋은 팀은 코드를 잘 짜는 팀이기도 하지만, 반복 작업을 덜 헷갈리게 만드는 팀이기도 하다.

마지막으로 남겨 두는 개인 치트시트

책을 덮기 전에, 가장 자주 쓸 명령어만 다시 압축해 보자. 이 표는 북마크해 두어도 좋다.

하고 싶은 일명령어
Flutter 상태 확인flutter doctor -v
새 앱 만들기flutter create my_app
앱 실행flutter run
기기 목록 보기flutter devices
패키지 받기flutter pub get
패키지 추가flutter pub add package_name
패키지 삭제flutter pub remove package_name
패키지 업데이트 확인flutter pub outdated
코드 분석flutter analyze
코드 포맷dart format .
테스트 실행flutter test
코드 생성dart run build_runner build --delete-conflicting-outputs
빌드 캐시 정리flutter clean && flutter pub get
Android 출시 빌드flutter build appbundle --release
iOS 출시 빌드flutter build ipa --release
Web 출시 빌드flutter build web --release

이제 여러분은 Flutter 앱을 만드는 데 필요한 큰 길을 모두 지나왔다. Dart 문법에서 시작해 위젯, 레이아웃, Material 3, 입력, 라우팅, 상태관리, 아키텍처, API, 로컬 저장소, Firebase, 알림, 네이티브 기능, 반응형 UI, 애니메이션, 테스트, 성능, 보안, 배포까지 왔다.

마지막에 남는 것은 결국 반복이다. 좋은 앱은 한 번에 완성되지 않는다. 만들고, 실행하고, 분석하고, 테스트하고, 고치고, 다시 빌드한다. 오늘 정리한 명령어와 패키지는 그 반복을 더 빠르고 안전하게 만들어 주는 도구다.

터미널을 열고 다음 명령어를 입력하는 순간, 여러분은 더 이상 예제만 따라 하는 독자가 아니다.

flutter create my_next_app

이제 다음 앱은 여러분의 차례다.

참고

1The Flutter command-line tool

2dart pub

3Getting started | Riverpod

4flutter_riverpod package

책 목록

처음부터 배포까지 Flutter 앱 개발 입문

전체 목차 보기

이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.

틸노트는 사용자가 AI를 활용해 노트를 쉽게 작성하거나 편집할 수 있는 서비스입니다.

AI 스퀘어 단톡방에 함께해요

AI 활용과 틸노트 사용 팁을 나누는 오픈채팅방입니다. 입장 비밀번호는 tilnote입니다.

참여하기