Реализация Hot-загрузки мини-программ без обновления основного приложения
Главное преимущество мини-программ над нативными приложениями — возможность обновить пользователям новую версию мгновенно, без App Store Review и без того, чтобы пользователь что-то делал. Вечером исправили баг в JS-коде, утром все пользователи уже на новой версии. Это работает, если hot-loading реализован правильно. Если нет — пользователи видят старый баг неделями, или, что хуже, падающий экран после обновления bundle, которое пришло с ошибкой.
Как устроена система горячей загрузки
Hot-loading для мини-программ — это не то же самое, что Hot Module Replacement в Webpack. Это CDN-based delivery system с версионным контролем и rollback-возможностью.
Базовый flow:
- Разработчик публикует новую версию мини-программы (новый bundle.zip на CDN)
- Платформа обновляет manifest — JSON с метаданными и URL нового bundle
- Super App периодически (или при запуске) проверяет manifest-сервер
- Если версия изменилась — скачивает новый bundle в фоне
- При следующем открытии мини-программы — загружается новый bundle
Дьявол в деталях шагов 3-5.
Стратегии проверки обновлений
Polling при старте хоста. Самое простое: при каждом запуске Super App фоновый сервис проверяет manifest для всех установленных мини-программ. На 50 мини-программ — 50 HTTP-запросов или один batch-запрос с bulk manifest API. Задержка обновления: до следующего запуска приложения, в среднем несколько часов.
Long polling / Server-Sent Events. Хост держит открытое соединение с manifest-сервером. При публикации новой версии сервер push-уведомляет все подключённые клиенты. Мгновенная доставка, но: постоянное соединение жрёт battery и трафик, нестабильно на мобильных сетях. Подходит для enterprise-приложений, где важна мгновенная доставка обновлений.
Silent Push Notification. APNs background push (iOS) или FCM data message (Android) при публикации новой версии. Система будит приложение в фоне на 30 секунд (iOS) или без явного лимита (Android с Doze mode ограничениями), оно скачивает bundle. Оптимальный баланс между скоростью доставки и battery impact. Ограничение на iOS: APNs silent push может быть задроттлен системой.
На практике комбинируем: silent push как основной канал + polling при запуске как fallback для устройств, где push не дошёл.
Атомарное применение обновления
Критический момент: нельзя применять bundle во время активной сессии мини-программы. Если заменить файлы пока WebView работает — краш гарантирован.
Решение — staged swap:
/miniapps/com.vendor.app/
current/ <- текущий active bundle (v2.3.1)
pending/ <- скачанный, но ещё не применённый (v2.3.2)
rollback/ <- предыдущий bundle для отката (v2.3.0)
pending становится current только при следующем холодном старте мини-программы. Переименование директории — атомарная операция на уровне FS. Если в момент swap произошёл краш хоста — pending останется как есть, и попытка повторится при следующем запуске.
Верификация перед применением
Перед применением нового bundle — верификация:
// iOS
let expectedHash = manifest.bundleHash // "sha256:a3f8c2..."
let actualHash = SHA256.hash(data: bundleData).hexString
guard "sha256:\(actualHash)" == expectedHash else {
throw BundleError.hashMismatch
}
Дополнительно: проверка цифровой подписи манифеста (платформа подписывает manifest приватным ключом, клиент верифицирует публичным). Это защищает от атак, когда CDN подменяет bundle на вредоносный.
Если верификация провалилась — bundle удаляется, продолжаем использовать текущую версию. В аналитику — событие с hash mismatch для мониторинга.
Rollback при краше
Новая версия bundle может содержать JS-ошибку, которая приводит к краш-петле. Нужен автоматический rollback.
Механизм: контейнер считает consecutive crashes при загрузке мини-программы. Если 3 краша подряд при старте — откатываемся на rollback/ директорию (предыдущая известно-рабочая версия). Событие в аналитику, уведомление разработчику через портал.
Что считать крашем: WKWebView навигация завершилась с ошибкой, или JS выбросил uncaught exception в течение 2 секунд после загрузки, или bridge не ответил на init-handshake за 5 секунд.
На стороне платформы — возможность emergency rollback: изменить currentVersion в manifest на предыдущую. Все клиенты, проверившие manifest, скачают «старый» bundle. Это выполняется за минуты, не часы.
Дифференциальные обновления
При больших bundle (> 1 MB) — дифференциальные патчи вместо полной замены. Алгоритм bsdiff: для обновления v2.3.1 → v2.3.2 генерируется патч-файл, который в 10-30 раз меньше полного bundle. Клиент скачивает патч, применяет к текущему bundle, получает новый.
Требует хранения бинарного bundle на клиенте (не только распакованных файлов) для применения патча. Усложняет реализацию, но критически важно для пользователей с медленным интернетом.
Сроки реализации системы hot-loading с нуля (manifest API + CDN + client-side загрузчик с верификацией + rollback): от 6 до 12 недель. С дифференциальными патчами — добавьте ещё 3-4 недели.







