Аудиокниги — сложный контент: файлы на 15 часов, нестабильное соединение, пользователи требуют точного возврата к позиции. Типичный баг — при переключении между Wi-Fi и LTE плеер теряет прогресс, а таймер сна обрывает главу без fade-out. Мы решили это на уровне архитектуры: агрессивное кеширование через URLSession background tasks, синхронизация позиции с облачным хранилищем каждые 5 секунд, плавное затухание перед остановкой. Результат — приложение не вылетает, позиции сохраняются, пользователи не жалуются.
Форматы файлов и потоковое воспроизведение
Аудиокниги чаще всего в форматах: MP3 (самый широкий), M4B (AAC с chapter markers, стандарт Apple), M4A, OGG/Opus. M4B предпочтителен для новых каталогов — он нативно содержит главы, обложку и метаданные без сайдкара.
Потоковое воспроизведение (не скачивать полностью перед воспроизведением): AVPlayer на iOS открывает HTTP URL и начинает играть без полной загрузки. ExoPlayer (Media3) на Android — аналогично через DefaultDataSource.Factory. Для длинных файлов (15 часов = ~800 МБ) это критично.
Главы из M4B: AVAsset.loadChapterMetadataGroups(bestMatchingPreferredLanguages:) возвращает AVTimedMetadataGroup[] с временными метками и названиями. На Android — MediaMetadataRetriever.extractMetadata + парсинг MP4 box structure для chapter atoms, либо используем ExoPlayer с кастомным MetadataRetriever.
Почему M4B — лучший выбор для нового каталога?
M4B использует контейнер MP4 с встроенными chapter markers, что упрощает навигацию и хранение метаданных. В отличие от MP3 не требуется внешний файл глав. При потоковой передаче клиент сразу получает структуру книги.
Точное сохранение позиции
Пользователь слушает книгу в машине, закрывает приложение — при следующем открытии должен попасть ровно на то место. С точностью до секунды.
Сохраняем currentTime (Double, секунды) + bookId + timestamp сохранения в UserDefaults/SharedPreferences при каждом фоновом переходе, уходе в background (applicationDidEnterBackground) и через Timer каждые 5 секунд во время воспроизведения. Timer каждые 5 секунд — не каждую секунду, это избыточно.
При восстановлении: player.seek(to: CMTime(seconds: savedPosition, preferredTimescale: 1000)) с .seconds точностью. Не MSEC — для аудио достаточно.
Синхронизация между устройствами: CloudKit CKRecord (iOS) или Firebase Firestore с userId/bookId ключом. При открытии книги на новом устройстве предлагаем «Продолжить с 1:23:45» — пользователь решает.
Как обеспечить бесшовную синхронизацию?
Используем облачное хранилище с конфликт-резолюцией «last write wins». При каждом сохранении позиции отправляем запрос в Firestore/CloudKit с временной меткой. При загрузке книги на другом устройстве сравниваем метки и выбираем актуальную. Дополнительно храним локальный кеш на случай отсутствия сети.
Таймер сна
Популярная функция: воспроизведение останавливается через N минут. Тривиально — DispatchQueue.main.asyncAfter (iOS) или Handler.postDelayed (Android). Нетривиальный вариант: «остановить в конце текущей главы» — получаем endTime текущей главы из метаданных и планируем остановку на это время.
Плавное затухание перед остановкой: за 30 секунд до конца уменьшаем player.volume линейно до 0 через CADisplayLink / ValueAnimator. Не резкая остановка — это раздражает.
Технические детали плавного затухания
Используем таймер с частотой 60 FPS (CADisplayLink на iOS, Choreographer на Android). Каждое обновление уменьшает громкость на (1/60)*(1/30) = 0.00056. По достижении времени остановки ставим player на паузу и возвращаем громкость к исходной для следующего воспроизведения.Скорость воспроизведения и pitch correction
player.rate = 1.5 (AVPlayer) ускоряет воспроизведение, но поднимает pitch — голос становится писклявым. iOS автоматически применяет pitch correction для AVPlayer при rate ≠ 1.0 начиная с iOS 16. На более старых — AVAudioUnitTimePitch в AVAudioEngine pipeline.
Android ExoPlayer: playbackParameters = PlaybackParameters(speed = 1.5f) — pitch correction встроен. Flutter just_audio: player.setSpeed(1.5) с pitchCorrectionMethod по умолчанию.
Диапазон полезных скоростей: 0.75x (для сложного технического контента), 1.0x, 1.25x, 1.5x, 2.0x. Больше 2x — разборчивость падает критически.
| Скорость | Применение | Pitch correction |
|---|---|---|
| 0.75x | Технический контент | Авто |
| 1.0x | Стандарт | Нет |
| 1.25x | Ускоренное прослушивание | Да |
| 1.5x | Быстрое чтение | Да |
| 2.0x | Предел разборчивости | Да |
"For audio playback, AVPlayer applies pitch correction when the rate is not 1.0." — Apple AVPlayer documentation.
Офлайн-скачивание и DRM
Скачивание для офлайна — URLSessionDownloadTask + URLSessionConfiguration.background (iOS): работает даже когда приложение не запущено, прогресс сохраняется при крашах. Android: WorkManager + DownloadManager или OkHttp с кастомным прогрессом.
Для платного контента нужен DRM. FairPlay Streaming (iOS) — интегрируется с AVContentKeySession. Widevine L3 (Android) — ExoPlayer с DefaultDrmSessionManager. Ключ шифрования запрашивается у лицензионного сервера при каждом воспроизведении. Без DRM пользователь копирует файл из /Library/Application Support и слушает без подписки.
Альтернатива без full DRM: AES-256 шифрование файла на диске с ключом, привязанным к аккаунту и DeviceID. Дешевле в реализации, но меньше защиты.
| DRM | iOS | Android |
|---|---|---|
| FairPlay Streaming | AVContentKeySession | — |
| Widevine L3 | — | ExoPlayer + DrmSessionManager |
| AES-256 self-managed | CommonCrypto | Android Keystore |
Каталог и поиск
Библиотека пользователя: купленные и скачанные книги. Каталог магазина: поиск, жанры, новинки, рекомендации. Пагинация через cursor (Alchemy-style next token или offset/limit). Обложки — через SDWebImage/Coil/cached_network_image с агрессивным disk cache (обложки меняются редко).
Что входит в работу
- Исходный код приложения (iOS/Android) с комментариями.
- API-документация и схема базы данных.
- Доступы к App Store Connect / Google Play Console.
- Обучение команды заказчика (2-3 сессии).
- Техническая поддержка на 3 месяца после релиза.
- Интеграция с existing backend или настройка нового.
| Функция | MVP | Полная версия |
|---|---|---|
| Воспроизведение MP3/M4B | да | да |
| Главы и навигация | нет | да |
| Офлайн-скачивание | нет | да |
| Синхронизация позиции | нет | да |
| DRM | нет | да |
| Таймер сна | да | да |
Сроки: MVP-плеер с каталогом и базовым воспроизведением — 3-4 недели. Полный продукт с DRM, офлайном, синхронизацией и подпиской — 8-12 недель. Экономия на лицензиях DRM при использовании self-managed AES-256 может достигать 30%.
Хотите обсудить ваш проект? Свяжитесь с нами — оценим архитектуру и предложим оптимальное решение. Закажите разработку приложения для аудиокниг под ключ.







