Flutter 입문기 및 학습내용 리뷰

yu minwoo·2024년 3월 18일
0
post-thumbnail

React Native 개발을 하다보면 본의 아니게 듣게 되는 프레임워크가 바로 Flutter일 것 같다. 사실 나도 React Native 개발을 하고 있지만 오랫동안 Flutter의 고도화에 대한 의구심을 가지고 있었던 만큼 본격적으로 Flutter를 공부하기에는 좀 조심스러웠다. 하지만 지금 이 상황이 Flutter를 한번 공부해볼 수 있겠다는 생각이 들어 온라인 강의를 통해 Flutter를 학습한 후기를 남겨보고자 한다.

Flutter?

Flutter는 React-Native와 같이 안드로이드와 iOS앱을 하나의 언어를 사용해 동시에 개발할 수 있는 또 하나의 크로스 플랫폼 프레임워크이다. React-Native가 페이스북(현 메타)에서 개발했다면, Flutter는 구글에서 개발했다. 그리고 지금 현재는 React-Native와 함께 크로스 프레임워크의 양대 산맥을 이루고 있다!! 메인언어는 구글이 자체 개발한 Dart라는 언어를 사용한다.

왜 Flutter 입문을 고민했나?

지금까지 구글이 벌려온 선례들로 인해 구글을 믿을 수가 없어서가 가장 컸다. 지난 십몇년 동안 구글이 정말 많은 기술들을 개발해놓고 폐기해버린 선례가 한둘이 아닌 만큼 Flutter도 그러지 말란 법이 없기 때문에 본격적인 입문에 조심스러웠다. 하지만 지금은 Flutter가 출시한지 7년의 시간이 흘렀고, 구글이 Flutter를 적극적으로 고도화하고 있고 이를 매년 구글io를 통해 공개한다는 것이 인상 깊었던거 같다. 특히 React Native 개발을 하는 입장에서 Flutter가 컴파일 성능에 있어서 React Native와는 비교가 안된다는 것을 알게되면서 Flutter를 공부해보자라고 마음을 먹은 것 같다.

사실 개인적인 Flutter 학습이 처음은 아니다.

사실 이 후기를 남기기 한 1년 전에도 Flutter를 책을 사서 공부한 적이 있다. 하지만 당시에 업무때문에 바쁘기도 했고, 또 학점은행제, 사이드 프로젝트... 이런 것들을 하면서 개인적으로 공부할 여력이 없어서 중간에 접었었다. 그리고 또 책에서는 Dart에 대한 기본 개념 내용이 많이 없기도 하고 책보다는 온라인 강의가 더 잘 맞는 거 같아서 노마드 코더에서 Dart 기본 개념 강의를 수강한 다음 Flutter 개념강의를 수강하는 방법으로 학습을 진행했다. 그리고 수강한 강의 내용은 노션에 적어가면서 기록하는 방식으로 진행했다.
역시나 책보다는 영상이 잘 맞았는지 Flutter 기본 개념강의는 수강 신청하고 거의 한 나흘만에 모든 강의를 다 들은 것 같다.

Flutter의 기본 동작 원리

안드로이드, iOS와 같은 네이티브 프레임워크는 운영체제와 직접적으로 대화하면서 "버튼 만들어줘", "textinput" 만들어줘 와 같은 기능들을 수행하게 된다. 이는 React Native도 마찬가지다.

하지만 Flutter의 경우 운영체제와 직접적으로 대화하는 방식이 아니다. Flutter의 동작 원리를 보면 약간 "비디오 게임 엔진"처럼 동작한다고 할 수 있다. (Unity를 사용해봤으면 쉽게 이해할 수 있다.)

Flutter 아키텍처 레이아웃


Flutter는 Flutter 프레임워크 안에 Material, Cupertino, Widgets, Animation, Painting, Gestures 등 많은 요소들을 포함하고 있지만, 이것들이 실제로 출력될 때는 운영체제와 직접 대화하는 방식이 아니다. 대신 C와 C++로 개발된 Flutter 엔진을 사용해 UI를 그리게 된다. 이 때문에 Flutter 앱은 플랫폼의 Native Widget을 사용하지 않는다. 운영체제가 담당하는 기존 방식과는 달리 Flutter 엔진에서 픽셀 단위의 모든 UI들을 그려나가기 때문이다.

