РозробкаБудь-який рівень

Flutter

Flutter — це UI-фреймворк від Google, який малює кожен піксель застосунку власним рушієм з однієї кодової бази на Dart для iOS, Android, вебу й десктопа. Через цей вибір застосунок на Flutter виглядає однаково всюди й не змінюється, коли змінюється операційна система, — навіть коли вона змінюється навмисно, як це зробила iOS 26. Сторінка починається з шістнадцяти речей, які потрібні застосунку, і того, малює їх Flutter чи мусить просити платформу; далі — три дерева й бюджет кадру, ціна перебудови, Dart та ізоляти, межа з платформою й редизайни ОС, релізи до Flutter 3.47, п’ять задокументованих кейсів і те, де все це вироджується.

Поточна версія
Flutter 3.47 · серп. 2026 · Dart 3.13
Модель
Малює кожен піксель; решту просить в ОС
Підтримка
Реліз щокварталу; виправлення — лише для останнього

Що Flutter малює сам, а що мусить просити, — шістнадцять речей, потрібних застосунку

Нативний застосунок просить кнопку в операційної системи, і система її малює. Застосунок на Flutter не просить: він малює кнопку сам на полотні, яке йому видала система, і система так і не дізнається, що там кнопка. Це одне рішення розкладає все, що потрібно застосунку, на кілька видів. Щось Flutter малює. До чогось дістає через міст, який сам підтримує. Щось — нативний код у плагіні, написаний кимось іншим. А чогось не може взагалі. Вид визначає, що станеться того дня, коли зміниться операційна система, — а це головне питання для застосунку, що живе роками. Ось шістнадцять речей, потрібних застосунку. Наступні розділи посилаються на рядки за номерами.

#Що потрібно застосункуХто це даєКоли це змінює ОСПеревірка
1Кнопки, списки, діалоги, панелі вкладок і навігаціїМалює Flutter — віджети Material і Cupertino, з серпня 2026 року пакети material_ui і cupertino_uiНічого не змінюється: Liquid Glass з iOS 26 до Flutter-застосунків не дійшовВирішіть, якого дизайну дотримуєтеся, і закладайте наступний редизайн самі
2Фізика скролу й overscrollFlutter, що імітує кожну платформу: відскок на iOS, розтягування на AndroidЗмінюється, лише коли зміну скопіює FlutterПорівнюйте обидві платформи поруч: фізика тепер — ваше дизайнерське рішення
3Розкладка й малювання текстуВласний текстовий рушій Flutter зі шрифтами платформиОднаково на кожному пристрої; системні зміни тексту самі не застосовуютьсяПеревіряйте довгі українські слова, письмо справа наліво, тайські рядки й великий масштаб тексту
4Переходи між сторінками й жест «назад»Перехід малює Flutter; predictive back на Android має реалізувати фреймворкAndroid 16 (API 36) вмикає predictive back типовоPopScope замість застарілого WillPopScope; перевірте «назад» на Android 16
5Саме малюванняРушій Flutter, Impeller, на Metal чи Vulkan, з OpenGL ES як запасним шляхом на AndroidПомилка драйвера GPU на одній моделі Android стає вашою помилкоюТестуйте на слабкому Android: нижче API 29 чи без Vulkan працює запасний шлях
6Введення тексту й клавіатураКлавіатура платформи, з’єднана з полями Flutter через канал введення текстуНові можливості клавіатури приходять, коли їх під’єднає FlutterПеревіряйте автовиправлення, українське й CJK-введення на реальних пристроях
7Доступність — VoiceOver, TalkBackДерево семантики, яке будує Flutter і перекладає в API доступності платформиНастільки добре, наскільки добрі ваші мітки Semantics; у власних віджетів їх типово немаєПройдіть кожен сценарій із читачем екрана на обох платформах
8Автозаповнення й менеджери паролівПід’єднано до сервісу автозаповнення платформиПрацює для полів, що оголошують, що в нихautofillHints на кожному полі входу й адреси
9Безпечні зони, виріз, системні панеліОС повідомляє відступи; Flutter розкладає довкола нихAndroid 16 робить edge-to-edge обов’язковимSafeArea чи відступи з MediaQuery на кожному екрані; перевірте жестову й трикнопкову навігацію
10Камера, біометрія, Bluetooth, файли, геолокаціяПлагіни: Dart-API поверх коду на Swift і KotlinНове правило дозволів ламає плагін, доки супровідник не випустить виправленняПерш ніж брати плагін, перевірте видавця, останній реліз і відкриті issues
11Пуш-сповіщення й фонова роботаПлагіни плюс налаштування нативних проєктів; коли фоновий код може працювати, вирішує ОСНайкрихкіша категорія на кожному релізі ОСПеревіряйте з убитим застосунком, на обох платформах, після кожного оновлення ОС
12Мапи, вебв’ю, відеоплеєри, нативна рекламаPlatform views: нативна в’ю, вбудована в зображення FlutterПоводиться нативно, але її композиція коштує кадрів, а жести можуть застрягати на стикуКілька на екран; перевіряйте скрол над ними й довкола
13Покупки в застосунку й підпискиПлагіни поверх StoreKit і Google Play BillingПлатіжні бібліотеки магазинів мають власні дедлайниТримайте платіжний плагін свіжим: від нього залежить дохід
14Віджети домашнього екрана, застосунки для годинника, Live Activities, App IntentsЛише нативний код — Flutter там не малюєКожен реліз ОС додає поверхні, до яких Flutter не дістаєЗакладайте нативні навички під це від початку
15Іконка, екран запуску, тексти дозволів, підпис, життєвий циклНативні проєкти ios/ та android/ усередині проєкту FlutterСюди приходять правила магазинів — життєвий цикл UIScene, target APIПереглядайте нативні проєкти на кожному оновленні Flutter; 3.38 додав міграцію на UIScene
16Системний інтерфейс — клавіатура, «Поділитися», запити дозволівОС, яку викликає FlutterЗмінюється разом з ОС, як у будь-якому застосункуНічого — межа між рядками 1 і 16 і є темою цієї сторінки

