Как создать EPUB Reader на Flutter без разработки с нуля: гибридный подход

Михаил
Михаил
Head of Mobile Department
05.08.2025
217
0

Сегодня cложно найти пользователя, который никогда бы не сталкивался с электронными книгами в формате EPUB: он открыт, гибок и совместим практически с любыми устройствами. Но реализация воспроизведения EPUB в кроссплатформенном мобильном приложении может оказаться неожиданно сложной задачей.

Давайте обсудим Ваш проект
Заполните личные данные.
Phone
Нажимая на кнопку “Отправить”, вы даете согласие на обработку личных данных. Подробнее

Именно с такой задачей мы столкнулись в нашем недавнем проекте для ведущего украинского издательства КСД. Подробности кейса скоро можно будет рассмотреть в портфолио WEZOM: клиент обратился к нам с запросом на разработку мобильного приложения с кастомным EPUB-ридером. Требовалось не просто "сделать читалку", а обеспечить в продукте стабильность, быстродействие и комфорт для читателя, соединив все это с надежной защитой авторского контента в экосистеме КСД. 

Сегодня мы расскажем, как команде удалось реализовать кастомный EPUB ридер на Flutter без написания движка с нуля, благодаря применению гибридных технологий. Это позволило существенно ускорить разработку и сэкономить огромные ресурсы, предоставив клиентам и пользователям достойный продукт. 

Вызовы при создании EPUB ридера на Flutter

Издательство нуждалось в качественном мобильном приложении для Android и iOS, которое работало бы и как онлайн-магазин, и как удобный ридер для купленных там электронных книг. Ключевыми требованиями к этому решению был высококачественный UX, продуманная эстетика и надежная защита авторского контента от недобросовестного копирования. 

Кроссплатформенная разработка EPUB-ридера в приложении была оптимальным вариантом, поэтому техническая команда сделала очевидный выбор в пользу фреймворка Flutter. Он имеет собственный графический движок и позволяет создавать сложные приложения на Android/iOS с единой кодовой базой, которые практически ни в чем не уступают нативным. Но гибридное Flutter-приложение с EPUB-ридером поставило перед разработчиками нетривиальные задачи.

Преимущества Flutter для разработки EPUB ридера: кроссплатформенность, производительность, UI, плагины, тестирование

В чем крылась проблема?

Дело в том, что EPUB, несмотря на свою открытость, остается достаточно сложным для работы форматом. Если бы речь шла только о тексте, проблем не было бы. Но EPUB – это практически целый сайт в ZIP-архиве. Он содержит HTML-файлы (разделы книги) и CSS-стили, определяющие вид книги в цифре. В архив также входят шрифты, изображения и т.д. 

Flutter как таковой не имеет инструментов для работы с веб-контентом: он не может рендерить HTML и CSS. Его главная задача – отрисовывать на экране свои виджеты (кнопки, текст, контейнеры). 

Имеющиеся пакеты Flutter могут преобразовывать HTML-теги в виджеты фреймворка. Для простой статьи в блоге этого могло бы хватить, но в нашем случае речь шла о целых книгах со сложной версткой, стилями и интерактивностью (как в EPUB 3). Требовалось решение, которое поддерживает сложный CSS и может выполнять JavaScript.

Чтобы реализовать замысел проекта в полном объеме, команде фактически нужно было бы написать собственный браузерный движок, который умеет:

  • Парсить структуру EPUB, то есть правильно "читать" служебные файлы, чтобы понять порядок разделов, содержание и метаданные;

  • Рендеринг HTML/CSS, чтобы корректно отобразить каждую страницу-раздел со всеми стилями и возможностями настройки;

  • Проводить пагинацию – то есть динамически разбивать "плавающий" HTML-текст на страницы, с учетом размера экрана и выбранного пользователем шрифта. Это очень нетривиальный алгоритм, работа над ним была бы наиболее сложным аспектом разработки. 

