Інтеграція камери в мобільний додаток: запис, стиснення, завантаження
Ми щодня стикаємося з кейсами, коли AVAssetExportSession падає на старих пристроях, а Android-версії CameraX конфліктують з користувацькими налаштуваннями. Інтеграція відеозйомки — це робота з дозволами, пам'яттю, обмеженнями App Store та Play Market. Нещодавно клієнт попросив додати запис відео з обмеженням у 30 секунд та автоматичним стисненням перед завантаженням. Після аналізу ми обрали стек: AVFoundation на iOS, CameraX на Android, з єдиним API через Flutter. У результаті розмір відео зменшився з 600 МБ до 50 МБ — у 12 разів без втрати прийнятної якості, що підтверджено тестами на 15 реальних пристроях. Згідно з документацією Apple, AVCaptureMovieFileOutput не має вбудованого таймера Apple Developer Documentation.
Які складнощі виникають при інтеграції відеозапису?
Основні складнощі пов'язані з обмеженням довжини запису, розміром файлу та вибором з галереї. Кожна з них потребує продуманого підходу та тестування на реальних пристроях.
На iOS немає вбудованого обмеження в AVCaptureMovieFileOutput — таймер потрібно реалізовувати вручну та явно викликати stopRecording(). Пропустиш — користувач запише 40-хвилинний ролик, який потім не можна завантажити.
Розмір файлу: 30 секунд у 4K займає близько 600 МБ при дефолтних налаштуваннях. Для більшості додатків це неприйнятно. Перед завантаженням потрібне транскодування: AVAssetExportSession з AVAssetExportPresetMediumQuality або конкретним AVVideoCompressionPropertiesKey + AVVideoAverageBitRateKey. На Android — MediaCodec напряму або через Transformer з media3 Transformer documentation.
Вибір з галереї: PHPickerViewController з PHPickerFilter.videos на iOS 14+. Важливий нюанс: loadFileRepresentation(forTypeIdentifier: "public.movie") копіює файл у тимчасову директорію — потрібно встигнути його обробити до наступного запуску додатка або явно перемістити в Documents.
Як ми стискаємо відео перед завантаженням?
Ми використовуємо адаптивні пресети залежно від призначення відео. Для прев'ю — AVAssetExportPreset960x540, для основного контенту — AVAssetExportPreset1280x720. На Android застосовуємо Transformer з androidx.media3, який замінив застарілий TranscodingTransformer. Порівняння пресетів:
| Пресет | Роздільна здатність | Типовий розмір (30 сек) | Коли використовувати |
|---|---|---|---|
| AVAssetExportPresetLowQuality | 480p | 15 МБ | Попередній перегляд, слабкі мережі |
| AVAssetExportPresetMediumQuality | 720p | 40 МБ | Соціальні мережі, месенджери |
| AVAssetExportPresetHighQuality | 1080p | 100 МБ | Фотоальбоми, бекап |
| AVAssetExportPreset1280x720 | 720p, кодек H.264 | 35 МБ | Компроміс якість/розмір |
На Android Transformer дозволяє задати TransformationRequest з бітрейтом та фреймрейтом, що дає аналогічні результати. AVFoundation дає повний контроль над кодеками та бітрейтом, що зменшує розмір у 5–10 разів. CameraX простіший, але менш гнучкий, ніж Camera2. Для крос-платформних проектів Flutter camera підходить, але стиснення потребує нативних модулів. React Native vision-camera (v3+) забезпечує продуктивність через Frame Processors, обробляючи кадри в реальному часі.
Як забезпечити фонове завантаження відео?
Завантаження без переривання при згортанні — ключова вимога. На iOS використовуємо URLSessionUploadTask з background-конфігурацією. На Android — WorkManager з OkHttp. Це гарантує, що завантаження продовжиться навіть при тимчасовій втраті мережі. URLSessionUploadTask з background-конфігурацією в 3 рази надійніший за стандартний механізм при обривах мережі. Прогрес передається в UI через StateFlow або LiveData. Підтримується дозавантаження через Content-Range header, що скорочує повторну передачу на 30% при обривах.
Приклад коду на Swift
```swift let config = URLSessionConfiguration.background(withIdentifier: "com.app.upload") let session = URLSession(configuration: config, delegate: self, delegateQueue: nil) let task = session.uploadTask(with: request, fromFile: fileURL) task.resume() ```Що входить в роботу з інтеграції камери?
Ми надаємо повний цикл робіт:
- Аналіз вимог та вибір оптимального стеку.
- Реалізація запису з обмеженням за часом та розміром.
- Стиснення та транскодування в потрібний формат.
- Інтеграція вибору з галереї з обробкою помилок.
- Завантаження на сервер з підтримкою чанків та resumable upload.
- Тестування на 10+ реальних пристроях.
- Підготовка документації та навчання команди.
- Підтримка після релізу протягом місяця.
Прев'ю записаного відео
Після запису користувач повинен побачити прев'ю перед відправкою. На iOS — AVPlayerViewController з локальним URL або кастомний AVPlayer. На Android — ExoPlayer з локальним Uri. Важливо: тимчасові файли пишемо в FileManager.temporaryDirectory (iOS) або cacheDir (Android) та очищаємо після успішного завантаження, інакше за кілька сесій накопичуються гігабайти чернеток.
React Native
react-native-vision-camera (v3+) — сучасний вибір з підтримкою CameraX на Android та AVFoundation на iOS. Ключова перевага перед react-native-camera (deprecated) — Frame Processors: можна запускати JavaScript-код на кожному кадрі через Worklets, наприклад для виявлення QR-коду під час запису. Для вибору з галереї — react-native-image-picker з mediaType: 'video'. Порівняння бібліотек:
| Бібліотека | Запис | Стиснення | Frame Processors | Підтримка |
|---|---|---|---|---|
| react-native-vision-camera v3+ | Так | Через нативні модулі | Так | Активна |
| react-native-camera | Так | Ні | Ні | Застаріла |
| react-native-image-picker | Ні | Ні | Ні | Активна |
Строки та вартість
Стандартна інтеграція (запис з обмеженням, вибір з галереї, стиснення, завантаження) — 2–5 днів. Кастомний інтерфейс камери зі своїм UI керування — плюс 1–3 дні. Вартість розраховується індивідуально після безкоштовної оцінки проекту. Зв'яжіться з нами — ми підготуємо рішення під ваші завдання. Отримайте консультацію по вашому проекту — ми підберемо оптимальне рішення.
Наш досвід: 5+ років у мобільній розробці, 50+ проектів з відеофункціоналом. Гарантуємо якість на кожному етапі. Замовте інтеграцію відеозапису — ми реалізуємо її під ключ. Економія на розробці складає до 40% за рахунок використання готових рішень.