Три дерева, два потоки й бюджет кадру

Коли ви пишете кнопку у Flutter, не створюється ні UIButton, ні Android-Button. Flutter будує власне дерево, сам робить розкладку й віддає результат своєму рушію, який перетворює його на команди малювання для . Платформа дає поверхню для малювання, події введення — і майже нічого більше. Це і є той єдиний факт, що пояснює про фреймворк майже все інше, зокрема рядок 1.

Flutter не просить в операційної системи кнопку. Він будує власне дерево, сам робить розкладку й віддає рушієві полотно, щоб намалювати його на GPU, — кожен піксель на екрані малює Flutter. Тому той самий код виглядає однаково на обох платформах, а набір віджетів не змінюється, коли ОС оновлює власний. Ціна в тому, що все, що може дати лише ОС — камера, біометрія, сповіщення, дозволи, — доступне через канал платформи, а доступність і введення тексту доводиться мостити, а не успадковувати.

Конвеєр проходить через три дерева, і розуміння, що є що, робить поведінку фреймворку зрозумілою. Віджети — ваш опис екрана: незмінні, дешеві, їх постійно викидають і будують знову. Елементи — те, що справді змонтовано; вони переживають перебудови й тримають стан, тому віджет можна перестворювати шістдесят разів на секунду, не втрачаючи його. Об’єкти рендерингу роблять розкладку й малювання. Саме вони дорогі, тож Flutter перевикористовує об’єкт рендерингу щоразу, коли новий віджет має той самий тип і ключ, що й старий.

Рушій — Impeller, що замінив Skia через одну конкретну проблему. Skia компілював шейдери GPU — маленькі програми, що малюють кожен ефект, — тоді, коли ефект з’являвся вперше, на телефоні користувача. Перша анімація могла застрягти на десятки мілісекунд, поки шейдер компілювався, — і так після кожного встановлення застосунку; розділ кейсів розповідає цю історію. Impeller компілює всі свої шейдери під час збірки рушія, тож під час роботи нічого не компілюється. Він став типовим на iOS у Flutter 3.10 (травень 2023) і єдиним рендерером там у 3.29; типовим на Android від 29 у 3.27 (грудень 2024), з OpenGL ES як запасним шляхом на старіших пристроях чи без Vulkan; і типовим на десктопі в 3.47. Flutter у вебі досі малює через Skia, скомпільований у WebAssembly.