Создание такого движка с нуля – это целый проект в проекте, колоссальная работа. И проводить эту работу в рамках запроса на создание приложения было неоправданно дорого и долго. Так что мы начали искать альтернативы.

Решение: гибридный подход с WebView

Если разработать собственный веб-движок в рамках проекта невозможно, нужно было найти где-то готовое решение и приспособить его под наши задачи. И такой инструмент есть – это встраиваемый компонент WebView. По сути это браузер, который можно встроить в приложение.

Полноценная интеграция WebView в Flutter дала проекту важные преимущества: 

  • Отпала потребность в собственном движке для рендеринга – разработчики взяли готовый, мощный и оптимизированный движок, который уже есть в каждом смартфоне.

  • Полная поддержка веб-технологий. Ведь WebView "из коробки" понимает HTML, CSS и JavaScript, что идеально подходит для формата EPUB 3.

  • Множество готовых решений. Команда получила возможность использовать любые существующие JS-библиотеки, созданные специально для отображения книг. Именно они взяли на себя всю сложную логику пагинации внутри WebView. 

Flutter WebView EPUB: преимущества рендеринга EPUB через WebView в мобильном приложении

Подобные решения существовали и раньше. Например, демонстрационный опенсорсный проект BookReader App использует связку epub.js, Flutter и WebView для воспроизведения EPUB в формате мобильного приложения. По схожей логике работает и Kotobee Reader – популярный "читатель" электронных книг EPUB на Android и iOS. Наша задача заключалась в том, чтобы реализовать эту логику кастомно – на высоком уровне, с учетом всех потребностей бизнеса клиента. 

Сокращение времени разработки через WebView позволило команде высвободить огромные ресурсы и сконцентрироваться на других аспектах разработки, сокращая затраты проекта и приближая релиз продукта. 

Применение WebView для отображения EPUB: технические тонкости

Flutter имеет базовую поддержку WebView через плагины (webview_flutter для Android и iOS). Но для более сложных сценариев, таких как передача команд между Flutter и JavaScript или работа с нативным парсингом, необходима гибридная архитектура с использованием Method Channels. Чтобы сделать WebView "послушным", важно четко определить точки входа/выхода – только так Flutter, нативный код и JS могут работать как одно целое.

Чтобы реализовать в WebView полноценный парсинг и рендеринг EPUB-файлов, необходимо использовать одну из соответствующих JS-библиотек. Кратко взглянем на самые популярные из них: 

JavaScript библиотеки для EPUB: Epub.js, Readium и Vivliostyle во Flutter EPUB ридерах

  • Epub.js

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

  • Readium

Readium JS / Readium Web – это комплексный набор инструментов, созданный консорциумом Readium Foundation. Он фокусируется на полном соответствии стандартам EPUB, включая расширенную поддержку EPUB 3 и функции доступности для инклюзивного чтения.

  • Vivliostyle 

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

Первой идеей команды разработчиков было обращение к самой популярной библиотеке. Однако JS библиотека Epub.js не подошла, поскольку предназначена для браузеров. Она выполняет весь парсинг EPUB-файла в JavaScript и не имеет нативной поддержки под Kotlin/Swift. Это делало Epub.js непригодной для использования в мобайле с высокими требованиями к производительности и стабильности.

Как мы реализовали парсинг EPUB?

Итак, обычный парсинг EPUB в JavaScript – это неэффективное решение. Такая обработка была бы слишком медленной, особенно для больших книг. Что же делать? Мы нашли более действенный подход: реализовать парсинг на нативной стороне с помощью специализированных библиотек Readium. Экосистема Readium Foundation предлагает для этого незаменимые инструменты: 

  • readium/kotlin-toolkit для Android.

  • readium/swift-toolkit для iOS.

Эти библиотеки делают всю сложную работу: распаковывают архив, анализируют структуру, готовят контент. После этого Readium запускает локальный веб-сервер непосредственно в приложении. Этот сервер раздает файлы книги (HTML, CSS, картинки) для воспроизведения в WebView.

