#!if 넘어옴1 != null
'''플러터'''{{{#!if 넘어옴2 == null
{{{#!if 넘어옴1[넘어옴1.length - 1] >= 0xAC00 && 넘어옴1[넘어옴1.length - 1] <= 0xD7A3
{{{#!if ((넘어옴1[넘어옴1.length - 1] - 0xAC00) % 28) == 0
는}}}{{{#!if ((넘어옴1[넘어옴1.length - 1] - 0xAC00) % 28) != 0
은}}}}}}{{{#!if 넘어옴1[넘어옴1.length - 1] < 0xAC00 || 넘어옴1[넘어옴1.length - 1] > 0xD7A3
은(는)}}}}}}{{{#!if 넘어옴2 != null
, '''플루터'''{{{#!if 넘어옴3 == null
{{{#!if 넘어옴2[넘어옴2.length - 1] >= 0xAC00 && 넘어옴2[넘어옴2.length - 1] <= 0xD7A3
{{{#!if ((넘어옴2[넘어옴2.length - 1] - 0xAC00) % 28) == 0
는}}}{{{#!if ((넘어옴2[넘어옴2.length - 1] - 0xAC00) % 28) != 0
은}}}}}}{{{#!if 넘어옴2[넘어옴2.length - 1] < 0xAC00 || 넘어옴2[넘어옴2.length - 1] > 0xD7A3
은(는)}}}}}}}}}{{{#!if 넘어옴3 != null
, ''''''{{{#!if 넘어옴4 == null
{{{#!if 넘어옴3[넘어옴3.length - 1] >= 0xAC00 && 넘어옴3[넘어옴3.length - 1] <= 0xD7A3
{{{#!if ((넘어옴3[넘어옴3.length - 1] - 0xAC00) % 28) == 0
는}}}{{{#!if ((넘어옴3[넘어옴3.length - 1] - 0xAC00) % 28) != 0
은}}}}}}{{{#!if 넘어옴3[넘어옴3.length - 1] < 0xAC00 || 넘어옴3[넘어옴3.length - 1] > 0xD7A3
은(는)}}}}}}}}}{{{#!if 넘어옴4 != null
, ''''''{{{#!if 넘어옴5 == null
{{{#!if 넘어옴4[넘어옴4.length - 1] >= 0xAC00 && 넘어옴4[넘어옴4.length - 1] <= 0xD7A3
{{{#!if ((넘어옴4[넘어옴4.length - 1] - 0xAC00) % 28) == 0
는}}}{{{#!if ((넘어옴4[넘어옴4.length - 1] - 0xAC00) % 28) != 0
은}}}}}}{{{#!if 넘어옴4[넘어옴4.length - 1] < 0xAC00 || 넘어옴4[넘어옴4.length - 1] > 0xD7A3
은(는)}}}}}}}}}{{{#!if 넘어옴5 != null
, ''''''{{{#!if 넘어옴6 == null
{{{#!if 넘어옴5[넘어옴5.length - 1] >= 0xAC00 && 넘어옴5[넘어옴5.length - 1] <= 0xD7A3
{{{#!if ((넘어옴5[넘어옴5.length - 1] - 0xAC00) % 28) == 0
는}}}{{{#!if ((넘어옴5[넘어옴5.length - 1] - 0xAC00) % 28) != 0
은}}}}}}{{{#!if 넘어옴5[넘어옴5.length - 1] < 0xAC00 || 넘어옴5[넘어옴5.length - 1] > 0xD7A3
은(는)}}}}}}}}}{{{#!if 넘어옴6 != null
, ''''''{{{#!if 넘어옴7 == null
{{{#!if 넘어옴6[넘어옴6.length - 1] >= 0xAC00 && 넘어옴6[넘어옴6.length - 1] <= 0xD7A3
{{{#!if ((넘어옴6[넘어옴6.length - 1] - 0xAC00) % 28) == 0
는}}}{{{#!if ((넘어옴6[넘어옴6.length - 1] - 0xAC00) % 28) != 0
은}}}}}}{{{#!if 넘어옴6[넘어옴6.length - 1] < 0xAC00 || 넘어옴6[넘어옴6.length - 1] > 0xD7A3
은(는)}}}}}}}}}{{{#!if 넘어옴7 != null
, ''''''{{{#!if 넘어옴8 == null
{{{#!if 넘어옴7[넘어옴7.length - 1] >= 0xAC00 && 넘어옴7[넘어옴7.length - 1] <= 0xD7A3
{{{#!if ((넘어옴7[넘어옴7.length - 1] - 0xAC00) % 28) == 0
는}}}{{{#!if ((넘어옴7[넘어옴7.length - 1] - 0xAC00) % 28) != 0
은}}}}}}{{{#!if 넘어옴7[넘어옴7.length - 1] < 0xAC00 || 넘어옴7[넘어옴7.length - 1] > 0xD7A3
은(는)}}}}}}}}}{{{#!if 넘어옴8 != null
, ''''''{{{#!if 넘어옴9 == null
{{{#!if 넘어옴8[넘어옴8.length - 1] >= 0xAC00 && 넘어옴8[넘어옴8.length - 1] <= 0xD7A3
{{{#!if ((넘어옴8[넘어옴8.length - 1] - 0xAC00) % 28) == 0
는}}}{{{#!if ((넘어옴8[넘어옴8.length - 1] - 0xAC00) % 28) != 0
은}}}}}}{{{#!if 넘어옴8[넘어옴8.length - 1] < 0xAC00 || 넘어옴8[넘어옴8.length - 1] > 0xD7A3
은(는)}}}}}}}}}{{{#!if 넘어옴9 != null
, ''''''{{{#!if 넘어옴10 == null
{{{#!if 넘어옴9[넘어옴9.length - 1] >= 0xAC00 && 넘어옴9[넘어옴9.length - 1] <= 0xD7A3
{{{#!if ((넘어옴9[넘어옴9.length - 1] - 0xAC00) % 28) == 0
는}}}{{{#!if ((넘어옴9[넘어옴9.length - 1] - 0xAC00) % 28) != 0
은}}}}}}{{{#!if 넘어옴9[넘어옴9.length - 1] < 0xAC00 || 넘어옴9[넘어옴9.length - 1] > 0xD7A3
은(는)}}}}}}}}}{{{#!if 넘어옴10 != null
, ''''''{{{#!if 넘어옴10[넘어옴10.length - 1] >= 0xAC00 && 넘어옴10[넘어옴10.length - 1] <= 0xD7A3
{{{#!if ((넘어옴10[넘어옴10.length - 1] - 0xAC00) % 28) == 0
는}}}{{{#!if ((넘어옴10[넘어옴10.length - 1] - 0xAC00) % 28) != 0
은}}}}}}{{{#!if 넘어옴10[넘어옴10.length - 1] < 0xAC00 || 넘어옴10[넘어옴10.length - 1] > 0xD7A3
은(는)}}}}}} 여기로 연결됩니다. #!if 설명 == null && 리스트 == null
{{{#!if 설명1 == null
다른 뜻에 대한 내용은 아래 문서를}}}{{{#!if 설명1 != null
{{{#!html BEMANI 시리즈의 수록곡}}}에 대한 내용은 [[Flutter(BEMANI)]] 문서{{{#!if (문단1 == null) == (앵커1 == null)
를}}}{{{#!if 문단1 != null & 앵커1 == null
의 [[Flutter(BEMANI)#s-|]]번 문단을}}}{{{#!if 문단1 == null & 앵커1 != null
의 [[Flutter(BEMANI)#|]] 부분을}}}}}}{{{#!if 설명2 != null
, {{{#!html 만화 '헌터×헌터'의 등장인물}}}에 대한 내용은 [[후라타]] 문서{{{#!if (문단2 == null) == (앵커2 == null)
를}}}{{{#!if 문단2 != null & 앵커2 == null
의 [[후라타#s-|]]번 문단을}}}{{{#!if 문단2 == null & 앵커2 != null
의 [[후라타#|]] 부분을}}}}}}{{{#!if 설명3 != null
, {{{#!html }}}에 대한 내용은 [[]] 문서{{{#!if (문단3 == null) == (앵커3 == null)
를}}}{{{#!if 문단3 != null & 앵커3 == null
의 [[#s-|]]번 문단을}}}{{{#!if 문단3 == null & 앵커3 != null
의 [[#|]] 부분을}}}}}}{{{#!if 설명4 != null
, {{{#!html }}}에 대한 내용은 [[]] 문서{{{#!if (문단4 == null) == (앵커4 == null)
를}}}{{{#!if 문단4 != null & 앵커4 == null
의 [[#s-|]]번 문단을}}}{{{#!if 문단4 == null & 앵커4 != null
의 [[#|]] 부분을}}}}}}{{{#!if 설명5 != null
, {{{#!html }}}에 대한 내용은 [[]] 문서{{{#!if (문단5 == null) == (앵커5 == null)
를}}}{{{#!if 문단5 != null & 앵커5 == null
의 [[#s-|]]번 문단을}}}{{{#!if 문단5 == null & 앵커5 != null
의 [[#|]] 부분을}}}}}}{{{#!if 설명6 != null
, {{{#!html }}}에 대한 내용은 [[]] 문서{{{#!if (문단6 == null) == (앵커6 == null)
를}}}{{{#!if 문단6 != null & 앵커6 == null
의 [[#s-|]]번 문단을}}}{{{#!if 문단6 == null & 앵커6 != null
의 [[#|]] 부분을}}}}}}{{{#!if 설명7 != null
, {{{#!html }}}에 대한 내용은 [[]] 문서{{{#!if (문단7 == null) == (앵커7 == null)
를}}}{{{#!if 문단7 != null & 앵커7 == null
의 [[#s-|]]번 문단을}}}{{{#!if 문단7 == null & 앵커7 != null
의 [[#|]] 부분을}}}}}}{{{#!if 설명8 != null
, {{{#!html }}}에 대한 내용은 [[]] 문서{{{#!if (문단8 == null) == (앵커8 == null)
를}}}{{{#!if 문단8 != null & 앵커8 == null
의 [[#s-|]]번 문단을}}}{{{#!if 문단8 == null & 앵커8 != null
의 [[#|]] 부분을}}}}}}{{{#!if 설명9 != null
, {{{#!html }}}에 대한 내용은 [[]] 문서{{{#!if (문단9 == null) == (앵커9 == null)
를}}}{{{#!if 문단9 != null & 앵커9 == null
의 [[#s-|]]번 문단을}}}{{{#!if 문단9 == null & 앵커9 != null
의 [[#|]] 부분을}}}}}}{{{#!if 설명10 != null
, {{{#!html }}}에 대한 내용은 [[]] 문서{{{#!if (문단10 == null) == (앵커10 == null)
를}}}{{{#!if 문단10 != null & 앵커10 == null
의 [[#s-|]]번 문단을}}}{{{#!if 문단10 == null & 앵커10 != null
의 [[#|]] 부분을}}}}}}#!if 설명 == null
{{{#!if 리스트 != null
다른 뜻에 대한 내용은 아래 문서를}}} 참고하십시오.#!if 리스트 != null
{{{#!if 문서명1 != null
* {{{#!if 설명1 != null
BEMANI 시리즈의 수록곡: }}}[[Flutter(BEMANI)]] {{{#!if 문단1 != null & 앵커1 == null
문서의 [[Flutter(BEMANI)#s-|]]번 문단}}}{{{#!if 문단1 == null & 앵커1 != null
문서의 [[Flutter(BEMANI)#|]] 부분}}}}}}{{{#!if 문서명2 != null
* {{{#!if 설명2 != null
만화 '헌터×헌터'의 등장인물: }}}[[후라타]] {{{#!if 문단2 != null & 앵커2 == null
문서의 [[후라타#s-|]]번 문단}}}{{{#!if 문단2 == null & 앵커2 != null
문서의 [[후라타#|]] 부분}}}}}}{{{#!if 문서명3 != null
* {{{#!if 설명3 != null
: }}}[[]] {{{#!if 문단3 != null & 앵커3 == null
문서의 [[#s-|]]번 문단}}}{{{#!if 문단3 == null & 앵커3 != null
문서의 [[#|]] 부분}}}}}}{{{#!if 문서명4 != null
* {{{#!if 설명4 != null
: }}}[[]] {{{#!if 문단4 != null & 앵커4 == null
문서의 [[#s-|]]번 문단}}}{{{#!if 문단4 == null & 앵커4 != null
문서의 [[#|]] 부분}}}}}}{{{#!if 문서명5 != null
* {{{#!if 설명5 != null
: }}}[[]] {{{#!if 문단5 != null & 앵커5 == null
문서의 [[#s-|]]번 문단}}}{{{#!if 문단5 == null & 앵커5 != null
문서의 [[#|]] 부분}}}}}}{{{#!if 문서명6 != null
* {{{#!if 설명6 != null
: }}}[[]] {{{#!if 문단6 != null & 앵커6 == null
문서의 [[#s-|]]번 문단}}}{{{#!if 문단6 == null & 앵커6 != null
문서의 [[#|]] 부분}}}}}}{{{#!if 문서명7 != null
* {{{#!if 설명7 != null
: }}}[[]] {{{#!if 문단7 != null & 앵커7 == null
문서의 [[#s-|]]번 문단}}}{{{#!if 문단7 == null & 앵커7 != null
문서의 [[#|]] 부분}}}}}}{{{#!if 문서명8 != null
* {{{#!if 설명8 != null
: }}}[[]] {{{#!if 문단8 != null & 앵커8 == null
문서의 [[#s-|]]번 문단}}}{{{#!if 문단8 == null & 앵커8 != null
문서의 [[#|]] 부분}}}}}}{{{#!if 문서명9 != null
* {{{#!if 설명9 != null
: }}}[[]] {{{#!if 문단9 != null & 앵커9 == null
문서의 [[#s-|]]번 문단}}}{{{#!if 문단9 == null & 앵커9 != null
문서의 [[#|]] 부분}}}}}}{{{#!if 문서명10 != null
* {{{#!if 설명10 != null
: }}}[[]] {{{#!if 문단10 != null & 앵커10 == null
문서의 [[#s-|]]번 문단}}}{{{#!if 문단10 == null & 앵커10 != null
문서의 [[#|]] 부분}}}}}}| <colcolor=#075B9D,#60C9F8> 플러터 Flutter | |
| | |
| 종류 | GUI 프레임워크 |
| 개발 | 구글 및 커뮤니티 |
| 출시 | 알파 0.0.6: 2017년 5월 11일# 정식 1.0.0: 2018년 12월 4일# |
| 안정 버전 | 3.35.7 (2025년 10월 26일) # |
| 지원 언어 | Dart |
| 플랫폼 | Android, iOS, 웹, Windows, macOS, GTKLinux |
| 라이선스 | BSD 라이선스# |
| | |
1. 개요
구글에서 2017년 5월 출시된 Skia 및 Impeller를 렌더링 엔진으로 사용하는 모바일/웹/데스크톱 크로스 플랫폼 GUI 프레임워크.단일 코드베이스로 Android, Linux, Windows, macOS, iOS 및 웹 브라우저에서 모두 동작되는 앱을 위해 출시되었으며, 이때 사용되는 프로그래밍 언어는 구글의 Dart이다. 구글의 또 다른 운영 체제인 퓨시아의 UI 및 퓨시아 애플리케이션 역시 플러터로 작성된다.
2. 특징
플러터 프레임워크는 소스 코드를 네이티브 CPU 머신 코드로 직접 컴파일하며 GUI를 위해 각 OS의 네이티브 UI 컴포넌트로 변환하지 않고 렌더링 엔진을 통해 GPU를 이용해 직접 드로잉하기 때문에 성능이 뛰어나다. OS에 관계없이 안드로이드의 Material 디자인, macOS/iOS의 Cupertino, 윈도우 Fluent UI 등등의 테마 적용이 가능하며 테마(Theme) 커스텀도 가능하다. CustomPaint등으로 픽셀 단위의 커스텀 위젯 작성도 가능하다.Flutter는 리액티브 프레임워크 프로그래밍 기법으로 제작되었다. 선언형(declarative) UI와 상태 관리(state management)가 특징이다. State 클래스에는 화면 표시와 관련된 build() 메서드외에 특정 조건에서만 실행되는 라이프 사이클 매서드가 있다. UI 디자인을 Dart 언어의 Widget을 사용하면 되므로 UI 언어가 분리된 Java, C#, Javascript 계열의 개발과는 생산성 측면에서 비교 자체를 불허한다.
상태 관리는 기본적으로 StatefulWidget/setState 사용 및 생성자(constructor)/콜백(callback)을 통한 데이터 up/down 전달이 가능하다. 본격적인 상태 관리 및 MVC/MVVM를 위해서는 GetX, Provider, Riverpod, BLoC(Cubit), MobX, get_it 등의 패키지들이 있으며 자신의 취향에 따라 선택하면 된다.
const 외에 final이라는 개념도 존재한다. const는 컴파일 단계에서 결정되며 final은 런타임에서 결정된다. 차이점은 인스턴스의 필드값 변경 가능 여부다. 상태 관리 시 필드값 변경이 필요하기 때문에 final이 많이 사용된다.
주요 IDE로는 Android Studio와 Visual Studio Code가 있다. VSC 만으로도 개발이 아예 불가능한 건 아니지만, JDK 번들이나 Android SDK, Android 에뮬레이터 등을 수작업으로 설치해야 하기에 VSC로 개발하려는 사람도 사실상 Android Studio는 반필수적으로 같이 설치하는 실정이다. 또한 디버깅 측면에서도 Android Studio 쪽이 뛰어나기 때문에 같이 쓰면 썼지 굳이 VSC로만 개발할 이유는 거의 없다.
2.1. Flutter vs React Native
항상 외국 포럼에서 주기적으로 불타오르는 주제 중 하나가 바로 '크로스플랫폼 앱 개발로 Flutter가 더 좋냐 React Native가 더 좋냐'는 주제이다. 이는 상황에 따라 답이 다르기 때문에 뭐가 더 좋고 뭐가 더 나쁘다라고 양분하는 건 사실상 불가능하며, 객관적인 사실만 놓고 봤을 때 각 프레임워크의 장점들은 다음과 같다:React Native의 장점
- Code Push가 공식적으로 지원된다. [1]
- 인력 시장에서 상대적으로 많은 React 개발자들을 채용하여 개발에 활용할 수 있다.
- 최신 네이티브 UI 요소를 바로 사용할 수 있다. [2]
- 앱 용량이 Flutter보다 작다.
Flutter의 장점
- 하나의 코드로 여러 플랫폼에서 동일한 UI를 보여줄 수 있다.
- Material 디자인에 특히 최적화가 잘 되어 있으며, Material 위젯들을 커스텀하여 자신만의 UI를 만들기도 쉽다.
- RN의 Fast Refresh보다 강력한 Hot Reload 기능
- 공식적으로 지원되는 데스크톱 플랫폼 [3]
- 기술적으로 RN보다 조금 더 빠른 성능 [4]
보통은 웹과 앱을 동시에 개발하거나 웹 개발 인력이 이미 있는 상황에서 앱을 추가적으로 개발하는 경우에는 React Native를 추천하고 처음부터 모바일 애플리케이션 위주로 만들 때에는 Flutter를 추천하는 편이지만, 그 외에도 본인의 여건들을 잘 고려하여 적합한 프레임워크를 선택하는 것이 좋다.
3. 지원 플랫폼
3.1. 모바일
기존에는 Android와 iOS 모두 Skia 2D 렌더러를 이용하였으나 Flutter 3.0 부터 iOS에 Metal API를 활용한 Impeller 엔진이 실험적으로 적용되었고, 3.10부터 안정화되고 기본값이 되었으며 3.29부터는 아예 Skia 렌더러가 iOS에서 빠지고 Impeller만 사용할 수 있게 되었다.Android의 경우 3.10부터 Vulkan 및 OpenGL ES를 활용한 Impeller 엔진이 실험적으로 적용되었으며, 3.27부터는 Android에서도 Impeller가 기본값이 되었다. 다만 Android의 경우 AP 파편화가 심하여 Google에서 모든 AP 드라이버에 맞춰 안정화하는데 애를 먹고 있으며, 그나마 퀄컴 스냅드래곤의 경우 상황이 낫지만 나머지 미디어텍 등의 AP에서는 화면 깨짐이나 앱 강제 종료[5] 등의 오류가 자주 발생한다. 특정 AP를 사용하는 기기들에서 유난히 크래시가 자주 일어난다면 공식 문서를 참고하여 Impeller를 비활성화해볼 수 있다.
Flutter 버전 및 플랫폼별 Impeller 지원상황
3.2. 데스크톱
데스크톱 상에서의 플러터 앱 실행은 2021년 3월부터 공식적으로 지원되고 있다. 윈도우에서는 OpenGL API 호출을 DirectX 11로 변환하는 ANGLE 라이브러리가 사용되어 렌더링되고 있으며, macOS의 경우 iOS의 것과 대부분을 공유하며 Metal API를 통한 Impeller 엔진으로 구동된다. 리눅스의 경우 GTK 임베더 위에서 Skia 엔진을 띄우고 있다. 윈도우 및 리눅스도 Impeller를 도입할 예정에 있으며 현재 실험 단계에 있다.Google이 발표한 공식 2025년 로드맵에 따르면 당분간 Google은 Flutter 모바일과 웹에만 집중할 것이며, 대신 Ubuntu의 개발사인 Canonical에서 Flutter 데스크톱에 대한 기여를 이어나갈 것이라고 밝혔다.[6]
3.3. 웹
| | |
| default 모드: 자바스크립트로 컴파일 및 canvaskit.wasm 렌더러 사용 | WebAssembly 모드: 웹어셈블리로 컴파일 및 skwasm 렌더러 사용 |
빌드된 플러터 웹 앱을 기존 HTML 페이지의 풀 윈도우, iframe, 또는 임의의 html element에 임베딩을 지원하고 있다. package:web을 사용하여 레거시 HTML/CSS와 연동하여 사용도 가능하다.
Flutter 3.32부터 웹에도 Hot Reload 기능이 실험적으로 도입되었으며, 3.35부터는 별도의 실험 플래그 필요없이 자동적으로 Hot Reload를 지원하여 개발 시간이 크게 단축되었다.
4. 백엔드
아무래도 Flutter 자체가 구글이 만든 것이다 보니 구글이 운영하고 있는 BaaS[7]인 Firebase를 쓰는 쪽이 가장 레퍼런스가 많아 적용하기 쉬운 편이다. 게다가 원격 푸시 알림을 구현하기 위해서는 대부분 FCM을 사용하기 때문에 겸사겸사 백엔드까지 Firebase를 쓰는 경우가 꽤 있다. 다만 Firebase의 경우 무료 사용량을 지나는 순간 과금 체계가 타 BaaS 대비 비싸기 때문에 수익 창출과 규모 확장을 고려하고 있는 앱이라면 재고해봄이 좋다.Firebase 외에도 Supabase나 Appwrite와 같은 서드파티 BaaS를 사용해볼 수 있다. 문서화가 잘 되어 있어 Firebase에 준하는 정도로 적용이 쉽고, 이 둘은 클라우드 서비스 뿐만이 아닌 개인 PC나 VPS 등에서 직접 온 프레미스(셀프 호스팅) 형태로 배포하는 것도 가능하다.
물론 이런 BaaS들을 쓰지 않고 Spring이나 NestJS 등과 같은 전통적인 백엔드 서버와 연동하는 것도 당연히 가능하다. 여담으로, Flutter에 사용된 Dart 언어는 UI(프론트엔드)와 서버(백엔드) 모두에서의 사용이 고려된 언어이기 때문에 Dart에 익숙하다면 Dart 기반의 백엔드[8]를 구현하여 Flutter 앱과 붙일 수도 있다.
5. 상태 관리 패키지
Flutter는 기본적으로 setState(), InheritedWidget, 그리고 Navigator를 중심으로 한 내장 상태 관리 및 라우팅 시스템을 제공한다.setState()는 위젯 단위로 상태를 직접 갱신하는 가장 단순한 방식으로, 소규모 위젯이나 단일 화면에서는 충분히 효율적이다. 그러나 화면이 복잡해지고 위젯 트리가 깊어질수록, 상태를 여러 곳에서 공유하거나 전달해야 하는 상황에서 코드가 급격히 복잡해진다.
Navigator 역시 Flutter가 기본적으로 제공하는 라우팅 시스템으로, 스택(Stack) 기반으로 페이지를 관리한다. 하지만 이 또한 화면 이동이나 상태 보존이 많은 프로젝트에서는 라우트 스택 관리가 번거롭고 코드가 장황해지는 문제가 있다. 특히 Web 환경에서는 URL 동기화나 브라우저 히스토리 관리가 까다롭다.
이러한 이유로, 많은 개발자들은 Flutter의 기본 상태 관리 방식 대신 외부 상태 관리 패키지를 사용한다. 현재 커뮤니티에서 널리 사용되는 대표적인 패키지는 GetX, BLoC, Provider, Riverpod, MobX, get_it 정도가 있으며, 각각 고유한 철학과 설계 방식이 존재한다.
5.1. GetX
상태 관리, 종속성 주입(Dependency Injection), 라우팅 및 기타 강력한 유틸리티들을 한 패키지 안에 탑재하고 있으며 code bloat가 없다. 또한 Flutter에서 어려운 개념 중 하나인 BuildContext를 사용하지 않아 사용 난이도 및 MVC/MVVM 아키텍처 구현이 가장 쉽다는 장점이 있다. 그로 인해 2024년 pub.dev 라이크 순위 1위를 차지하기도 하였다.하지만 이 BuildContext를 사용하지 않는다는 점이 오히려 비판을 받기도 한다. BuildContext는 위젯 트리에서 현재 위젯의 위치와 레이아웃 정보 등을 포함하는 객체로 Flutter에서 중요한 개념인데, 이를 사용하지 않다 보니 사용 중 위젯 트리가 꼬여도 디버깅이 어려워진다. 일각에서는 이러한 점 때문에 GetX를 이용하여 개발하는 것은 Flutter 앱이 아닌 GetX 앱으로 만드는 것이라고 꼬집기도 하였으며#, LINE 개발진도 Flutter 상태 관리 패키지를 비교 탐구하면서 GetX의 이러한 점 때문에 사용을 포기했을 정도라고 언급하기도 하였다.#
또한, 업데이트 주기가 매우 불규칙적이고 텀도 긴 편이라서 사용자의 불안을 일으키고 있다. 실제로도 Github Issue는 1000개가 넘어감에도 불구하고 GetX 4 및 GetX 5 RC 모두 2025년 9월 기준 6개월 넘게 업데이트되고 있지 않으며, GetX 5 RC의 경우 첫 RC 버전이 2023년 2월에 출시되었으니 2년 반이 넘도록 stable 버전으로 업그레이드되고 있지 않다. 최근 이슈란을 보면 이러한 점에 대해 걱정하는 글들이 많이 올라오고 있다.[9]
현재 stable 최신 버전인 GetX 4의 경우 웹에서의 라우팅 관련 버그가 존재한다. 이는 GetX 5 RC 버전을 사용하면 완화된다. GetX 5로의 마이그레이션 가이드(초안)
5.2. BLoC
BLoC(Business Logic Component)은 UI와 비즈니스 로직을 완전히 분리하기 위해 설계되었다. 핵심 개념은 이벤트(Event)와 상태(State) 의 흐름을 통해 앱 로직을 관리하는 것이다. 사용자는 UI에서 이벤트를 발생시키고, BLoC은 그 이벤트를 처리하여 새로운 상태를 UI로 흘려보낸다. 이러한 구조는 단방향 데이터 흐름(Unidirectional Data Flow) 을 보장하기 때문에 예측 가능성과 테스트 용이성이 매우 높다.하위 라이브러리로 Cubit이 있으며, 이는 BLoC보다 단순화된 버전으로 이벤트 클래스를 따로 정의하지 않고 상태만을 관리한다. 그 덕분에 구조는 단순하지만, 명시적인 이벤트-상태 흐름이 필요할 경우에는 여전히 BLoC이 선호된다.
단점으로는 보일러플레이트가 많고, 이벤트·상태 클래스의 수가 많아지는 등 코드량이 상당히 증가한다는 점이 있다. 또한 Stream 기반으로 작동하기 때문에 초심자에게는 진입장벽이 높게 느껴질 수 있다.
그러나 이 구조 덕분에 테스트와 유지보수성이 탁월하여, 대규모 앱이나 여러 팀이 협업하는 프로젝트에서 안정성과 일관성을 보장하기 쉬워 국내외의 중대형 기업들은 BLoC을 주로 선택하는 추세다. 대표적으로 삼성의 Dropship, 쿠팡이츠 사장님/배달 파트너 앱, 라인의 데마에칸, GS의 GS SHOP과 우리동네GS, SPC의 배스킨라빈스, 신세계의 이마트24 등이 있다.
다만 작은 규모의 앱이나 MVP 단계의 프로젝트에서는 오히려 과도한 구조로 느껴질 수 있다. 최근에는 이러한 복잡성을 줄이기 위해 Cubit이나 Flutter Hooks와 조합해 사용하는 사례도 늘고 있다.
5.3. Provider
Provider는 Flutter의 기본 철학인 위젯 트리 기반 상태 전달을 가장 충실히 구현한 상태관리 라이브러리로, InheritedWidget을 기반으로 동작한다. Google 개발자 Rémi Rousselet가 제작하였으며, Flutter의 공식 문서와 예제 코드에서도 오랫동안 기본 상태 관리 도구로 소개되어 왔다.가장 큰 장점은 단순함이다. 별도의 복잡한 구조나 보일러플레이트 없이 ChangeNotifier와 Consumer를 통해 UI를 쉽게 갱신할 수 있다. 또한 다른 패키지와의 호환성도 높고, 개발 생태계가 안정적이다.
하지만 BuildContext를 필수적으로 사용해야 하므로 특정 스코프 바깥에서는 상태에 접근하기 어렵고, 위젯 트리가 깊어질수록 코드 가독성과 유지보수성이 떨어지는 단점이 있다. 특히 Provider 트리의 구조가 복잡해질수록 어디서 어떤 Provider가 생성되고 소비되는지 추적하기가 어렵다.
이러한 구조적 한계를 인식한 제작자는 이후 Riverpod을 새로 개발하게 되었으며, 현재 Provider는 기존 프로젝트 유지보수용 수준으로만 관리되고 있다. 따라서 2020년대 중반 이후 Flutter를 새로 배우는 개발자라면 Provider 대신 Riverpod을 학습하는 것이 추천된다. 그럼에도 불구하고 Provider는 여전히 소규모 프로젝트나 교육용 샘플 코드에서 자주 사용되며, Flutter 초심자에게 상태 관리의 기본 개념을 익히는 데 적합한 패키지로 평가받는다.
5.4. Riverpod
Riverpod은 Provider의 제작자가 만든 차세대 상태관리 라이브러리로, Provider의 구조적 한계를 근본적으로 해결하기 위해 등장했다.이름부터 'Provider'의 애너그램으로, 단순한 후속작이 아니라 전면적인 리디자인에 가깝다.
가장 큰 차이점은 BuildContext에 의존하지 않는다는 점이다. 즉, 위젯 트리의 어느 위치에서도 상태를 안전하게 접근·관리할 수 있으며, 스코프 외부에서도 자유롭게 Provider를 조합할 수 있다. 또한 Riverpod은 컴파일 타임 안전성을 강화하여 Provider 이름이 잘못되었거나 타입이 일치하지 않을 경우 빌드 시점에서 바로 오류를 잡아준다. 이 점은 런타임 오류가 잦은 Provider의 약점을 보완한다.
버전 2 이후에는 Code Generation(코드 생성) 기능이 강화되어 @riverpod 어노테이션 기반의 자동 코드 생성을 지원하고 AsyncNotifier, FutureProvider, StreamProvider 등을 통해 비동기 상태도 효율적으로 관리할 수 있다. 또한 StateNotifier 기반 구조를 사용하기 때문에 테스트 작성이 용이하고 순수 Dart 환경에서도 동작한다는 점이 큰 장점이다.
단점은 Provider에 비해 상대적으로 학습 곡선이 가팔라졌다는 것이다. 상태의 범위(scope), provider 간의 의존 관계, autoDispose 등 개념을 이해해야 하며, IDE 자동완성에 의존하는 경향이 있다. 따라서 간단한 앱이나 프로토타입 수준의 프로젝트에서는 오히려 코드가 복잡해질 수 있다. 그래도 BLoC보다는 학습하기 쉬운 편이다.
Riverpod은 현재 Flutter 커뮤니티에서 가장 빠르게 성장하는 상태 관리 라이브러리 중 하나로, Riverpod으로 점진적 마이그레이션이 진행되는 사례가 많기에 취업 시장에서 BLoC과 더불어 배우면 좋다.
6. 플러터 사용 예시
Official showcaseIt's all widgets, 2022년초 이후 다수의 웹 앱 예제가 제시되고 있다.
7. 외부 링크
유튜브 공식 Flutter 채널Flutter 공식 문서
Flutter SDK 다운로드
Flutter Packages - 플러터 라이브러리 패키지
공식 트위터 - '금주의 위젯' 등 유용한 소식이 업데이트된다.
Reddit FlutterDev
8. 도서
도서관 자료 목록 - 플러터 링크9. 웹 IDE
Flutter SDK를 로컬 PC에 별도 설치하지 않고도 간단한 예제를 웹 브라우저에서 코딩하고 바로 실행시킬 수 있다.DartPad와 Firebase Studio가 있다.
| |
[1] Flutter도 Shorebird를 사용하면 코드 푸시가 되긴 하지만 푸시할 수 있는 코드 변경 범위가 다소 제한적이고 어디까지나 유료 서드파티 패키지인 점이 걸림돌이다.[2] Flutter의 경우 Google이 직접 material과 cupertino 패키지를 업데이트하고 있지만 그 속도가 느린 편이며 Material 3 Expressive와 Liquid Glass와 같은 최신 UI 요소를 바로바로 반영하지 못하고 있다. 또한 cupertino 패키지의 경우 꾸준히 개선되고는 있지만 아직 버그가 꽤 있는 편이다.[3] RN의 Windows 버전과 macOS 버전은 메타가 아니라 마이크로소프트에서 개발 및 유지보수하는 중이다.[4] RN은 JS 브릿지를 사용하는 특성상 일정량의 오버헤드가 생길 수밖에 없다. 하지만 그렇다고 사용자가 충분히 체감할 수 있을 정도의 차이는 아니며, 헤르메스 엔진 채택 등을 통한 꾸준한 성능 향상이 있었으므로 매우 유의미한 성능 차이가 난다고 보기는 어렵다.[5] Github 이슈 중 하나[6] 리눅스 방면에서 쓸만한 GUI 프레임워크들은 접근성이 상당히 낮기에 크로스 플랫폼이 지원되는 Flutter는 리눅스 기반 GUI 개발에서도 상당히 매력적인 선택지다.[7] Backend-as-a-service, 서비스형 백엔드[8] Dart Frog, Serverpod, shelf, Vania 등[9] 이슈 1이슈 2이슈 3이슈 4