10일간의 플러터 챌린지에 참여하게 되었다. 나 플러터 하나도 모른다. 뭐부터 시작해야 할지 전혀 모르겠지만, 문제에서 요구하는 사항들을 천천히 구현하다 보면 좀 익숙해지지 않을까 싶다.
플러터를 배우기에 앞서 dart 언어에 대한 강의를 좀 봤다.
C++, JavaScript를 다뤄봐서 그런지 그렇게 어렵거나 튀는 내용은 없었던 것으로 기억한다.
플러터는 크로스 플랫폼 프레임워크로만 알고 있었다. 구글에서 개발했고, 자체적으로 UI를 그리는 엔진을 사용하여 다양한 플랫폼에서 화면을 그려낼 수 있다고 들었다.
💡 네이티브 앱 vs. 크로스 플랫폼 앱
네이티브 앱
iOS와 같은 특정 플랫폼을 위한 소프트웨어를 만드는 것을 네이티브 앱 개발이라고 한다. 즉, 해당 네이티브 디바이스 기능에 대한 전체 액세스 권한을 가지며, 해당 플랫폼의 여러 기능과 UI를 사용할 수 있다. 때문에 일반적으로 크로스 플랫폼 앱에 비해 더 높은 성능과 속도를 가진다. 하지만 하나의 플랫폼밖에 지원하지 않기 때문에 여러 플랫폼에서 일관된 사용자 경험을 제공하기 쉽지 않다.
크로스 플랫폼 앱
크로스 플랫폼 앱은 단일 코드를 베이스로 여러 플랫폼을 위한 소프트웨어를 개발하는 것을 말한다. 하나의 프로그래밍 언어와 코드로 다양한 플랫폼을 위한 애플리케이션을 구축할 수 있기 때문에 네이티브 앱 개발보다 비용과 시간의 적게 들고, 여러 플랫폼에서 일관된 사용자 경험을 제공할 수 있다. 하지만 네이티브 디바이스 기능 사용이 제한된다는 단점이 있다.
그러면 이제 플러터가 도대체 어떻게 크로스 플랫폼을 지원하는지가 궁금해진다. 봐도 잘 모르겠지만, 플러터의 아키텍처를 한번 살펴보자.
그림을 보면 크게 세 개의 레이어로 이뤄져 있다. Dart는 코드가 있는 부분인 것 같다는 생각이 들고, 나머지 둘은 잘 모르겠다. 그래서 문서를 한번 찬찬히 읽어봤다.
위의 그림을 보면 Dart로 작성된 코드를 C/C++로 이루어진 플러터 엔진이 해석하여 렌더링이 이뤄진다. 코드를 네이티브 디바이스가 직접 해석하고 렌더링 해주는 것이 아니라, 플러터 엔진이 직접 코드를 해석해서 화면을 그려준다. 때문에 플러터는 하나의 빈 캔버스로 비유되기도 한다.
더 자세한 내용은 공식문서를 참고!
--> How does Flutter run my code?
--> Flutter architectural overview
--> Flutter System Architecture
플러터에는 세 가지 트리가 존재한다.
코드로 작성된 위젯을 트리로 나타낸 것이다. immutable한 속성을 가지고 있다. Widget Tree는 Element Tree와 1대 1로 연결되어 있다.
Widget Tree의 상태를 관리하고, Render Tree의 생명주기를 관리한다.
위에서 말했듯이 Widget Tree는 immutable한 속성을 가지고 있기 때문에, 상태를 관리할 트리가 필요하다. 때문에 플러터 프레임워크는 createElement() 메서드를 사용하여 Element Tree를 생성한다. 일반적으로 Stateful Widget을 사용할 때 저장되는 상태가 이 상태를 의미한다.
UI를 그리기 위해 참조하는 트리다. 플러터 프레임워크는 Element Tree에 있는 모든 요소들에 대해 createRenderObject() 메서드로 RenderObject를 생성한다. 때문에 Renter Tree를 다시 생성하는 것은 비용이 많이 든다. 이를 방지하기 위해 react와 비슷하게 위젯에 Key를 사용하여 같은 위젯인지 비교하기도 한다.
처음에는 플러터 공식 문서를 보고 따라 했었다. 하지만~ flutter 폴더가 현재 위치에 냅다 생성되더니... 이것저것 경로를 설정해 줘야 하더라. 그래서 그냥 삭제하고 homebrew를 사용해서 설치하기로 했다.
brew install --cask flutter
위 명령어로 flutter를 설치해준다.
flutter doctor
그리고 위 명령어를 실행하면 플러터와 각종 시뮬레이터에 대한 정보를 볼 수 있다.
나는 VSCode를 사용하고 있기 때문에, dart와 flutter를 위한 확장 프로그램들을 깔아줬다.
그리고 처음에 플러터를 깔았다가 삭제해서 그런지 flutterSDK 경로가 잘못됐다는 문구가 자꾸 떴었는데, settings.json
에서 다음과 같이 경로를 바꿔줬다.
{
"dart.flutterSdkPath": "/opt/homebrew/Caskroom/flutter/3.16.0/flutter/bin",
}
cmd
+ shift
+ p
에서 "Add Flutter SDK to PATH" 로 설정할 수도 있다.
하나의 시뮬레이터만 사용해도 된다고 하여 Android는 제쳐두고 iOS를 쓰기로 했다. XCode를 설치해야 iOS 시뮬레이터를 사용할 수 있다. 나는 그냥 App Store에서 깔았다.
💡 시뮬레이터(Simulator) vs.에뮬레이터(Emulator)
깔고 나서 flutter doctor
를 실행해 보면 아래와 같이 뜬다.
CocoaPods를 설치해야 한단다. 그게 뭔데? 공식 문서에는 다음과 같이 쓰여있다.
CocoaPods is a dependency manager for Swift and Objective-C Cocoa projects. It has over 98 thousand libraries and is used in over 3 million apps. CocoaPods can help you scale your projects elegantly.
해석해 보자면, CocoaPods는 의존성을 관리해 주는 매니저다. Flutter는 iOS 애플리케이션을 빌드하고 Xcode에서 실행하는 데 사용되는 플랫폼이지만, 앱의 종속성 및 패키지 관리에는 CocoaPods가 사용된다고 한다.
그래서? 설치해 줬다.
sudo gem install cocoapods
근데?! 마지막에 에러가 떴다.
루비 버전 관련 오류인 것 같은데, 시키는 대로 해줬다.
sudo gem install drb -v 2.0.5
drb install을 해주고 다시 시도해도 아래와 같은 오류가 떴다.
sudo gem install activesupport -v 6.1.7.6
시키는 대로 activesupport를 설치하고 나니 정상적으로 CocoaPods가 설치되었다. flutter doctor
로 현재 상태를 다시 확인해 봤다.
와우와우와우~~! Xcode가 정상적으로 연결되었다. 이제 VSCode에서 시뮬레이터로 iOS를 설정해 주면 된다.
프로젝트 생성은 쉽다.
flutter create [프로젝트 이름]
위의 명령어를 입력하면 바로 만들어진다. 생성된 프로젝트 폴더에 들어가 보면 lib
라는 폴더가 있는데, 그 폴더에 추가적인 폴더를 만들어서 이번 FlutterBoot 코드들을 작성하기로 했다.
디버그 모드에서 플러터는 가상 머신을 사용하여 코드를 실행한다. 이는 "stateful hot reload"를 활성화하기 위함으로, 재컴파일 없이 실행 중인 코드를 변경할 수 있다.
사실 나는 아직 iOS 시뮬레이터를 완벽하게 연결하지 못했다. VSCode에 iOS 시뮬레이터가 뜨긴 하는데, 사용하려고 누르면 자꾸 에러가 난다. 아쉽지만 나에겐 시간이 없기 때문에 고치는 건 다음으로 미루고 당장 사용할 수 있는 Chrome을 사용하기로 했다.
위 이미지 처럼 Chrome 시뮬레이터를 설정하고, 코드를 디버그 모드로 실행하면 이렇게 크롬 창이 뜬다.
오늘은 0일차인데, warm up 문제를 주셨다. 숫자의 increment/decrement가 가능한 counter를 만드는 간단한 문제였다. dragger를 사용하는 심화 문제도 풀어보고 싶었지만, 익숙하지 않다 보니 기본 문제를 푸는데도 시간이 오래 걸려서 심화 문제까지는 도달하지 못했다...
https://aws.amazon.com/ko/what-is/flutter/
https://flutter-ko.dev/resources/faq#run-android