문제는 이러한 점 때문에 안드로이드와 iOS 등 운영체제에서 제공하는 Alert나 DatePicker와 같은 기능들의 UI를 사용할 수가 없다. 이것들은 전부 운영체제에서 그려주는 것들인데 Flutter는 모든 UI를 Flutter 엔진이 그리게 되는 만큼 구조적으로 불가능한것이다. 따라서 Flutter에서 Material UI(안드로이드 디자인 시스템)와 Cupertino UI(애플 디자인 시스템)를 제공한다고 해도, 그것들은 운영체제에서 그려진게 아니기 때문에 진짜가 아니다.

하지만 이러한 점으로 인해 Flutter를 통해서 통제할 수 있는 것이 많다는 장점도 있다. Flutter가 Navigation, 애니메이션 등 모든 것을 통제할 수 있는 이유는 Flutter 엔진을 통해 화면상의 모든 픽셀을 제어하기 때문에 운영체제의 영향에서 상대적으로 자유롭다. 그래서 React Native보다 구현할 수 있는 애니메이션이 훨씬 많고 성능도 좋다.

그러면 이제까지 Flutter 엔진에 대해서 이야기를 했다. 그러면 각 운영체제에서 Flutter 엔진을 어떻게 실행할까? 이 역할을 Embedder에서 하게 된다. Embedder는 운영체제 상에서 Flutter 엔진을 가동하는 역할을 하고 운영체제(iOS, Android, 맥 OS, 윈도우, 리눅스 등) 맞게 다양한 Embedder가 존재한다!

Flutter vs React Native

그럼 나 처럼 React Native 개발자라면 이런 의문이 들 수 있다. 어떤 상황에서 Flutter를 사용하면 좋고, React Native를 사용하면 좋을까?

Flutter

  • 아주 세밀한 디자인 요구사항이 포함된 경우
  • 요소들이나 애니메이션들을 모두 커스터마이징해야 하는 경우

React Native

  • 네이티브 운영체제 상에서 제공하는 순정 UI를 사용하고자 할 때
  • 아주 세밀한 디자인 요구사항이 요구되지 않는 경우

예를 들어서, 토스 또는 당근과 같이 자체적인 디자인 시스템을 사용하고자 하는 경우에는 React Native보다는 Flutter를 사용하는게 유리할 수 있다.

실제 토스, 당근의 경우 채용공고 내용과 실제 앱 세부기능으로 보아 네이티브로 개발했을 가능성이 높아보인다.

기본 사용 환경: VSCode

Flutter도 React Native와 같이 기본적으로 VSCode를 사용하게 된다. 그리고 강의에서 알려준 대로 VSCode에 "Flutter", "Dart" 익스텐션을 설치해서 사용하니 기존에 React Native에서 디버그 실행하는 것보다 훨씬 더 편하게 개발할 수 있었다.

VSCode에서 거의 모든걸 제공해준다

이번에 Flutter에 입문하면서 가장 인상 깊었던 점을 꼽자면 React-Native와 달리 VSCode에서 개발 시 사용하게 되는 대부분을 실행할 수 있다는 것이었다. 시뮬레이터 실행, 디버그 모드 실행 등을 React-Native에서는 터미널로 실행하거나 Xcode를 직접 켜서 실행해야 하거나 했는데 이런 것들을 익스텐션만 설치하면 VSCode에서 실행할 수 있다. VSCode 하단에 아래와 같은 버튼이 나타나게 되는데

이 버튼을 클릭하면 아래와 같은 창이 열리면서 안드로이드 에뮬레이터, iOS 시뮬레이터를 바로 실행할 수 있다.