Что в итоге? Парсинг EPUB на Flutter на самом деле осуществляется через нативный код Kotlin/Swift. А JS-код в WebView отвечает только за отображение (рендеринг) уже проработанного контента.

Как устроено гибридное Flutter-приложение EPUB

Чтобы создать EPUB-ридер/мобильное приложение, которое сочетает удобство Flutter, мощность нативного кода и гибкость веб-решений, мы реализовали трехуровневую гибридную архитектуру. Это позволило нам добиться высокой производительности, стабильности и гибкого взаимодействия между всеми компонентами продукта. 

В общих чертах наша архитектура выглядит так:

Архитектура гибридного Flutter-приложения EPUB с WebView и нативным парсингом

1.  Flutter (уровень UI)

Все, что видит пользователь, с чем он взаимодействует – это виджеты Flutter: кнопки, панели, настройки, интерактивные элементы и т.д. Сам ридер (модуль для чтения) встраивается в приложение как отдельный компонент в Flutter UI.

2.  Native (логика+парсинг EPUB)

На уровне Android (Kotlin) и iOS (Swift) в приложении используется Readium SDK, отвечающий за парсинг. Это “черный ящик”, где происходит вся “магия” вокруг EPUB:

  • Распаковка файла;

  • Парсинг его структуры;

  • Запуск локального веб-сервера, который раздает контент в WebView

3.  JavaScript в WebView (рендеринг)

WebView подключается к локальному серверу и загружает EPUB-ридер на базе Readium Web. Именно здесь происходит:

  • Отображение текста;

  • Пагинация;

  • Функционал UI: поиск, выделение, аннотации, изменение шрифтов, тем;

  • Обработка жестов (перелистывание) и т.д. 

Как Flutter взаимодействует с JavaScript

Прямого взаимодействия здесь нет. Для настройки связи между Flutter и WebView мы использовали Method Channel – официальный механизм Flutter для обмена данными с нативным кодом. Проще всего будет объяснить эту логику с помощью практических примеров работы читателя с приложением: 

  • Изменение размера шрифта:
    • Пользователь жмет на кнопку + во Flutter-интерфейсе.

    • Flutter отправляет команду на нативную сторону: {'action': 'setFontSize', 'value': '18px'}.

    • Нативный код (Kotlin/Swift) получает команду и выполняет JS-код в WebView: webView.evaluateJavascript("reader.setFontSize('18px')").

    • Код JS изменяет CSS-стили книги.

  • Пролистывание страниц
    • Код JS на стороне WebView фиксирует пролистывание и определяет новую позицию в книге.

    • JS вызывает специальную функцию, которая передает данную позицию нативному коду.

    • Нативный код получает позицию и отправляет ее во Flutter.

    • Flutter получает данные и обновляет свой виджет, например, Страница 5 из 120.

Такое взаимодействие «Flutter-WebView» в EPUB-ридере может казаться не очень элегантным, но на самом деле оно работает в разы быстрее, чем обработка всех интеракций непосредственно на стороне WebView. 

Оптимизация EPUB ридера для Android и iOS

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

  • Адаптация интерфейса под разные платформы

Логика виджетов Flutter позволила команде легко адаптировать визуал и функциональность продукта под Android и iOS, соблюдая нативные гайдлайны. Панели управления, кнопки и жесты пролистывания ведут себя одинаково предсказуемо на обеих платформах. Более того, мы учли специфику системных WebView: Safari на iOS и Chrome на Android.

Таблица: Гайдлайны дизайна мобильных приложений для Android и IOS
Характеристика Android (Material Design) iOS (Human Interface Guidelines)
Дизайн-философия Яркие цвета, глубина, тени, четкая иерархия элементов Простота, минимализм, акцент на контент и плавность
Платформенные отличия UI Floating Action, насыщенные цвета, акценты Пространство, чистота, легкость, минимализм
Компоненты интерфейса Материальные кнопки, чекбоксы, разделенные поля ввода Тумблеры, списки настроек, интегрированные текстовые поля
  • Ускорение загрузки страниц EPUB

 Высокая производительность EPUB Reader на Flutter была одним из главных требований проекта. Ключом к быстродействию стало разделение парсинга и рендеринга, который мы уже описывали выше. Readium SDK позволил использовать для парсинга нативный код и мгновенно выводить его в WebView. Книги любого объема и сложности открываются мгновенно, словно приложение имеет собственный нативный движок для рендеринга EPUB.

  • Безопасность и стабильность

