Flutter는 Cross-Platform UI Toolkit으로 iOS 혹은 Android와 같은 OS에서 코드를 재사용하는 것과 동시에 Platform Service와 직접적으로 상호작용하여 효율성을 높이는 것이 목적이다.

개발하는 동안, Flutter는 Hot Reload기능을 제공하여 완전한 Compile없이 코드를 실행할 수 있게한다. 배포시에는 Flutter App은 기계어로 Compile된다. (e.g. Intel x64, ARM, JavaScript)

Architectural layers

Flutter는 확장 가능하고 계층적인 시스템으로 설계되었습니다. 각각의 독립된 라이브러리로 구성되어 있으며, 각 라이브러리는 하위 레이어에 종속됩니다. 어떤 레이어도 아래 레이어에 특별한 권한이 없으며, 프레임워크의 모든 부분은 선택적이고 교체 가능하도록 설계되었습니다.

Flutter 애플리케이션은 기본 운영 체제에서 다른 원시 애플리케이션과 동일한 방식으로 패키징됩니다. 플랫폼별 embedder는 진입점을 제공하며, 렌더링 서피스, 접근성, 입력과 같은 서비스에 대한 기본 운영 체제와의 협력을 조정하며, 메시지 이벤트 루프를 관리합니다. Embedder는 해당 플랫폼에 적합한 언어로 작성됩니다. 현재 Android의 경우 Java와 C++, iOS 및 macOS의 경우 Objective-C/Objective-C++, Windows 및 Linux의 경우 C++입니다. Embedder를 사용하여 Flutter 코드는 기존 애플리케이션의 모듈로 통합되거나 코드 자체가 애플리케이션의 전체 내용이 될 수 있습니다. Flutter에는 일반적인 대상 플랫폼을 위한 여러 embedder가 포함되어 있지만, 다른 embedder도 존재합니다.

Flutter의 핵심은 대부분 C++로 작성된 Flutter 엔진입니다. 이 엔진은 모든 Flutter 애플리케이션을 지원하기 위해 필요한 기본 기능을 제공합니다. 엔진은 새로운 프레임을 그릴 때 합성된 장면을 래스터화하는 역할을 담당합니다. 이 엔진은 Flutter의 핵심 API를 낮은 수준에서 구현하며, 이는 iOS에서는 Impeller를 통한 그래픽(향후 Android에서도 지원 예정) 및 다른 플랫폼에서는 Skia를 통한 그래픽, 텍스트 레이아웃, 파일 및 네트워크 I/O, 접근성 지원, 플러그인 아키텍처, Dart 런타임 및 컴파일 도구체인을 포함합니다.

보통 개발자들은 Flutter Framework를 통해서 Flutter를 사용한다.

  • Flutter는 애니메이션, 그리기, 제스처와 같은 빌딩 블록 서비스와 기본적인 Foundation 클래스를 제공합니다. 이러한 서비스와 클래스는 Foundation 기반 위에 일반적으로 사용되는 추상화를 제공합니다.
  • Flutter의 렌더링 레이어는 레이아웃 처리를 위한 추상화를 제공하며, 이를 사용하여 렌더링 가능한 객체의 트리를 구성할 수 있습니다. 이 트리를 동적으로 조작하면 레이아웃이 자동으로 변경되어 변경 사항을 반영합니다.
  • 위젯 레이어는 구성 추상화입니다. 렌더링 레이어의 각 렌더 객체에는 위젯 레이어에서 해당하는 클래스가 있습니다. 이 레이어를 사용하여 재사용할 수 있는 클래스의 조합을 정의할 수 있습니다. 이것은 반응형 프로그래밍 모델이 소개되는 레이어입니다.
  • Material 및 Cupertino 라이브러리는 위젯 레이어의 구성 기본 요소를 사용하여 Material 또는 iOS 디자인 언어를 구현하는 포괄적인 컨트롤 세트를 제공합니다.

Anatomy of an app

Dart App

  • Composes widgets into the desired UI.
  • Implements business logic.
  • Owned by app developer.

Framework (source code)

  • Provides higher-level API to build high-quality apps (for example, widgets, hit-testing, gesture detection, accessibility, text input).
  • Composites the app’s widget tree into a scene.