Роботу кожного кадру роблять два потоки. -потік виконує весь код на Dart — ваш і фреймворку — і створює опис кадру, що зветься деревом шарів. Потік растру перетворює його на команди GPU. При 60 Гц разом вони мають 16,7 мс на кадр; при 120 Гц — 8,3 мс. З Flutter 3.29 UI-потік на iOS і Android — узагалі не окремий потік: Dart виконується в головному потоці платформи (десктоп приєднався в 3.35). Це дозволяє Dart викликати API платформи синхронно через FFI. А ще це означає, що довга задача на Dart тепер затримує й код плагінів та системні колбеки, а не лише ваші кадри.

При 60 Гц Flutter має 16,7 мс, щоб збудувати й намалювати кадр, а при 120 Гц — 8,3 мс. Увесь код на Dart — ваш і фреймворку — виконується в UI-потоці, який із Flutter 3.29 на iOS і Android є головним потоком платформи. Декодуйте там велику JSON-відповідь — і потік не зможе збудувати наступні кадри: у цьому ілюстративному прогоні декодування на 40 мс коштує двох кадрів, і екран 33 мс показує старе зображення. Isolate.run переносить ту саму роботу в ізолят-воркер із власною пам’яттю; UI-потік і далі будує кадри, а результат приходить, щойно готовий.

Оверлей продуктивності й Flutter DevTools показують обидва потоки стовпчиками відносно лінії 16 мс, і колір підказує, яка у вас проблема. Червоний стовпчик в UI-потоці означає, що Dart робить забагато: великий build, розбір, сортування — робота, якій місце в ізоляті. Червоний стовпчик у потоці растру означає, що кадр задорогий для малювання: шари, які зберігають і відновлюють ефекти на кшталт прозорості, обрізання й розмиття, завеликі зображення, тіні на кожному рядку списку. Виправлення в них різні, тож спершу подивіться, а потім оптимізуйте.

Перебудови: що насправді перемальовує один setState

setState робить одне: позначає віджет, що володіє станом, як «брудний», і в наступному кадрі Flutter знову викликає його метод build і проходить усе, що той повертає. Віджети дешеві, тож перебудова зазвичай не є проблемою. Коштує інше: скільки всього лежить під віджетом, чий стан змінився, і скільки роботи робить кожен build дорогою. Лічильник, чий стан живе вгорі екрана, перебудовує екран; той самий лічильник у власному маленькому віджеті перебудовує два віджети.

Коли викликають setState, Flutter перебудовує віджет, що володіє станом, і все під ним. Тримайте стан лічильника кошика вгорі одного великого методу build — і один тап перебудовує весь екран: дев’ять віджетів заради одного зміненого числа. Перенесіть стан у маленький віджет CartButton — і той самий тап перебудовує два: кнопку та її лічильник. Icon усередині кнопки створено з const, тож це той самий об’єкт, що й минулого разу, і Flutter його пропускає. Тому й радять виносити віджети в класи, а не в методи-помічники: метод не має власного елемента, і пропустити його не можна.
  • Опускайте стан до найменшого віджета, якому він потрібен, і піднімайте лише тоді, коли він справді потрібен другому місцю.
  • Виносьте частини екрана в класи віджетів, а не в методи, що повертають віджети: клас отримує власний елемент і може бути пропущений; метод виконується знову разом із батьком.
  • Ставте const-конструктори всюди, де аргументи сталі: const-віджет — той самий об’єкт у кожній перебудові, тож Flutter на ньому зупиняється.
  • Тримайте build вільним від роботи: жодного розбору, сортування, створення контролерів чи потоків — build може виконуватися шістдесят разів на секунду.
  • Давайте елементам списку Key, якщо їх можуть переставляти, вставляти чи видаляти, інакше стан лишиться за позицією, а не за елементом.
  • Обгортайте частину, що часто перемальовується, — анімацію, індикатор прогресу — у RepaintBoundary, щоб її малювання не перемальовувало сусідів.

