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

Михаил
Михаил
Head of Mobile Department
5.0
01.08.2025
1840
0

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

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

Именно с такой задачей мы столкнулись в нашем недавнем проекте для ведущего украинского издательства КСД. Подробности кейса скоро можно будет рассмотреть в портфолио 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, логистики, медицины, страхования и финансов. Обеспечивает баланс между потребностями клиента, технологическими возможностями и удобством для пользователя.
Больше статей от автора
Как вам статья?
5.0
Проголосовало: 1
Обсудить проект
Заполните личные данные.
Phone
Нажимая на кнопку “Отправить”, вы даете согласие на обработку личных данных. Подробнее
Шаг 1 из 2
Комментарии
(0)
Будьте первыми, кто оставит комментарий
have questions image
Остались вопросы?
Оставьте ваши контактные данные. Наш менеджер свяжется и проконсультирует вас.
Подписывайтесь на рассылку Айтыжблог
blog subscriber decor image
Хотите получать интересные статьи?
Нажимая на кнопку “Отправить”, вы даете согласие на обработку личных данных. Подробнее
Следите за нами в социальных сетях