Screen Broadcasting — трансляция экрана мобильного приложения — востребована в сценариях демонстрации, технической поддержки, стриминга и удалённого обучения. На iOS доступен только ReplayKit с жёстким лимитом памяти 50 МБ в Broadcast Extension, а на Android — MediaProjection с возможностью захвата в реальном времени. Неправильная реализация ведёт к потере кадров, перерасходу памяти и сбоям под нагрузкой. Мы решаем эти проблемы: оптимизируем downscale видео, внедряем heartbeat-мониторинг для контроля состояния трансляции и подбираем оптимальный протокол — RTMP, SRT или WebRTC. Наши инженеры имеют 7+ лет опыта в мобильной разработке, реализовали более 30 проектов со стримингом экрана и с 2018 года на рынке. Получите предварительную оценку вашего проекта — просто свяжитесь с нами.
Особенности Screen Broadcasting на iOS
Трансляция экрана на iOS работает только через ReplayKit. Попытки захватить UIScreen напрямую с помощью UIScreen.main.snapshot дают единичный снимок, а не видеопоток. Как указано в документации Apple, ReplayKit — единственный публичный API для захвата экрана ReplayKit. Однако он накладывает ограничения: задержка 2–5 секунд и лимит памяти 50 МБ для Broadcast Extension.
Два режима ReplayKit и когда что использовать
RPScreenRecorder (in-app recording). Захватывает только контент внутри приложения. Пользователь не видит системный picker. Подходит для записи геймплея, capture UI приложения. Недостаток — захват прекращается при сворачивании.
RPBroadcastSampleHandler (broadcast upload extension). Работает как системный Extension — процесс живёт отдельно от основного приложения. Захватывает весь экран устройства, включая другие приложения и уведомления. Пользователь запускает через Control Center или RPSystemBroadcastPickerView. Именно этот режим нужен для трансляции «всего экрана».
Архитектура Broadcast Extension:
iOS System → RPBroadcastSampleHandler (Extension process) ↓ CMSampleBuffer (video + audio) ↓ App Group shared container (если нужна коммуникация с основным приложением) ↓ RTMP/SRT → сервер трансляции Расширение не имеет UI и ограничено 50 МБ RAM. Это жёсткое ограничение: всё кодирование и отправка должны умещаться в этот бюджет.
RPBroadcastSampleHandler: реализация
class BroadcastHandler: RPBroadcastSampleHandler { private var rtmpStream: RTMPStream? override func broadcastStarted(withSetupInfo setupInfo: [String: NSObject]?) { // Инициализируем RTMP или SRT соединение // setupInfo — данные от основного приложения через Info.plist } override func processSampleBuffer(_ sampleBuffer: CMSampleBuffer, with sampleBufferType: RPSampleBufferType) { switch sampleBufferType { case .video: rtmpStream?.append(sampleBuffer) case .audioApp: rtmpStream?.append(sampleBuffer) // аудио приложений case .audioMic: // аудио микрофона — отдельный поток, требует явного разрешения break } } override func broadcastFinished() { rtmpStream?.close() } } Передача параметров (stream key, endpoint) из основного приложения в Extension — через App Group UserDefaults:
let defaults = UserDefaults(suiteName: "group.com.yourapp.broadcast") defaults?.set(streamKey, forKey: "streamKey") Почему задержка на iOS неизбежна?
ReplayKit screen broadcast добавляет буферизацию ~2–5 секунд. Это не баг — Apple буферизирует для защиты конфиденциальности (показ системных диалогов с паролями). Снизить нельзя.
Разрешение зависит от модели устройства: современные топовые модели отдают 1668×2388 (native scale), что избыточно для стрима. В processSampleBuffer перед энкодированием нужно downscale через VTPixelTransferSession или CIContext:
// Масштабируем до 1280×720 перед отправкой в энкодер let scaledBuffer = pixelTransferSession.scale(pixelBuffer, to: CGSize(width: 1280, height: 720)) Без downscale Extension превысит 50 МБ RAM на первом же I-frame в 4K.
Сравнение протоколов трансляции
| Протокол | Задержка | Надёжность | Сложность реализации |
|---|---|---|---|
| RTMP | 2-5 с | Средняя (требует ретрансляции) | Низкая |
| SRT | 0.5-2 с | Высокая (FEC, автоматическое восстановление) | Средняя |
| WebRTC | <0.5 с | Высокая (P2P, адаптивный битрейт) | Высокая |
Выбор протокола зависит от сценария: RTMP — для массовых стримов, SRT — для стабильности, WebRTC — для минимальной задержки. Мы помогаем подобрать оптимальный вариант под ваш проект.
Реализация трансляции экрана на Android
На Android аналог — MediaProjection. Пользователь подтверждает разрешение через системный диалог (startActivityForResult с MediaProjectionManager.createScreenCaptureIntent()). После получения MediaProjection создаём VirtualDisplay и направляем его в MediaCodec через Surface:
val virtualDisplay = mediaProjection.createVirtualDisplay( "ScreenCapture", width, height, dpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mediaCodec.createInputSurface(), null, null ) В отличие от iOS, задержки ReplayKit нет — захват идёт почти в реальном времени. Но на более новых версиях Android появилось требование: если MediaProjection-сессия используется в ForegroundService, нужен тип FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION. Документация MediaProjection API описывает все нюансы.
| Параметр | iOS (ReplayKit) | Android (MediaProjection) |
|---|---|---|
| Задержка | 2–5 секунд (встроенная) | Минимальная (реальное время) |
| Ограничение памяти | 50 МБ RAM на Extension | Нет жёсткого лимита, но рекомендуется управление |
| Захват других приложений | Да (Broadcast Extension) | Да (с разрешения) |
| Версии | iOS 10+ | Android 5+ (API 21) |
| Параметры запуска | Через Control Center | Через системный диалог |
Android MediaProjection обеспечивает задержку менее 100 мс, что в 20–50 раз меньше задержки ReplayKit на iOS.
Как избежать падения Broadcast Extension?
На iOS Extension может работать бесконечно, но если процесс превышает 50 МБ — система его убивает без предупреждения. Для мониторинга из основного приложения — heartbeat через App Group: Extension пишет timestamp каждые 5 секунд, приложение проверяет. Если timestamp не обновлялся 15 секунд — считаем Extension упавшим и показываем предупреждение.
Мы внедряем heartbeat-механизм: Extension каждые 5 секунд сохраняет текущее время в UserDefaults через App Group. Основное приложение проверяет это значение каждые 15 секунд. Если с момента последнего обновления прошло больше 15 секунд — значит Extension упал. Пользователь получает уведомление и может перезапустить трансляцию.
Что входит в работу
- Проектирование архитектуры с выбором протокола (RTMP, SRT, WebRTC) и сервера.
- Разработка Broadcast Extension для iOS или сервиса захвата для Android.
- Настройка App Group и коммуникации между процессами.
- Оптимизация downscale видео и настройка битрейта.
- Внедрение heartbeat-мониторинга и обработки ошибок.
- Интеграция с сервером и тестирование на реальных устройствах.
- Документация по интеграции и обучение команды.
- Поддержка при релизе в App Store и Google Play.
Сроки ориентировочно
iOS Broadcast Extension с RTMP/SRT, downscaling, App Group коммуникацией: 2–3 недели. Android MediaProjection: 1.5–2 недели. Кросс-платформа с общим управляющим кодом: 4–5 недель. Стоимость рассчитывается индивидуально. Закажите предварительную оценку — свяжитесь с нами.
Важно соблюдать App Store Review Guidelines Section 4.2 — трансляция экрана должна быть явно указана в описании. Получите консультацию по архитектуре и оптимальное решение для вашего проекта.