Керування станом і чесна відповідь

У Flutter немає офіційної бібліотеки керування станом — тому кожна розмова про це перетворюється на порівняння пакетів. Корисно дивитися на поле за тим, скільки структури нав’язує кожен варіант, і правильна відповідь залежить більше від розміру команди, ніж від переваг бібліотеки.

  • setState

    Вбудований, локальний для одного віджета. Правильний для всього, чим володіє один екран, і хибний тієї миті, коли двом екранам потрібне те саме значення.

  • Provider / Riverpod

    Впровадження залежностей плюс спостережуваний стан. Riverpod новіший із двох: перевіряється під час компіляції, тестований і незалежний від дерева віджетів.

  • BLoC

    Події всередину, стани назовні, потоками. Забагато церемонії для малого застосунку; передбачувано й простежувано для великої команди на довгому проєкті.

Порада, що тримається незалежно від вибору, — це правило перебудов вище, застосоване до стану: тримайте його якомога ближче до місця використання й виносьте назовні лише тоді, коли він справді потрібен другому місцю. Більшість складності, яку приписують керуванню станом у Flutter, створено власноруч: глобальне сховище, заведене першого ж дня для застосунку з чотирьох екранів без спільного стану, яке потім на кожну зміну перебудовує більше, ніж треба.

Dart: два компілятори, ізоляти й генерація коду

Вивчати мову заради фреймворку звучить як витрата, і Dart — приблизно найменша версія цієї витрати: будь-хто, кому зручно з , Java чи C#, читає його першого ж вечора. Він статично типізований і надійний щодо null: значення, що може бути null, не можна використати як таке, що не може, і компілятор це забезпечує; від Dart 3 іншого режиму немає. Незвичайним Dart робить те, що він компілюється двома способами під дві цілі. У розробці він працює на віртуальній машині з JIT-компілятором — саме це уможливлює гаряче перезавантаження зі збереженням стану: змінили віджет — і запущений застосунок оновився менш ніж за секунду, не втративши місця. Для релізу він компілюється заздалегідь у машинний код, тож у поставленому застосунку немає інтерпретатора. Швидкість розробки й продуктивність релізу зазвичай торгуються одна проти одної; тут — ні.

Гаряче перезавантаження має межі, які варто знати, перш ніж вони коштуватимуть пів дня. Воно вставляє змінений код і перебудовує дерево віджетів, але не виконує знову main() чи initState об’єкта стану й зберігає поточні значення глобальних і статичних змінних. Зміна будь-чого з цього потребує гарячого перезапуску, що скидає стан застосунку. Зміна нативного коду — плагіна, проєктів ios/ чи android/ — потребує повної перезбірки, бо гаряче перезавантаження дістає лише до Dart.

Паралельність працює як у JavaScript: кожен ізолят має один потік і цикл подій, тож await ніколи не блокує екран, а довге обчислення — блокує. Для важкої роботи ви запускаєте ще один ізолят із власною пам’яттю, що спілкується з вашим лише повідомленнями, — без спільного стану, а отже, без гонок, які приносять потоки. Isolate.run робить це одним рядком: виконує функцію в новому ізоляті й повертає результат. Декодування великої -відповіді, зміна розміру зображення чи розбір файлу — саме туди, як показує схема бюджету кадру вище.

DartВихідЩо змінилося у вигляді коду
3.0трав. 2023Лише надійна null-безпека; записи, патерни, sealed-класи й модифікатори класів
3.10листоп. 2025Крапкові скорочення: .center там, де тип уже відомий
3.12трав. 2026Приватні іменовані параметри
3.13серп. 2026Первинні конструктори — поля, оголошені в заголовку класу