Мы обеспечили:

  • Контролируемый и стабильный обмен данными: Flutter - нативный EPUB reader - WebView. Через Method Channels передаются только минимально необходимые данные (команды, номера страниц).

  • Ограничение доступа к файловой системе: книги не хранятся в открытом виде;

  • Стабильный рендеринг в случае нестандартных EPUB-файлов, ведь Readium SDK "переваривает" даже поврежденные или устаревшие книги.

Дополнительный функционал для читателя электронных книг

Помимо базового отображения контента современный EPUB-ридер должен обеспечивать комфортное, гибкое и персонализированное чтение. В нашем проекте мы реализовали ряд функций, которые делают этот опыт приятным и удобным вне зависимости от предпочтений пользователя или типа устройства.

UX-функции EPUB ридера на Flutter: тёмная тема, поиск, настройки текста, сохранение прогресса

  • Сохранение прогресса и закладок

 Читатель может продолжить чтение с того места, где остановился – позиция автоматически сохраняется в памяти приложения. У него есть возможность создавать закладки и свободно переходить между ними через интерфейс ридера. Все данные хранятся локально. 

  • Поиск по тексту и масштабирование

В кастомном ридере предусмотрена возможность поиска по тексту через ключевые слова и фразы. Пользователь также имеет полную свободу настройки отображения страниц EPUB WebView: выбор и масштабирование шрифтов, изменение размеров, интервалов, полей и т.д. Эти функции работают через Method Channels.

  • Темная тема и кастомизация интерфейса

Современное чтение – это чтение в любых условиях: днем, ночью, в транспорте или на улице. Мы реализовали темную тему, выбор цвета фона и текста, а также широкие возможности кастомизации интерфейса. Все стили применяются динамически через CSS и JavaScript, сохраняя при этом скорость рендеринга страниц.

Тестирование и отладка приложения

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

  • Как протестировать EPUB-ридер? 

Прежде всего в арсенале Readium есть набор Test Books. Он содержит набор тестовых EPUB-файлов, охватывающих специфические случаи: устаревшие форматы, поврежденные файлы и т.д. Более того, команда собрала собственную коллекцию EPUB-файлов с разными уровнями сложности: простые книги, экзотические форматы, файлы с нестандартной версткой, книги с множеством изображений, книги со сложными и перегруженными стилями и пр. Мы несколько раз прогнали все наборы через приложение, чтобы убедиться, что оно воспроизводит любые файлы корректно. 

  • Обеспечение совместимости 

В этом направлении команда не столкнулась с существенными проблемами. Прежде всего благодаря тому, что Readium – это стандарт индустрии. Его библиотеки способны "переваривать" практически любые EPUB-файлы и исправлять незначительные проблемы "на лету". Использование системного WebView (Chrome – Android, Safari – iOS) гарантирует, что книга будет корректно открываться и выглядеть одинаково на 99% устройств. С учетом различий между движками Chrome/Safari стили и скрипты дополнительно тестировались отдельно на обеих платформах.

Выводы 

Как оказалось, кроссплатформенная разработка мобильного EPUB-ридера – это не просто техническая задача, а настоящий вызов, требующий баланса между производительностью, гибкостью и удобством для пользователя. В кейсе КСД мы реализовали гибридную архитектуру, объединяющую Flutter, нативный код и WebView, чтобы обеспечить стабильную работу с EPUB-контентом без компромиссов в быстродействии или качестве.

