Перейти к контенту

Вайбкодинг с нейросетью 1: проверяю сборку Flutter-приложения в AppImage

Эксперименты с ИИ Eugene Kaddo 13

Данная статья посвящена сборке Flutter‑приложения в AppImage с помощью нейросетей GigaChat и Perplexity. Статья будет участвовать в конкурсе «Сезон ИИ в разработке» на Habr, посвящённом теме вайбкода в разработке.

Вайбкодинг с нейросетью 1: проверяю сборку Flutter-приложения в AppImage
Эксперименты с ИИ Eugene Kaddo 13

Что такое Flutter и чем он лучше Kivy?

Проведу небольшое исследование по сравнению Flutter и Kivy. Я не знаком с Flutter, поэтому для меня это буквально как изучать новое по ходу написания этой статьи. С этим мне тоже отлично помогают нейросети, которым можно доверить как исправление орфографических ошибок, так и поиск или написание некоторого текста.

Когда сравниваешь Kivy и Flutter, довольно быстро становится заметно, что эти инструменты стоят на совершенно разных основаниях, хотя внешне оба предлагают кросс-платформенную разработку. Kivy вырос из Python-экосистемы и представляет собой в первую очередь UI-фреймворк, которому приходится работать поверх интерпретируемого языка и множества слоёв абстракции. Flutter же был изначально спроектирован Google как полноценный SDK для создания нативных интерфейсов, и именно поэтому он существенно выигрывает в производительности, стабильности и управляемости сборки.

Kivy опирается на Python — мощный и гибкий язык, но изначально не предназначенный для высокопроизводительной отрисовки интерфейсов и уж тем более для нативной компиляции. Приложения на Kivy работают внутри виртуальной машины Python, а сам UI отрисовывается через OpenGL слоями, которые фреймворку приходится собирать вручную. Это приводит к заметным накладным расходам: приложения оказываются тяжелее, отклик медленнее, а поведение на разных ОС непредсказуемее. Попытки собрать приложение под Linux, macOS или мобильные платформы часто превращаются в борьбу с зависимостями, нестыкующимися версиями библиотек и обилием сторонних инструментов вроде buildozer или python-for-android. Именно из-за этого каждая новая сборка становится похожа на мини-исследование, где заранее невозможно знать, появится ли следующий сюрприз.

Flutter устроен совсем иначе. Он использует Dart — язык, созданный с учётом особенностей UI-разработки. Dart умеет работать в двух режимах: в JIT-режиме с быстрым hot-reload для разработки и в AOT-режиме, при котором код компилируется в полноценный нативный машинный код для целевой платформы. Это значит, что Flutter-приложение не интерпретируется, не работает внутри виртуальной машины и не зависит от особенностей окружения. Вместо этого оно запускается так же, как и любое нативное приложение, что сразу поднимает производительность и снижает задержки рендера.

В то время как в Kivy-приложении возникают заметные задержки даже при простом раскрытии вложенных элементов. Иногда у меня появлялось ощущение, что такая тормознутость интерфейса может отпугнуть пользователей, и они просто не захотят им пользоваться.

Важной частью архитектуры Flutter является собственный рендер-движок Skia. Этот движок используется и в Chrome, и в Android, и в ряде других крупных проектов, поэтому он отлично оптимизирован под высокие FPS, плавность анимаций и одинаковое поведение на всех платформах. Flutter не доверяет отрисовку системным элементам ОС: он рисует весь интерфейс сам, что гарантирует одинаковый внешний вид и одинаковую производительность независимо от того, собираете ли вы приложение под Linux, Windows, Android, iOS или macOS.

С точки зрения сборки разница ещё заметнее. Когда работаешь с Kivy, любое добавление зависимостей может превратиться в многодневную охоту за решениями, особенно если речь идёт о Linux или мобильных системах. Python-библиотеки часто требуют нативных расширений, которые должны компилироваться под конкретную архитектуру, а инструменты для сборки не всегда умеют делать это корректно. Иногда приходится вручную искать версии библиотек, собирать колёса, подстраивать окружение — и всё это только ради того, чтобы приложение наконец запустилось на целевой платформе.