Чого в Dart досі немає, то це вбудованого способу згенерувати toJson, copyWith і рівність для класу даних. Команди пишуть їх генерацією коду: build_runner запускає пакети на кшталт freezed і json_serializable, що пишуть файли .g.dart поруч із вихідним кодом. Макроси мали це замінити — і їх скасували в січні 2025 року; розділ кейсів пояснює чому. Первинні конструктори в 3.13 — перша з менших можливостей, обіцяних натомість, і вони прибирають частину шаблонного коду, не прибираючи генератора.

Межа з платформою: канали, FFI, плагіни й редизайни ОС

Те, чого Flutter не може намалювати, він мусить попросити, і перейти на той бік можна чотирма способами. Плагін — це просто пакет, що користується одним із них і постачає вам нативну половину.

СпосібЯк викликаєДля чого
Канал платформи (MethodChannel)Асинхронне повідомлення коду на Swift чи KotlinБільшість викликів плагінів; усе, що може зачекати кадр
PigeonЗгенерований типізований код каналу з обох боківВаш власний нативний код без рукописних рядків-повідомлень
FFI (dart:ffi, з ffigen і jnigen)Прямий синхронний викликБібліотеки C, а з 3.29 — і API платформи, що мають працювати в головному потоці
Platform viewЦіла нативна в’ю, вкомпонована в зображення FlutterМапи, вебв’ю, відеоплеєри, нативна реклама (рядок 12)

Через рядки 10–15 плагіни — частина застосунку на Flutter, найбільш відкрита до часу. Кожен — це нативний код для двох платформ, що змінюються щороку, і підтримує його той, хто опублікував. Коли Apple оголосила, що застосунки, зібрані з iOS 27 , мусять використовувати життєвий цикл на сценах, інакше не запустяться, сам Flutter додав міграцію в 3.38 — а потім запити на підтримку UIScene відкрилися в одному популярному плагіні за іншим. Перш ніж додати плагін, перевірте, хто його видає, коли був останній реліз, які платформи він підтримує і скільки чекають його відкриті issues. Після додавання для ваших користувачів це ваш код.

Коли операційна система перемальовує себе

iOS 26, що вийшла у вересні 2025 року, перемалювала системні елементи керування в напівпрозорому стилі, який Apple називає Liquid Glass. Будь-який застосунок, перезібраний з iOS 26 SDK — без цього з 28 квітня 2026 року не приймають завантажень в App Store, — отримує новий вигляд усюди, де елемент малює операційна система. Саме це точно проводить межу між підходами. Застосунок на SwiftUI чи UIKit змінився майже всюди. Застосунок на React Native — усюди, де його компоненти є справжніми в’ю платформи. Застосунок на Flutter — лише в системному інтерфейсі, який він викликає, бо його Cupertino-віджети — це малюнки елементів керування iOS 18, а не самі елементи.

iOS 26 перемалював системні елементи керування в стилі Liquid Glass, і будь-який застосунок, перезібраний з iOS 26 SDK — без цього з 28 квітня 2026 року не приймають завантаження в App Store, — отримує новий вигляд усюди, де елемент малює операційна система. Саме це точно проводить межу між трьома підходами: застосунок на SwiftUI чи UIKit змінюється майже всюди; застосунок на React Native — там, де його компоненти є справжніми в’ю платформи, і лишається як був там, де їх намальовано з JavaScript-в’ю; застосунок на Flutter, що малює свої Cupertino-віджети сам, зберігає старий вигляд, крім системного інтерфейсу, який він викликає. Ключ відмови Apple, UIDesignRequiresCompatibility, ігнорується, щойно застосунок збирають з iOS 27 SDK.

Команда Flutter написала у своєму трекері в червні 2025 року, що «зараз не розробляє нові дизайнерські можливості Apple’26 у бібліотеці Cupertino». Відповідь прийшла в серпні 2026 року: Material і Cupertino опублікували як окремі пакети material_ui і cupertino_ui — копії всередині фреймворку мають застаріти й зникнути, — щоб оновлення дизайну виходили щотижня, а не з кожним квартальним релізом, і в оголошенні сказано, що «робота над офіційними реалізаціями Liquid Glass уже триває». Для нативних застосунків годинник іде у зворотний бік. Apple дала їм зберегти старий вигляд ключем у Info.plist, UIDesignRequiresCompatibility, і її документація тепер каже, що для застосунків, зібраних з iOS 27 SDK, цей ключ ігнорується. Тож упродовж року нативні застосунки не зможуть уникнути нового дизайну, а застосунки на Flutter зберігатимуть старий, доки хтось його не перебудує.