Engine (source code)

  • Responsible for rasterizing composited scenes.
  • Provides low-level implementation of Flutter’s core APIs (for example, graphics, text layout, Dart runtime).
  • Exposes its functionality to the framework using the dart:ui API.
  • Integrates with a specific platform using the Engine’s Embedder API.

Embedder (source code)

  • Coordinates with the underlying operating system for access to services like rendering surfaces, accessibility, and input.
  • Manages the event loop.
  • Exposes platform-specific API to integrate the Embedder into apps.

Runner

  • Composes the pieces exposed by the platform-specific API of the Embedder into an app package runnable on the target platform.
  • Part of app template generated by flutter create, owned by app developer.

Reactive user interfaces

Flutter는 반응형, 선언적 UI 프레임워크로, 개발자는 애플리케이션 상태와 인터페이스 상태 간의 매핑을 제공하고, 프레임워크가 애플리케이션 상태 변경 시 인터페이스를 런타임에서 업데이트하는 작업을 담당한다. 이 모델은 Facebook의 React 프레임워크에서 영감을 받았으며, 많은 전통적인 디자인 원칙을 재고했다.

대부분의 전통적인 UI 프레임워크에서는 사용자 인터페이스의 초기 상태를 한 번 설명한 다음, 이벤트에 대한 사용자 코드에 따라 런타임에서 별도로 업데이트된다. 이 방식의 한 가지 문제는 애플리케이션이 복잡해질수록 개발자가 상태 변경이 전체 UI에 걸쳐 어떻게 전파되는지 알아야 한다는 것이다.

위의 예시를 보면, 상태는 색상 상자, 색상 슬라이더, 라디오 버튼과 같은 여러 곳에서 변경될 수 있다. 사용자가 UI와 상호 작용하면 변경 사항은 다른 모든 곳에 반영되어야 한다. 더 나쁜 점은, 심지어 신중하지 않으면 사용자 인터페이스의 일부를 작은 변경하더라도 seemingly unrelated한 코드 조각에 ripple 효과를 일으킬 수 있다는 것이다.

이 문제에 대한 한 가지 해결책은 MVC와 같은 접근 방식으로, 데이터 변경을 컨트롤러를 통해 모델로 전달하고, 모델이 컨트롤러를 통해 새로운 상태를 뷰로 전달하는 것이다. 그러나 이것도 문제가 될 수 있으며, UI 요소의 생성 및 업데이트는 서로 다른 두 단계이며 동기화가 어려울 수 있다.

Flutter는 다른 반응형 프레임워크와 함께 이 문제에 대한 대안적인 접근 방식을 취하여 사용자 인터페이스를 기반으로한 상태와 명시적으로 분리한다. React 스타일의 API를 사용하여 UI 설명만 작성하면, 프레임워크가 해당 구성을 사용하여 사용자 인터페이스를 생성하고/또는 업데이트하는 작업을 처리한다.

Flutter에서 위젯(React의 컴포넌트와 유사)은 변경할 수 없는 클래스로 표현되며, 객체 트리를 구성하는 데 사용된다. 이 위젯은 레이아웃을 위해 별도의 객체 트리를 관리하고, 이를 통해 compositing을 위한 별도의 객체 트리를 관리한다. Flutter는 핵심적으로 변경된 트리의 부분을 효율적으로 탐색하고, 객체 트리를 하위 수준 객체 트리로 변환하고, 이러한 트리 간의 변경 사항을 전파하기 위한 메커니즘의 시리즈이다.

위젯은 build() 메서드를 오버라이딩하여 사용자 인터페이스를 선언한다. 이 메서드는 상태를 UI로 변환하는 함수이다.

build() 메서드는 의도적으로 빠르게 실행되어 부작용이 없어야 하며, 렌더링 된 프레임마다 한 번씩 호출될 수 있도록 프레임워크에서 호출될 수 있도록 설계되었다.

이 접근 방식은 언어 런타임의 특정한 특성(특히, 빠른 객체 인스턴스화 및 삭제)에 의존한다. 다행히도 Dart는 이 작업에 특히 적합하다.

# References

  1. Flutter architectural overview