Flutter в этом смысле почти противоположен. Его система сборки тщательно организована и использует официальные инструменты платформ: Xcode для iOS, toolchain Apple для macOS, стандартные инструменты Linux, Windows и Android. Разработчик пишет код на Dart, а Flutter уже знает, как его собрать, упаковать, связать и оптимизировать. В итоге типичная сборка сводится к одной-двум командам в терминале и занимает предсказуемое время. Ошибки возникают редко, а если и появляются, то, как правило, воспроизводимы и документированы — в отличие от многих сюрпризов, которые встречаются при сборке проектов на Kivy.

Из-за этой комбинации факторов Flutter нередко воспринимается как инструмент на голову превосходящий Kivy. Он предлагает заранее продуманную архитектуру рендера, современный язык с нативной компиляцией, единый подход к сборке приложений и большую экосистему пакетов. Kivy хорош для экспериментов, но когда речь заходит о стабильной кросс-платформенной разработке, особенно с упором на производительность и предсказуемость, Flutter становится более очевидным выбором.

Быстро и стабильно работать с Kivy у меня, увы, не получается, потому что приходится постоянно искать информацию и разбираться с нюансами, тогда как во Flutter те же задачи решаются буквально двумя командами — быстро и без лишнего мозгового штурма.


Hello world на flutter

Сама идея Flutter мне очень понравилась, он, как мне кажется, на голову превосходит Kivy. Теперь мне нужно написать код на Flutter, с которым я как Python3-разработчик пока совершенно не знаком. Обычного «Hello, World» будет достаточно для текущего этапа исследования гипотезы, поэтому я попрошу нейросеть написать приложение, которое я затем соберу под Linux.

Ответ GigaChat:

Ответ Perplexity:

Мне нравится, что Perplexity начал с установки Flutter и зависимостей для сборки. Хотя я не просил об этом, это кажется более профессиональным подходом, так как мне как пользователю не пришлось дополнительно искать информацию о том, как его установить.

git clone https://github.com/flutter/flutter.git -b stable
export PATH="$PATH:`pwd`/flutter/bin"

Далее, после установки Flutter и зависимостей, я создаю новый проект. С этим справились обе нейросети.

flutter create hello_world

Вывод в terminal:

Your application code is in hello_world/lib/main.dart.

Вот такая богатая структура создаётся после инициализации проекта. Сразу видно, под какие операционные системы можно собрать проект. Выбор впечатляет! В данный момент я не буду разбирать каждый элемент системы, так как сам пока не знаю, как устроен проект на Flutter.

Далее мне нужно выбрать код, который я вставлю в приложение.

Ответ GigaChat:

Тут мне больше понравился код, который написал GigaChat, так как, помимо текста, он ещё указал стиль (видимо, для текста «Привет, мир!»). Читаю код как английский текст, а сам синтаксис языка Dart для меня частично загадка, но отчасти интуитивно понятно что в нём.

import 'package:flutter/material.dart';
void main() {
  runApp(const MyApp());
}
class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Hello World',
      home: Scaffold(
        appBar: AppBar(title: Text('Hello World')),
        body: Center(
          child: Text(
            'Привет, мир!', 
            style: Theme.of(context).textTheme.headlineMedium,
          ),
        ),
      ),
    );
  }
}

Ответ Perplexity:

После написания запущу проект и посмотрю как оно отработает.

cd hello_world && flutter run

Вывод в terminal:

Downloading Web SDK...                                              4,0s  
Downloading linux-x64-debug/linux-x64-flutter-gtk tools...          4,6s  
Downloading linux-x64-profile/linux-x64-flutter-gtk tools...      2 822ms  
Downloading linux-x64-release/linux-x64-flutter-gtk tools...      2 208ms  
Connected devices:  
Linux (desktop) • linux  • linux-x64      • Debian GNU/Linux 12 (bookworm) 6.1.0-41-amd64  
Chrome (web)    • chrome • web-javascript • Google Chrome 143.0.7499.40  
[1]: Linux (linux)  
[2]: Chrome (chrome)  
Please choose one (or "q" to quit): 1  
Launching lib/main.dart on Linux in debug mode...  
Building Linux application...                                              
✓ Built build/linux/x64/debug/bundle/hello_world  
Syncing files to device Linux...                                   117ms  
Flutter run key commands.  
r Hot reload.   
R Hot restart.  
h List all available interactive commands.  
d Detach (terminate "flutter run" but leave application running).  
c Clear the screen  
q Quit (terminate the application on the device).  
A Dart VM Service on Linux is available at: http://127.0.0.1:43129/yIwmXl6KQrU=/  
The Flutter DevTools debugger and profiler on Linux is available at: http://127.0.0.1:43129/yIwmXl6KQrU=/devtools/?uri=ws://127.0.0.1:43129/yIwmXl6KQrU=/ws

Кажется оно запустилось =) Прочитаю немного что там за VM Service и VM Service запустились.

Dart VM Service — это интерфейс для отладки и профилирования приложения:

