귀하는 로그인되어 있지 않습니다. 이대로 편집하면 귀하의 IP 주소가 편집 기록에 남게 됩니다.스팸 방지 검사입니다. 이것을 입력하지 마세요!==특징== ===기기에 독립된 사용자 인터페이스=== 지금까지 모바일을 겨냥한 [[크로스 플랫폼]] [[프레임워크]]는 [[아파치 코르도바]]처럼 웹 뷰를 사용하되 여기에 사용되는 자원을 각 기기에 미리 심는 방식, 즉 앱이 로컬 웹 서버로 돌아가도록 해서 웹 앱보다는 빠르고 OS 관계 없이 똑같은 인터페이스를 제공하거나<ref>하지만 운영체제의 기본 웹브라우저를 사용하므로 웹브라우저에 따라 모양이 좀 다를 수는 있다.</ref>, 리액트 네이티브나 [[자마린]]처럼 각 OS의 네이티브 기능을 최대한 활용해서 인터페이스는 조금 차이가 나지만 빠른 속도를 추구하는 방법이 있는데, Flutter는 이들 둘과는 아예 다르다. 각 OS의 네이티브 그래픽 기능을 최대한 활용하되 각 OS의 유저 인터페이스를 무시하고 몽땅 Flutter가 자체 제공한다. 즉, 각 OS는 그림 그릴 캔버스만 제공하고 그 위에 뭘 표현할지는 Flutter의 렌더링 엔진인 Skia<ref>Skia는 Flutter의 전유물은 아니다. 별도의 프로젝트로 운영하고 있으며, 크롬, 크롬OS, 안드로이드도 사용하고 있으며 구글 바깥에서도 파이어폭스, [[리브레오피스]] 같은 소프트웨어가 그래픽 렌더링에 Skia 엔진을 사용하고 있다.</ref>가 다 그려버리는 것. 그 때문에 OS에 관계 없이 똑같은 모습의 유저 인터페이스를 제공한다. Flutter는 두 가지 인터페이스 디자인을 기본 제공한다. OS에 따라 디자인을 달리 하는 것도 가능해서 안드로이드에서는 머티리얼, iOS에서는 쿠퍼티노 인터페이스<ref>[[애플]]이 아니라 [[구글]]에서 자사의 머티리얼 디자인과 구별하기 위해 붙인 이름이다. 애플 폰사가 쿠퍼티노에 있기 때문에 이런 이름을 붙였다.</ref> 를 사용하는 식으로 할 수도 있고 그 반대로도 할 수 있다! 같은 앱에서 입맛에 맞게 어떤 부분은 머티리얼, 어떤 부분은 쿠퍼티노 디자인을 적용할 수도 있다. 다만, 똑같은 기능을 하는 인터페이스라고 해도 모양이나 크기가 다를 수 있으므로 이를 감안해야 한다. 네이티브 UI를 활용하는 것에 비해서 속도 면에서 불리하지 않은가 싶을 수 있는데 테스트 결과를 보면 상당히 준수하게 나온다. 렌더링 엔진인 Skia는 [[C++]]로 구현했는데 최적화를 무척 잘 했는지 성능이 아주 좋다. 그리고 지금도 계속 최적화를 하고 있어서 업데이트 될 때마다 어느 정도나 성능을 향상시켰는지 공지한다. 다만 Flutter 웹은 [[HTML]]와 CSS, [[자바스크립트]]<ref>Flutter가 나오기 전부터 [[Dart]]는 [[자바스크립트]]로 컴파일할 수 있는 기능을 제공했다.</ref>를 사용한다. 이쪽은 이 두 가지만 가지고도 어지간히 다 할 수 있기도 하고<ref>아파치 코르도바가 내장한 [[HTML]]을 UI에 사용하는 방식으로 크로스 플랫폼 모바일 앱을 구현할만큼 HTML과 CSS만 있으면 웬만한 UI는 다 구현할 수 있다.</ref> 웹 표준을 무시하면 매장당하는 문제도 있다. Flutter를 웹 개발에 쓰면 사실상 [[HTML]]나 CSS 코딩 없이 [[Dart]]만으로 다 만들 수 있다.<ref>애초에 Flutter의 구조가 웹 구조에 힌트를 얻은 것이기도 하다. [[자바]] 기반 아파치 위켓 웹 [[프레임워크]]는 모든 것을 위젯으로 보고 모든 구성요소를 위젯 트리 구조로 구성하며, [[XML]] 같은 것을 쓰지 않고 UI도 코드로 몽땅 처리하는 데다가 stateless와 stateful 개념을 가지고 있어서 많은 면에서 Flutter와 닮아 있다.</ref> ===핫 리로드=== 핫 리로드(Hot Reload) 기능을 제공하여 코드가 변경된 부분이 바로바로 디버그 모드의 앱에 반영되는 것도 특징이다. 네이티브도 코드가 변경되었을 때 전체 컴파일 및 패키징 없이도 변경 내용을 반영하는 기능이 있지만 Flutter의 핫 리로드는 이보다 훨씬 빠르고 간편하다. 위젯의 속성을 바꾸고 나서 그게 어떤 모양으로 보이는지 아주 간단하하게 확인해 볼 수 있기 때문이다. 뭐 하나 바꿀 때마다 다시 컴파일하고 실행하는 것과는 비교도 안 되게 빠르고 편리하다. 특히 재실행이 아니라, 실행 상태를 유지하면서 코드를 바꾼 내용만 반영해 주기 때문에 위젯의 디버깅에 큰 이점을 가진다. 애초에 Flutter 설계 때부터 이 기능을 염두에 두었다고 한다. 정확하게는 [[Dart]] 가상머신이 제공하는 기능이다. 다만 핫 리로드로 바로 변경이 적용되는 부분은 위젯을 그리는 부분, 특히 Widget.build() 메서드 안에 있는 코드이며<ref>build() 메서드 안에서 다른 메서드나 함수를 불렀다면 이것도 해당된다.</ref>, 조건에 따라 완벽하게 올바른 실행을 보장하지는 않기 때문에 코드가 문제가 없는데도 오류가 나거나 이상하게 동작할 수 있다. 핫 리스타트도 엄청나게 편리한 기능인데, 1초 정도면 되는 핫 리로드에 비하면 길지만 4~5초 정도면 재실행이 되므로 코드 한 번 고칠 때마다 다시 컴파일해서 실행시키려면 분 단위로 기다려야 했던 앱 개발 환경과 비교해 보면 정말 눈물날 정도로 순식간이다. 핫 리로드는 현재의 데이터가 초기화되지 않는다. 즉 위젯이 가진 속성값을 변경시키고 나서 핫 리로드를 했다면 변경된 값이 그대로 유지된다. 반면 핫 리스타는 모든 값이 초기화된다. 만약 여러 페이지로 된 앱을 첫 페이지에서 다른 페이지로 넘어간 상태에서 핫 리로드를 했다면 넘어간 페이지를 그대로 유지하지만 핫 리스타트는 첫 페이지로 돌아간다. 핫 리로드는 현재의 실행 상태를 유지한 채로 프로그래머가 위젯을 변경한 부분만 업데이트해 주며, 핫 리스타트는 앱을 재실행하는 것으로 볼 수 있다. 핫 리로드를 했을 때 오류가 나거나 코드는 바꿨는데 생각과는 달리 외관이나 동작이 달라지지 않았다면 핫 리로드가 아닌 핫 리스타트로 재실행을 시켜보는 게 좋다. 핫 리로드나 핫 리스타트 둘 다 기존의 재실행 방법에 비해서 눈물날 정도로 빠르기 때문에 앱 개발 기간을 엄청나게 단축시켜 준다. 경우에 따라서는 핫 리스타트를 해도 계속 나는 오류가 있어서 다시 빌드가 필요할 수도 있다. 예를 들어 패키지를 새로 설치했거나 지웠을 때라든가 이미지, 폰트와 같은 자산(asset)을 추가했을 때와 같이 pubspec.yaml 파일을 변경했다면 이를 반영하기 위해서는 다시 빌드해야 한다. 핫 리로드나 핫 리스타트는 기기의 접속을 끊으면 변경된 내용이 반영되지 않으므로 변경된 내용을 기기에 완전히 심기 위해서는 실행을 중단시킨 다음 다시 컴파일해서 실행시키거나 프로파일 모드 또는 릴리즈 모드로 실행시켜야 한다. 참고로 프로파일 모드는 디버깅 정보가 그대로 다 뜨지는 않지만 앱 성능 측정과 로깅 기능은 유지하는 모드로, 릴리즈 모드에 준하는 속도를 내면서도 디버깅에 일부 도움을 받을 수 있다. 웹용 Flutter는 아직 핫 리로드는 지원하고 있지 않으며, 핫 리스타트만 지원한다. ===위젯=== Flutter에서는 모든 요소가 위젯(Widget)이다. 페이지조차도 위젯이다. 심지어는 아예 가장 기본이 되는 App 클래스<ref>App 클래스 객체를 main() 함수에서 runApp() 함수 매개변수로 전달하는 것이 모든 Flutter 앱의 시작 지점이다.</ref> 조차도 StatelessWidget 클래스에서 상속 받는다! 대부분의 위젯은 child, 또는 children 속성으로 자식 위젯을 품을 수 있다. 따라서 Flutter의 UI는 위젯의 트리 구조다. 위젯은 상태 변화가 없는 Stateless Widget과 상태 변화를 감지하는 Stateful Widget 두 가지로 나뉜다. 중요한 것은 위젯 자체는 stateless든 stateful이든 불변(immutable)이다. 따라서 위젯 안의 모든 속성은 final이어야 하며<ref>그런데 final이 아닌 필드가 있어도 컴파일을 하면 경고 메시지는 뿜어내지만 빌드가 되긴 된다. 다만 제대로 동작할지는 보장할 수 없다.</ref>, 위젯을 업데이트할 수 있는 메서드 같은 것은 제공하지 않는다. 만약 위젯이 어떤 텍스트를 출력하고 있고, 그 텍스트가 바뀌어야 한다면 안드로이드나 iOS 네이티브로 계산할 때에는 그 위젯<ref>아마 안드로이드나 iOS는 각자 그에 해당하는 다른 이름을 쓸 것이다.</ref>의 setText() 메서드를 호출한다든가 해서 매개변수로 새 텍스트를 넘겨주는 식으로 텍스트를 바꿀 것이다. 즉 명령을 통해 인터페이스를 업데이트 한다. Flutter는 이렇게 하지 않는다. 위젯이 표시할 텍스트는 stateless든 stateful이든 위젯이 만들어질 때 생성자의 매개변수로 넘겨야 하고, 이 값을 바꿀 수 있는 메서드는 없다. 위젯의 색깔을 바꾼다든지, 위치를 바꾼다든지 하는 것도 명령으로 업데이트할 수 없다. 위젯은 build() 메서드를 제공하는데, 이 메서드는 위젯이 만들어졌을 때 한 번만 호출된다. 그렇다면 상태의 변화를 감지하는 Stateful Widget은 상태 변화에 어떻게 대응하나? Flutter가 채용하는 방식은 위젯과 상태를 다른 클래스로 분리한다. 즉 위젯을 그리는 build() 메소드를 위젯이 아닌 상태 (state) 클래스가 가지고 있고, 이 상태 클래스를 immutable인 위젯에서 createState() 메소드에서 만들어 가지고 있는 방식으로 문제를 해결한다. State 클래스는 final이 아닌 속성을 둘 수 있다. 위젯의 상태가 변하면, 즉 위젯의 모양에 영향을 미치는 데이터에 변화가 생기면 상태 클래스에 있는 build()가 위젯을 처음부터 다시 그리며 자신이 품고 있는 위젯 트리도 여기서 다시 그린다. 어떤 상태 변화가 있을 때마다 build()를 불러서 전체 위젯을 다시 그린다면 굉장히 효율이 떨어질 것처럼 보이지만 의외로 좋은데, 실제로는 Flutter 엔진이 어떤 부분이 변했는가를 검사한 다음, 영향을 받는 위젯을 'dirty' 상태로 표시하고, 이 위젯들만 다시 그리는 방식으로 효율을 낸다. 만약 stateful한 위젯에서 상태에 변화를 일으키는, 즉. 위젯을 다시 그려야 하는 dirty한 데이터 변경이 있다면 setState() 메서드를 호출해서 그 안에서 데이터를 변경해야 한다.<ref>[[리액트]]를 써본 사람들이라면 친숙한 방식일 것이다.</ref> UI에 영향을 미치는 데이터가 비동기적으로 변한다면<ref>즉 위젯의 업데이트를 위해 build() 메서드가 호출되었을 때 필요한 상태 데이터가 업데이트 되어 있다는 보장이 없는 경우를 뜻한다.</ref> 이는 [[Dart]]의 Future 또는 Stream 클래스를 이용해서 반영할 수 있다. 이 때에는 위젯의 build() 메서드 안에서 각각 FutureBuilder 또는 StreamBuilder 클래스를 사용해서 처리한다. 특히 구글의 제품인만큼 구글의 [[NoSQL]] 동기화 [[데이터베이스]]인 [[Firestore]]와 궁합이 기가 막히게 좋다. StreamBuilder를 사용하면 [[데이터베이스]]가 업데이트 되었을 때 자동으로 동기화가 되고 UI에 반영된다. 쉽게 말해서 UI 단에서는 업데이트에 대비해서 따로 뭘 할 게 없다는 뜻이다. 다만 단점도 있는데, 이들 위젯이 속해 있는 부모 위젯이 다시 그려질 때, 즉 build()가 호출될 때, 이것들도 다시 build()가 호출되므로 Future 혹은 Stream 객체를 다시 만들어서 그리며, 그때문에 데이터가 불필요하게 다시 로딩되거나 깜빡이는 현상이 나타난다. 또한 UI를 구성하는 방식이 [[XML]]과 같은 외부 파일이 아니라 코드 자체 안에서 구현하는 방식이다. 페이지 자체도 위젯이기 때문에 위젯을 구성하는 build() 메소드 안에서 자식 위젯을 정의하고, 자식 위젯 안에서 자식 위젯을 정의하고... 이런 방식이다. 배치 방법, 마진이나 패딩 같은 것들도 모두 코드로 구현한다. 따라서 위젯의 구성이나 모양을 바꿀 때마다 코드를 다시 컴파일해야 하지만<ref>UI 레이아웃을 [[XML]]로 분리했다고 해도 어차피 빌드를 다시 하긴 해야 하며, 이 과정에서 [[XML]]을 코드로 컴파일하는 과정이 있는 방식이 대다수라 컴파일 효율이 낫다고 보기도 어렵다.</ref> 위에서 이야기한 핫 리로드 때문에 별 불편하지는 않긴 하다. 가독성 측면에서도 XML이 딱히 낫다고 보기 어렵고 효율성 측면에서도 좋은 소리는 못 듣기 때문에<ref>[[리누스 토르발스]]도 [[XML]]이 가장 나쁜 데이터 저장 방식이라고 엄청 깠다.</ref> UI 레이아웃을 코드로 구현하는 부분은 좋은 평가를 받는다. 참고로 설정 파일은 [[YAML]](확장자 .yml) 형식을 사용한다. 프로젝트에 포함시킬 외부 패키지, 글꼴, 그리고 이미지를 비롯한 자산(asset) 파일은 이 안에 포함시켜야 한다. 기존 위젯을 가지고 새로운 위젯을 만들려면 기존 위젯은 상속하지 않는 것이 좋다. 일단 실제로 해 보면 구현이 잘 안 되는 걸 알 수 있다. 대신 StatelessWidget 또는 StatefulWidget 클래스를 상속해서 새 위젯 클래스를 만든 다음 build() 메서드에서 확장하고자 하는 위젯에 내가 구현한 기능을 붙인 위젯 객체를 돌려주는 방식으로 구현해야 한다. ===그밖에=== 각 OS의 네이티브에 붙어 있는 기능을 써야 할 때에는 그 부분만 네이티브로 개발해서 Flutter에 붙일 수도 있다. Flutter는 이를 위한 인터페이스를 제공한다. 단, 네이티브 부분은 [[안드로이드]]라면 [[자바]]나 [[코틀린]], iOS라면 오브젝티브C나 스위프트와 같이 각자의 네이티브 개발 언어를 써야 붙여줘야 한다. 카메라나 GPS처럼 플랫폼을 가리지 않고 대다수 하드웨어가 공통으로 제공하는 기능은 Flutter 지원 패키지로도 웬만큼은 다룰 수 있다.<ref>단, 플랫폼에 따라 기능이나 동작은 조금씩 차이가 있을 수 있다.</ref> Flutter의 사용자층이 넓어지면서 Flutter는 물론 [[Dart]]의 기능을 확장해 주는 패키지들도 빠른 속도로 늘어나고 있다. 패키지 관리를 위해서 [[자바스크립트]]가 npm, [[파이썬]]이 pip을 사용하는 것처럼 Flutter의 프로그래밍 언어인 [[Dart]]도 Pub을 제공한다. [https://pub.dev pub.dev] 웹사이트에서 패키지를 검색해 볼 수 있으며 필요한 패키지를 Pub으로 설치 및 관리할 수 있다. 필요한 패키지는 pubspec.yaml 파일에 추가해서 'flutter pub get' 명령으로 받아올 수 있다. 비주얼 스튜디오 코드나 안드로이드 스튜디오는 pubspec.yaml 파일 변경을 감지해서 자동으로 pub get 명령을 실행하거나 명령을 실행할지 물어본다. 편집 요약 가온 위키에서의 모든 기여는 크리에이티브 커먼즈 저작자표시-동일조건변경허락 라이선스로 배포된다는 점을 유의해 주세요(자세한 내용에 대해서는 가온 위키:저작권 문서를 읽어주세요). 만약 여기에 동의하지 않는다면 문서를 저장하지 말아 주세요. 또한, 직접 작성했거나 퍼블릭 도메인과 같은 자유 문서에서 가져왔다는 것을 보증해야 합니다. 저작권이 있는 내용을 허가 없이 저장하지 마세요! 취소 편집 도움말 (새 창에서 열림)