Інтеграція камери (відео) в мобільний додаток
Запис відео тяжче фото в кожному сенсі: більше дозволів, більше пам'яті, більше точок відмови. Додаток для знайомств хоче відеоанкети до 30 секунд — здається тривіально, але AVAssetExportSession падає з exportFailed на iPhone SE з iOS 16.4 при певній комбінації дозволу і бітрейту.
Основні складності
Обмеження довжини запису. На iOS немає вбудованого обмеження в AVCaptureMovieFileOutput — таймер потрібно реалізовувати вручну і явно викликати stopRecording(). Пропустиш — користувач запише 40-хвилинний ролик, який потім неможливо завантажити.
Розмір файлу. 30 секунд в 4K на iPhone 15 Pro — близько 600 МБ при дефолтних налаштуваннях. Для більшості додатків це неприйнятно. Перед завантаженням потрібне транскодування: AVAssetExportSession з AVAssetExportPresetMediumQuality або конкретним AVVideoCompressionPropertiesKey + AVVideoAverageBitRateKey. На Android — MediaCodec напрямо або через Transformer з media3.
Вибір із галереї. PHPickerViewController з PHPickerFilter.videos на iOS 14+. Важливий нюанс: loadFileRepresentation(forTypeIdentifier: "public.movie") копіює файл у тимчасову директорію — потрібно встигти його обробити до наступного запуску додатку або явно перемістити в Documents.
Як реалізуємо
iOS. AVCaptureSession + AVCaptureMovieFileOutput для кастомної камери з повним контролем над параметрами. Для простих сценаріїв — UIImagePickerController з mediaTypes: [kUTTypeMovie as String]. Відео стискаємо через AVAssetExportSession, обираючи пресет залежно від призначення: AVAssetExportPreset960x540 для превью, AVAssetExportPreset1280x720 для основного контенту.
let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPreset1280x720)
exportSession?.outputURL = outputURL
exportSession?.outputFileType = .mp4
exportSession?.exportAsynchronously { ... }
Android. CameraX VideoCapture API стабілізувався в 1.3.x. Запис через Recorder → PendingRecording → Recording. Обмеження за часом — stop() в Handler.postDelayed. Стискання — Transformer з androidx.media3:media3-transformer (заміна застарілого TranscodingTransformer).
Flutter. camera (pub.dev) для кастомної камери, image_picker для вибору з галереї. Для транскодування — video_compress або виклик нативного коду через MethodChannel.
Завантаження
Відеофайли грузимо чанками (multipart або resumable upload). На iOS — URLSessionUploadTask з background конфігурацією. На Android — WorkManager + OkHttp, щоб завантаження не перервалось при сворачуванні. Прогрес передаємо в UI через StateFlow або LiveData.
Превью записаного відео
Після запису користувач повинен побачити превью перед відправкою. На 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'.
Строки
Стандартна інтеграція (запис з обмеженням, вибір з галереї, стискання, завантаження) — 2–3 дні. Кастомний інтерфейс камери з власним UI управління — плюс 1–2 дні.