Dart VM Service (http://127.0.0.1:43129/…) — внутренний сервер, через который можно получать информацию о работе приложения: состояние памяти, потоков, производительность и т.д;

Flutter DevTools (http://127.0.0.1:43129/…/devtools) — веб-интерфейс для удобной работы с Dart VM Service. Через него можно:

  • отлаживать код (debugger);
  • смотреть логи;
  • профилировать производительность (CPU, память);
  • визуализировать виджеты и их состояние.

VM Service:

Очень приятно, что из коробки Flutter представляет такой богатый функционал отладки и профилирования.

Окно программы:

В окне видны две надписи: «Hello World» и «Привет, мир!». Также в углу указано, что приложение запущено в режиме отладки (Debug).


Сборка приложения под Linux

Далее перехожу к самому главному исследованию — сборке приложения под Linux. Мне нужно понять, насколько этот процесс удобен во Flutter. Для эксперимента я решил выбрать формат AppImage.

AppImage — это формат упаковки приложений для Linux, который позволяет запускать программу как единый самодостаточный файл, без установки и зависимости от системных библиотек. Он удобен тем, что даёт почти портативный опыт: скачал, дал права на запуск — и вперёд, никакого «танца с пакетами» и конфликтов версий. Поддерживается AppImage на большинстве дистрибутивов Linux, от Debian, Ubuntu и Fedora до Arch и openSUSE, и именно универсальность делает его любимцем разработчиков, которые хотят распространять софт без лишних хлопот.

На втором шаге нейросети расскажут, как собрать приложение. Что ж, посмотрим, насколько хорошо у них это получится на практике.

Ответ GigaChat:

В начале я решил проверить пример от GigaChat. По его совету я решил поставить appimagetool через apt.

sudo apt install appimagetool

Вывод в terminal:

Этого пакета нет в apt для Debian 12. Посмотрим каким способом предлагает Perplexity установить пакет для сборки приложения.

Ответ Perplexity:

Perplexity предлагает скачать два инструмента linuxdeploy и appimagetool с помощью wget.

Чем они отличаются?

  • appimagetool — это инструмент упаковки: он берёт уже подготовленную файловую структуру AppDir и превращает её в AppImage;
  • linuxdeploy — это инструмент сборки: он сам собирает AppDir из вашего бинарника, подтягивает зависимости, раскладывает всё по правильным каталогам и только потом уже может упаковать это в AppImage.

В итоге:

  • appimagetool = упаковщик
  • linuxdeploy = сборщик + упаковщик

Flutter приносит с собой почти всё необходимое для запуска приложения: 
движок, рендерер, ICU-данные, бинарники — всё включается в билд. Поэтому основные зависимости Flutter уже внутри.

Из-за этого в теории можно просто взять готовый build/linux/x64/release/bundle, оформленный как AppDir, и упаковать его через appimagetool — и оно должно запустится на большинстве дистрибутивов.

Appimagetool не подтягивает зависимости. Он просто упаковывает то, что уже положили в AppDir. Если какой-то системной библиотеки не хватает на старой версии Ubuntu/Debian/Fedora, AppImage может не запуститься.

Для начала выберу самый простой вариант собрать с помощью appimagetool.

Скачивание инструмента:

wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage

Вывод в terminal:

2025-12-08 23:24:34 (5,15 MB/s) - «appimagetool-x86_64.AppImage» сохранён [8811712/8811712]

Делаем файл исполняемым:

chmod +x appimagetool-x86_64.AppImage

Создание нужной структуры каталогов для сборки:

mkdir -p AppDir/usr/bin
cp build/linux/x64/debug/bundle/hello_world AppDir/usr/bin/
cp build/linux/x64/debug/bundle/hello_world.png AppDir/
cp build/linux/x64/debug/bundle/hello_world.desktop AppDir/

Вывод в terminal:

cp: не удалось выполнить stat для 'build/linux/x64/debug/bundle/hello_world.desktop': Нет такого файла или каталога

Судя по всему, отсутствует важный файл, и если сейчас запустить сборку, она ожидаемо упадёт.

./appimagetool-x86_64.AppImage hello_world/AppDir  

Вывод в terminal:

appimagetool, continuous build (commit 5735cc5), build <local dev build> built on 2023-03-08 22:52:04 UTC  
Desktop file not found, aborting

Теперь мне нужно узнать у нейросетей, что это за файл .desktop и как его создать.

Ответ GigaChat:

Ответ Perplexity:

Мне больше понравился .desktop файл от Perplexity, который выглядит более простым.

Создание пустого .desktop

touch ./AppDir/hello_world.desktop

Заполнение файла:

[Desktop Entry]
Name=Hello World
Exec=hello_world
Icon=hello_world
Type=Application
Categories=Utility;
Comment=Hello World Flutter App

Теперь запускаю процесс сборки приложения.

./appimagetool-x86_64.AppImage hello_world/AppDir

Вывод в terminal:

Creating 4.0 filesystem on Hello_World-x86_64.AppImage, block size 131072.  
[=|] 4/4 100%  
Exportable Squashfs 4.0 filesystem, gzip compressed, data block size 131072  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;compressed data, compressed metadata, compressed fragments,  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;compressed xattrs, compressed ids  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;duplicates are removed  
Filesystem size 229.65 Kbytes (0.22 Mbytes)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;89.06% of uncompressed filesystem size (257.87 Kbytes)  
Inode table size 138 bytes (0.13 Kbytes)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;57.26% of uncompressed inode table size (241 bytes)  
Directory table size 98 bytes (0.10 Kbytes)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;67.59% of uncompressed directory table size (145 bytes)  
Number of duplicate files found 0  
Number of inodes 7  
Number of files 3  
Number of fragments 1  
Number of symbolic links &nbsp;1  
Number of device nodes 0  
Number of fifo nodes 0  
Number of socket nodes 0  
Number of directories 3  
Number of ids (unique uids + gids) 1  
Number of uids 1  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;root (0)  
Number of gids 1  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;root (0)  
Embedding ELF...  
Marking the AppImage as executable...  
Embedding MD5 digest  
Success

Результатом процесса сборки стал файл Hello_World-x86_64.AppImage, который мне не терпелось запустить.

Однако, когда я нажал на файл, увидел ошибку: «The command not be found», что означает, что команда не была найдена. Я предположил, что что-то не так со структурой или приложение не может понять, как запустить себя. Я спросил у нейросетей совета по решению и прикрепил изображение с ошибкой.

Ответ Perplexity:

Ответ GigaChat:

Тут я опять выбрал ответ от Perplexity так как он подсказал создать файл AppRun, который необходим для запуска приложения.

Создание AppRun:

touch ./AppDir/AppRun
#!/bin/sh
HERE="$(dirname "$(readlink -f "$0")")"
export LD_LIBRARY_PATH="$HERE/lib:$LD_LIBRARY_PATH"
exec "$HERE/hello_world" "$@"
chmod +x ./AppDir/AppRun

Далее последовала череда ошибок и запросов к нейросетям, которые я не буду перечислять, чтобы не затягивать статью. Однако я кратко расскажу о некоторых моментах.

Тут он не мог инициализировать движок:

embedder.cc (2090): 'FlutterEngineInitialize' returned 'kInvalidArguments'. Not running in AOT mode but could not resolve the kernel binary.  
** (com.example.hello_world:315658): WARNING **: 00:57:09.388: Failed to start Flutter engine: Failed to initialize Flutter engine

Оказалось, что я не заметил: собирал debug-версию, а не release. Поэтому я пересобрал релизную версию под Linux.

flutter build linux --release -v

Так же можно запускать сам файл hello_world чтоб видеть ошибки ещё до сборки. Это экономит массу времени.

./bin/hello_world 

Вывод в terminal:

./bin/hello_world: error while loading shared libraries: libflutter_linux_gtk.so: cannot open shared object file: No such file or directory

Ошибка указывает на отсутствие библиотеки, содержащей код, необходимый для работы Flutter-приложения на Linux: отображение окон, обработка событий, взаимодействие с системой и рендеринг графики. Также возможно нарушение структуры проекта, из-за чего библиотека не находится.

В итоге помог запрос к Perplexity, который помог понять, что проблема была именно со структурой. Это действительно логично, так как из папки build приложение запускается нормально.

Далее нужно было пересоздать каталог, скопировать в него правильно файлы и структуру и добавить остальные файлы, которые были созданы выше.

mkdir -p AppDir 
cp -r build/linux/x64/release/bundle/* AppDir/

Проверка запуска:

cd AppDir
export LD_LIBRARY_PATH="$PWD/lib:$LD_LIBRARY_PATH"

Команда export LD_LIBRARY_PATH="$PWD/lib:$LD_LIBRARY_PATH" добавляет путь к папке lib в текущей директории в список путей, где система ищет динамические библиотеки при запуске программ.

./hello_world

После того как окно приложения запустилось осталось только собрать его и проверить в собранном виде.

cd .. ./appimagetool-x86_64.AppImage AppDir 
chmod +x Hello_World-x86_64.AppImage
./Hello_World-x86_64.AppImage

Запуск из terminal:

./Hello_World-x86_64.AppImage

В результате запуска появилось окно приложения. Обе нейросети показали себя достаточно хорошо и помогли разобраться с возникающими проблемами. В итоге за один вечер мне удалось успешно собрать и запустить Flutter-приложение под Linux.


Поздравления с днём рождения

Так получилось, что день публикации статьи совпал с днём рождения Ивана — создателя и автора канала «Код на салфетке». Хочу поздравить его с праздником и пожелать всего самого наилучшего, а также дальнейших успехов в карьере и в развитии канала!


Планы на будущее

В следующей статье я продолжу проверять гипотезу, написав на Flutter и собрав что-то более сложное, чем Hello World. Мне предстоит разобраться в структуре проекта, синтаксисе языка Dart и в том, как создаётся внешний вид приложения. Также я хочу взять часть своего приложения Kivy и попробовать повторить похожий результат на Flutter.

Если кому-то интересен проект на Kivy, который я упоминал в начале статьи, то вы можете узнать о нём, перейдя по этой ссылке.

Если у вас есть мысли о том, как можно улучшить проект, пишите в комментариях — с удовольствием ознакомлюсь с вашими предложениями!

Читайте продолжение — не пропустите!

Аватар автора

Автор

Eugene Kaddo

Программист фрилансер. Пишу боты, парсеры и скрипты на Python3. По вопросам фриланс заказа программы пишите на почту, указанную в профиле. Автор статей по программированию. Увлекаюсь lego, робототехникой на arduino, рок музыкой, программированием на Python3 и C.

Войдите, чтобы оставить комментарий.

Комментариев пока нет.