Релізи, підтримка і який Flutter перед вами

Flutter випускає стабільний реліз щокварталу — у лютому, травні, серпні й листопаді, — і номер версії щоразу росте на три: 3.41, 3.44, 3.47. Кожен іде в парі з релізом Dart. Між ними виправлення отримує лише поточний стабільний: 3.47.6 вийшов 1 жовтня 2026 року, а 3.44 відтоді, як вийшов 3.47, не отримав жодного. Гілки довгострокової підтримки немає, тож «підтримуваний» означає «останній», а команда, що пропускає рік, опиняється на чотири релізи позаду.

FlutterВихідЩо змінилося
3.10трав. 2023Dart 3; Impeller типовий на iOS
3.16листоп. 2023Material 3 типово
3.22трав. 2024WebAssembly для Flutter web — стабільно; MaterialState перейменовано на WidgetState
3.27груд. 2024Impeller типовий на Android від API 29; широка колірна гама, withOpacity застарів
3.29лют. 2025UI-потік і потік платформи злито на iOS і Android; Skia прибрано з iOS; HTML-рендерер для вебу прибрано
3.35серп. 2025Потоки злито на macOS і Windows
3.38листоп. 2025Dart 3.10; підтримка iOS 26 і Xcode 26; міграція на життєвий цикл UIScene
3.47серп. 2026Dart 3.13; Material і Cupertino — окремі пакети; Impeller типовий на десктопі; Widget Previewer стабільний

Який Flutter перед вами

Що ви бачите в кодіЩо це означає
WillPopScopeНаписано до predictive back; застаріло на користь PopScope — рядок 4
useMaterial3: false або відсутній useMaterial3 у коді 2023 рокуСтилі Material 2; типове значення змінилося в 3.16
MaterialStatePropertyСтарше за 3.22, де воно стало WidgetStateProperty
color.withOpacity(0.5)Старше за 3.27; withValues(alpha: 0.5) зберігає точність широкої гами
--web-renderer html у скрипті збіркиHTML-рендерер і сам прапорець прибрано в 3.29; скрипт збірки треба оновити
Файли розігріву SkSL (--bundle-sksl-path)Обхід ривків через шейдери з часів Skia; під Impeller не має сенсу
import 'package:flutter/material.dart' після серпня 2026Поки що працює — копії у фреймворку мають застаріти й зникнути; dart fix переносить імпорти на material_ui, де будують Liquid Glass і Material 3 Expressive
iOS-AppDelegate без делегата сценШаблон, старший за 3.38; змінити обов’язково до збірки з iOS 27 SDK

Дедлайни магазинів щодо збірок стосуються Flutter так само, як будь-якого іншого застосунку, — сторінка про React Native зводить їх у таблицю: iOS 26 SDK з квітня 2026 року, життєвий цикл UIScene з iOS 27 SDK, Android 16 як target API з 31 серпня 2026 року й сторінки пам’яті по 16 КБ для кожної нативної бібліотеки. У Flutter рушій виконує свою частину, коли ви оновлюєтеся; нативні проєкти (рядок 15) і кожен плагін (рядки 10–14) мусять виконати свою.

П’ять кейсів і те, чого в кожному бракувало

Кейси взято з трекера issues і блогів самого Flutter, вітрини Google і публічних записів спільноти. Разом вони покривають рендерер, велике переписування, людей за фреймворком, можливість мови, що так і не вийшла, і платформу, що перемальовує сама себе.