Благодаря использованию Readium SDK нам удалось создать быструю и стабильную кроссплатформенную EPUB-читалку, которая работает одинаково хорошо на Android и iOS. Так мы предоставили нашему клиенту продукт достойного качества, а конечным пользователям качественный опыт потребления контента. Издательство КСД обеспечило своим пользователям уникальный сервис и защитило интеллектуальную собственность своих партнеров. Это решение имеет мало аналогов не только на украинском, но и на глобальном рынке. 

Команда WEZOM получила в данном проекте уникальный опыт и готова масштабировать и развивать продукт, ведь жизненный путь нового приложения только начался. А если у вас есть дополнительные вопросы по такой разработке или ищете кастомные решения для собственного бизнеса, обращайтесь прямо сейчас! Мы готовы помочь.

FAQ

Как настроить epub.js для работы с Flutter WebView?

Чтобы настроить epub.js во Flutter, нужно загрузить его в WebView через локальный HTML-файл, подключить библиотеку и инициализировать ридер в JavaScript. Но по нашему опыту такая интеграция будет не лучшим решением. Лучше обратить внимание на библиотеки Readium.

Можно ли добавить офлайн-режим в гибридный EPUB ридер?

Да, можно. В нашем кейсе EPUB файл сохраняется локально, а WebView работает через локальный веб-сервер, поэтому весь контент доступен без Интернета. Офлайн-режим реализуется полностью на пользовательском устройстве.

Как реализовать поддержку больших EPUB файлов в Flutter?

В нашем кейсе эту задачу удалось решить благодаря нативному парсингу через Readium SDK. Впрочем, в других проектах эта задача может решаться другими путями – через подбор соответствующей JS-библиотеки или через написание собственного браузерного движка. Всё зависит от потребностей бизнеса.

Какие преимущества гибридного подхода перед нативными EPUB ридерами?

Разница между нативным и гибридным ридером кроется в сложности разработки. Гибридный подход позволяет быстро разработать EPUB-читалку с использованием WebView и готовых библиотек, обеспечивая полную поддержку HTML/CSS. Это экономит ресурсы, упрощает обновление и дает гибкость в кастомизации интерфейса без разработки собственного движка с нуля.

Возможна ли интеграция посторонних плагинов для EPUB во Flutter приложение?

Да, возможна. Посторонние JavaScript-плагины для EPUB можно интегрировать в WebView, а взаимодействие с Flutter реализовать через метод-каналы. Это позволяет расширять функционал ридера без изменений в самом Flutter-приложении.

Как настроить защиту от копирования текста в EPUB ридере?

Чтобы защитить текст от копирования, можно отключить выделение текста и контекстное меню через CSS (user-select: none) и JavaScript. Также WebView позволяет блокировать длинные нажатия. Следует также ограничить доступ к файловой системе и не сохранять EPUB в открытом виде. Защиту могут предоставить специализированные DRM-решения, такие как Readium LCP.

Михаил
Про автора
Михаил
Head of Mobile Department
6
Управляет командами и отвечает за реализацию приложений для iOS, Android и кроссплатформенных технологий (Flutter, React Native). Обладает экспертизой в архитектуре, UX/UI и полном цикле разработки мобильных продуктов. Под его руководством создано десятки приложений для e-commerce, логистики, медицины, страхования и финансов. Обеспечивает баланс между потребностями клиента, технологическими возможностями и удобством для пользователя.
Больше статей от автора
Как вам статья?
Давайте обсудим Ваш проект
Заполните личные данные.
Phone
Нажимая на кнопку “Отправить”, вы даете согласие на обработку личных данных. Подробнее
Свернуть
Комментарии
(0)
Будьте первыми, кто оставит комментарий
have questions image
Остались вопросы?
Оставьте ваши контактные данные. Наш менеджер свяжется и проконсультирует вас.
Подписывайтесь на рассылку Айтыжблог
blog subscriber decor image
Хотите получать интересные статьи?
Нажимая на кнопку “Отправить”, вы даете согласие на обработку личных данных. Подробнее
Следите за нами в социальных сетях