그리고 터미널에 디버그 실행 명령어를 실행할 필요 없이 시뮬레이터를 실행하고 이 버튼만 클릭하면 바로 디버그로 실행할 수 있었다.

Flutter 학습내용 정리

1. Widget?

Widget은 예시를 들자면 "레고 블록"과 같다. Flutter의 모든 것은 Widget으로 구성되어 있고, 쉽게 생각하면 레고 블록을 조립한다고 생각하면 된다. 즉, Flutter는 수많은 Widget을 합치는 방법으로 개발하는 방법인 것이다. React-Native로 생각하면 "컴포넌트"와 비슷하다.

주의
안드로이드, iOS 운영체제에서 폰 바탕화면에 나타나는 그 위젯과는 전혀 다르다!!!!

Widget은 그 개수가 정말 많다. 그리고 Flutter 커뮤니티에서 개발한 공식 Widget도 그 개수가 정말 많다. 즉, UI를 그리기 위한 수많은 다양한 기능들을 Flutter 커뮤니티에서 공식 지원받을 수 있다.

코드의 관점에서 Widget을 바라보면 그 형태는 "클래스"와 같다.

import 'package:flutter/material.dart';

void main() {
  runApp(App());
}

class App {

}

이렇게만 놓고 보면 Widget이 아니고 단순 클래스만 선언한 것이다. 이 클래스를 Widget으로 만들기 위해서는 Flutter SDK에서 제공하는 Core Widget(StatelessWidget, StatefulWidget 등) 중 하나를 상속받으면 그 클래스는 Widget이 된다.

import 'package:flutter/material.dart';

void main() {
  runApp(App());
}

class App extends StatelessWidget {
  const App({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      ...
    );
  }
}

2. Root Widget은 return 해야 하는 Widget이 정해져있다.

Widget을 선언할 때 보통은 어떤 Widget을 return해도 상관없지만, 최상위에 속하는 Root Widget은 반드시 MaterialApp 또는 CupertinoApp Widget을 return해줘야 한다. 여기에서 material은 구글의 디자인 시스템이고, cupertino는 애플의 디자인 시스템을 말하는데, 만약 구글 또는 애플 그 어느 디자인 시스템의 느낌을 살리지 않고 나만의 UI를 만들고자 하는 경우에도 Root는 둘 중 하나를 반드시 return해줘야 한다. 놀랄 일은 아니지만 Flutter는 구글이 개발했기 때문에 MaterialApp을 적용하는게 가장 자연스럽다. 그래서 보통은 MaterialApp을 많이 연결하지만 앱에서 material 디자인 시스템의 느낌이 사라지는 데는 그리 오랜 시간이 걸리지 않는다.

3. StatefulWidget

  • StatelessWidget: build 메서드를 통해 UI만 출력함
  • StatefulWidget: 상태값을 가지고 있는 Widget. 상태에 따라 데이터가 변경될 때 이 변화를 UI에 반영하여 실시간으로 보고 싶을 때 사용한다.

React-Native 개발을 하다보면 햇갈릴 수 있는게, 컴포넌트는 상태(State)가 곧 전부이기 때문에 컴포넌트의 UI 렌더링은 모두 State에 좌우되지만, Flutter는 그렇지 않다.

StatefulWidget의 코드 구조

import 'package:flutter/material.dart';
import 'package:toonflix_flutter_ex/widgets/button.dart';
import 'package:toonflix_flutter_ex/widgets/currency_card.dart';

void main() {
  runApp(const App());
}

class App extends StatefulWidget {
  const App({super.key});

  
  State<App> createState() => _AppState();
}