КейсЩо сталосяЧого бракувало
Ривки через шейдери, 2019–2025Перші анімації смикалися, поки Skia компілював шейдери на телефоні; обхідний розігрів був крихкимШейдери, скомпільовані до постачання, — Impeller
Google Pay, 2020Два нативні застосунки, 1,7 мільйона рядків, переписано в один Flutter-застосунок, на 35% меншийНічого — переписування цілого застосунку командою, яку для цього навчили
Flock, жовт. 2024Колишній інженер Flutter форкнув фреймворк, пославшись на малу заморожену командуПогляд на людей за фреймворком як на ризик залежності
Макроси Dart, січ. 2025Показану в прев’ю можливість мови скасували, бо вона сповільнювала редактор і гаряче перезавантаженняПравило не будувати на можливості, яка ще не вийшла
Liquid Glass, черв. 2025 – 2026iOS перемалювала свої елементи керування; нативні застосунки змінилися після перезбирання, Flutter-застосунки — ніПлан, що називає редизайн роботою самої команди

Перший кейс — сам рендерер. Skia, графічна бібліотека, якою Flutter користувався від початку, компілював кожен шейдер GPU тоді, коли застосунок уперше його потребував, — на телефоні користувача, посеред кадру. Коли перехід між сторінками чи розмиття запускалися вперше, кадр міг застрягти на десятки мілісекунд; удруге все йшло плавно. Користувачі бачили застосунок, що смикається, поки новий, — особливо на iOS, де не було постійного кешу шейдерів. Issue #32170, відкритий 6 травня 2019 року, просив автоматичного виправлення. Тимчасовою відповіддю, з Flutter 1.20 у 2020 році, було запустити застосунок, зібрати використані шейдери у файл і вкласти цей файл у збірку — що покривало лише ті шляхи, які хтось не забув пройти, і могло відрізнятися від пристрою до пристрою. Справжнім виправленням став інший рушій: Impeller компілює кожен шейдер під час збірки рушія. Він став типовим на iOS у 3.10 (травень 2023), на Android — у 3.27 (грудень 2024), а Skia прибрали з iOS у 3.29. Шість років від звіту до видалення — ціна проблеми, що жила в архітектурі, а не в окремому застосунку.

Третій кейс — про людей. У жовтні 2024 року Метт Керролл, який працював над Flutter у Google, оголосив Flock — форк, що мав іти в ногу з Flutter, але швидше приймати виправлення й можливості. Його причини були публічними й конкретними: за його підрахунком, близько 50 людей у Google будували фреймворк, яким користується приблизно мільйон розробників, кількість посад було заморожено приблизно з 2023 року, у 2024 році були скорочення, а три з шести платформ Flutter фактично перебували в режимі підтримки. Відтоді Flutter виходив щокварталу, тож форк не передбачив краху. Він показав залежність, якої більшість команд ніколи не записує: фреймворк — це ще й команда, що його підтримує, а її розмір і пріоритети визначає бюджет однієї компанії. Запишіть, що ви робитимете, якщо фреймворк сповільниться: які частини застосунку зможете зберегти і які плагіни зможете підтримувати самі.

Четвертий кейс — можливість, яку пообіцяли, показали й відкликали. Макроси Dart — код, що пише код усередині компілятора, щоб клас даних отримував toJson і рівність без генератора, — показали з прев’ю JsonCodable на Google I/O у травні 2024 року. 29 січня 2025 року Віджай Менон оголосив, що команда Dart зупинилася: реалізація сповільнювала редагування (аналіз і автодоповнення) і сповільнювала інкрементну компіляцію — перший крок гарячого перезавантаження, — а команда не була певна, що виправить обидва за розумний час. Натомість пообіцяли три менші речі: augmentations, швидший build_runner і окремі можливості мови для даних. До Dart 3.13 у серпні 2026 року вийшли первинні конструктори; augmentations у стабільному релізі так і не з’явилися. Команди, що відклали генерацію коду в очікуванні макросів, повернулися до неї. Плануйте на тому, що вже вийшло.

Де він вироджується