class _AppState extends State<App> {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
          backgroundColor: const Color(0xFF181818),
          body: SingleChildScrollView(
            child: Padding(
              //padding: EdgeInsets.all(10),
              //padding: EdgeInsets.only(left: 
							...

보이는 것 처럼 StatefulWidget은 아주 작은 크기의 코드이고, 단순히 State라고 불리는 클래스를 하나 가지고 있을 뿐이다. 그리고 State는 우리가 UI를 구축하는 곳이고 이 상태는 아주 특별하다. 그 이유는 우리가 State를 바꿀 때 우리의 UI는 새로고침되면서 최신 데이터를 보여주기 때문이다.

상태를 선언할 때는 State 클래스 내부에 변수를 추가하고 setState 함수 안에 어떻게 변수값을 변경할 건지를 작성하면 그 대로 값이 변경된다. 그 안에서 변경하지 않은 경우 값은 변경되지만 UI가 새로고침이 발생하지 않는다.

참고
강의에서는 예시를 들기 위해 setState를 많이 사용했지만, 실제로는 Flutter에서 state를 사용하는 경우는 많이 없다고 한다. state를 사용하지 않더라도 더 멋지고 좋은 Widget을 사용해서 반응형이나 인터렉티브를 처리하는 경우가 많기 때문이다.

4. BuildContext

Flutter는 앱 내의 모든 스타일을 한 곳에서 지정할 수 있는 기능을 제공한다. 만약 하위 페이지에서 타이틀, 공통적인 스타일이 필요되는 부분이 있을 때 그 때 BuildContext를 사용하게 된다.

최상위 Widget에 아래와 같이 theme 값을 추가하고

  
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        textTheme: const TextTheme(
          titleLarge: TextStyle(
            color: Colors.red,
          ),
        ),
      ),
      home: const Scaffold(
        backgroundColor: Color(0xFFF4EDDB),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              MyLargeTitle(),
            ],
          ),
        ),
      ),
    );
  }

사용하고자 하는 부분에서는 아래와 같이 사용하면 된다.

class MyLargeTitle extends StatelessWidget {
  const MyLargeTitle({
    super.key,
  });

  
  Widget build(BuildContext context) {
    return Text(
      'My Large Title',
      style: TextStyle(
        fontSize: 30,
        color: Theme.of(context).textTheme.titleLarge?.color, // 이 부분
      ),
    );
  }
}

느낀 점

지금까지 내가 개발을 해왔던 것을 되돌아보면 기획, 디자인 등 다양한 파트의 사람들과 논의를 하면서 디자이너가 서비스의 특징을 잘 녹여낸 UI를 제공해줘도 React Native의 기술적인 한계로 인해 일부 UI를 구현하지 못했던 적이 많았던 거 같다. 그리고 기획팀에서 이 부분에 대해 애니메이션을 넣어달라고 하면 애니메이션으로 인해 메모리 이슈가 발생한 적이 많았다 보니 어쩔 수 없이 거절할 수 밖에 없었던 점이 지금까지도 아쉽기만 했는데, Flutter에서는 운영체제의 제약을 받지 않고 원하는 UI를 그릴수 있고 원하는 애니메이션을 쉽게 구현할 수 있다는 것에 많이 놀라울 따름이었다.
특히 요즘에는 운영체제 UI가 아닌 자신들만의 디자인 언어를 만들어가면서 서비스의 특징을 사용자에게 온전하게 보여주고자 하는게 요즘의 트랜드라는 점을 볼때 네이티브 개발 방식을 제외하면 Flutter가 쉬운 대안이 될 수 있다고 생각한다.
하지만 장점도 있으면 단점도 있는 법이다. 사실 주변에서 React Native와 Flutter 둘 중 어느것이 좋냐는 질문을 받으면 나는 "잘 모르겠다"라고 대답했다. 그 이유는 React Native와 Flutter에서 기술적으로 구현할 수 있는 것에 대해 장단점이 너무 명확하게 갈린다고 생각했고 지금도 그렇다고 생각하기 때문이다.
하지만 현재까지 구글의 행보를 볼때 Flutter만큼은 앞으로도 쭉 가져갈 생각이 있다는 것을 구글IO를 통해 느꼈고 언젠가는 지금의 단점이 많이 보완될 것이라고 생각한다. 그래서 나도 올해부터는 구글IO를 시청하면서 Firebase 강의만 시청하지 않고 Flutter 강의도 시청하면서 이걸 블로그에 기록으로 남기려고 한다.

0개의 댓글