Flutter щедрий до всього, що малює, і мовчазний щодо всього, чого не малює. Екран швидко будувати, і він однаковий усюди, тож команда може зайти далеко, перш ніж зустріне нативний бік, — і тоді зустрічає його весь одразу. Майже кожен збій — одне з цього:

  • Метод build на сотні рядків зі станом угорі, що перебудовує цілий екран через одне значення.
  • Віджети, винесені в методи-помічники, а не в класи, тож const ніколи не зможе їх пропустити.
  • Розбір, декодування й сортування в UI-потоці — який із 3.29 ще й головний потік платформи.
  • Продуктивність, оцінена в debug-режимі чи на емуляторі, а не в profile-режимі на телефоні середнього класу.
  • Плагіни, взяті без перевірки, хто їх підтримує, що потім блокують дедлайн ОС (рядки 10–15).
  • Власні віджети без Semantics, невидимі для читача екрана (рядок 7).
  • Вигляд Cupertino, обраний, щоб «відчуватися нативно», і залишений позаду наступним редизайном платформи (рядок 1).
  • Версія Flutter річної давнини із застарілими API з таблиці «який Flutter» на своїх місцях.
  • Пакет глобального стану, узятий першого дня для застосунку, у якого спільного стану немає.
  • Flutter web, обраний для публічного текстового сайту, де полотно — хибний вихід для виділення тексту, пошукових систем і доступності.

Чесна межа — лінія між рядком 1 і рядком 16. Flutter володіє кожним пікселем, який малює, тож не може успадкувати нічого, що платформа додає до своїх елементів керування — редизайн, нову взаємодію, поведінку доступності, — доки хтось це не перереалізує. Застосунок, що має відчуватися точно як платформа, платить цю ціну на кожному великому релізі ОС, а застосунок, чия цінність живе у віджетах, циферблатах годинника й системних інтеграціях, однаково пише більшість цієї цінності нативно. Рушій їде всередині застосунку, тож бінарник Flutter стартує на кілька мегабайтів більшим за нативний. Для брендових продуктів з одним дизайном на всіх платформах, інтерфейсів, насичених анімацією, і команд без наявних навичок React обмін працює навпаки, і Google Pay — масштаб, на якому це доведено.

Практична перевірка займає десять хвилин. Запустіть flutter --version і знайдіть реліз у таблиці. Знайдіть у коді WillPopScope, withOpacity і MaterialStateProperty. Складіть список плагінів із pubspec.yaml з видавцем і датою останнього релізу кожного. Відкрийте найповільніший екран у profile-режимі на телефоні середнього класу з Android з увімкненим оверлеєм продуктивності й запишіть, який стовпчик червоніє. Увімкніть VoiceOver і TalkBack і пройдіть головний сценарій. І переконайтеся, що в iOS-проєкті є делегат сцен, перш ніж хтось збиратиме з iOS 27 SDK.

Коли це застосовувати

Застосовуйте, коли

  • Продукти, що мають виглядати й поводитися однаково на кожній платформі — з однієї специфікації дизайну.
  • Брендові інтерфейси з власною дизайн-системою, де ви й так збиралися перевизначати віджети платформи.
  • Насичений анімаціями інтерфейс — володіння конвеєром малювання тут саме й дає перевагу.
  • Команди без наявних навичок React, для яких Dart не більша перешкода, ніж будь-який інший новий стек.

Уникайте, коли

  • Застосунки, що мають відчуватися точно як платформа й іти за її редизайнами, — там суть в успадкованих нативних елементах.
  • Продукти, чия цінність живе у віджетах, застосунках для годинника й системних інтеграціях, які однаково пишуть нативно.
  • Публічні текстові сайти — рендер у полотно є хибним інструментом для тексту, пошуку й доступності.
  • Усе, що збудовано навколо найновішого API платформи, — до Flutter воно доходить після того, як дійшло до нативного коду.

Джерела й метод

На чому стоїть ця стаття

  • 13 джерел
  • Перевірено 13 жовтня 2026 р.

Дослідження з Claude. Пошук і звірку першоджерел зроблено з Claude (Anthropic). Відбір, текст і перевірку фактів — редакція Anatomy of IT Product.

Було корисно?

Поділіться з тим, хто працює над тією ж задачею.