Screen sharing на мобильных платформах — принципиально другая задача, чем на десктопе. iOS и Android не дают приложению прямой доступ к буферу экрана. Мы используем специальные системные механизмы, каждый со своими ограничениями и особенностями. Без правильной архитектуры проект рискует столкнуться с падениями из-за нехватки памяти, отклонениями в App Store Review или неработающим захватом на новых версиях ОС. За 50+ реализованных проектов мы накопили опыт, который гарантирует стабильную работу screen sharing в production.
Как работает ReplayKit на iOS?
На iOS захват экрана возможен только через ReplayKit. Нельзя получить контент экрана напрямую из основного процесса приложения — это ограничение sandbox. Для трансляции в реальном времени используем RPSystemBroadcastPickerView, который показывает системный picker для запуска broadcast. Трансляция идёт через Broadcast Upload Extension — отдельный таргет в проекте, который запускается в собственном процессе (com.apple.broadcast-services-upload). Extension и основное приложение не имеют общей памяти — обмен данными только через App Group (shared UserDefaults, shared FileManager, или Darwin notify для сигналов).
Структура extension:
class SampleHandler: RPBroadcastSampleHandler { override func processSampleBuffer(_ sampleBuffer: CMSampleBuffer, with sampleBufferType: RPSampleBufferType) { switch sampleBufferType { case .video: // Передаём CMSampleBuffer в WebRTC/Agora/Livekit videoSource?.capturer(capturer, didCapture: toRTCVideoFrame(sampleBuffer)) case .audioApp: // Системное аудио case .audioMic: // Микрофон (доступен только при явном разрешении в Info.plist) } } } Extension имеет лимит памяти 50 МБ — в 90% случаев падение вызвано превышением этого лимита. Agora и Livekit предоставляют облегчённые версии SDK специально для Broadcast Extension. Коммуникация extension → основное приложение через CFNotificationCenter (Darwin notifications). Разрешение и FPS ограничены ReplayKit: максимум 1080p, до 60 FPS. На практике для screen sharing достаточно 720p/15fps — экраны мобильных устройств небольшие, а битрейт снижается на 40% без потери читаемости текста.
Apple Developer Documentation: ReplayKit
Что такое MediaProjection API на Android?
На Android захват экрана — через MediaProjection API. Пользователь должен явно разрешить запись:
val mediaProjectionManager = getSystemService(MEDIA_PROJECTION_SERVICE) as MediaProjectionManager startActivityForResult( mediaProjectionManager.createScreenCaptureIntent(), REQUEST_MEDIA_PROJECTION ) В onActivityResult получаем Intent с разрешением — из него создаём MediaProjection. VirtualDisplay с MediaProjection.createVirtualDisplay() даёт Surface, на который система рисует содержимое экрана.
Для передачи через WebRTC используем ScreenCapturerAndroid (из org.webrtc): он оборачивает MediaProjection и поставляет кадры в VideoSource. С Android 10+ при запуске screen capture через ForegroundService нужен android:foregroundServiceType="mediaProjection" в манифесте. С Android 14 — дополнительно явный ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION при старте сервиса через startForeground(). Без этого — SecurityException. При разрыве соединения MediaProjection.Callback.onStop() вызывается — нужно обработать и уведомить пользователя.
Android Developers: MediaProjection
Как передаются кадры в реальном времени?
И на iOS, и на Android кадры захвата экрана — это CMSampleBuffer (iOS) или Bitmap/Image через ImageReader (Android). Для передачи по сети через WebRTC конвертируем в RTCVideoFrame с YUV420PlanarBuffer (iOS) или JavaI420Buffer (Android). Конвертация YUV из BGRA — дорогая операция, делаем в нативном коде (C++) или через аппаратный конвертер. Для Agora — AgoraRtcKit.startScreenCapture() принимает конфигурацию с contentHint: .text для оптимизации кодека под текстовый контент (меньше motion, высокая резкость). WebRTC гибче Agora в настройке битрейта, но Agora проще интегрировать с Broadcast Extension.
Сравнение iOS и Android
| Параметр | iOS (ReplayKit) | Android (MediaProjection) |
|---|---|---|
| Минимальная версия | iOS 12+ | Android 5.0 (API 21) |
| Захват экрана | Broadcast Extension (отдельный процесс) | Прямой доступ через Intent |
| Лимит памяти | 50 МБ на extension | Нет жёсткого лимита |
| Макс. разрешение | 1080p | Зависит от устройства, часто 1080p+ |
| FPS | до 60 | до 30 (обычно) |
| Аудиозахват | Системный + микрофон | Микрофон через AudioRecord |
| Foreground service | Не требуется | Обязателен (Android 10+) |
Типичные проблемы screen sharing
| Проблема | Решение |
|---|---|
| Падение Broadcast Extension на iOS | Использовать облегчённые SDK (Agora/Livekit) и следить за лимитом 50 МБ |
| SecurityException на Android 14 | Явно указать foregroundServiceType="mediaProjection" и вызвать startForeground() с правильным типом |
| Пользователь отменил захват через шторку уведомлений Android | Обработать onStop() и корректно переключить UI без ошибок |
| Задержка при конвертации YUV | Использовать аппаратный конвертер или нативный код C++ |
Технические детали Broadcast Extension
Broadcast Extension живёт в отдельном процессе с лимитом 50 МБ. Если SDK весит больше — extension упадёт без внятного сообщения. Agora и Livekit предоставляют "lite"-версии для extension. Для обмена данными между extension и основным приложением используем Darwin notifications через CFNotificationCenter. Extension не может устанавливать сетевые соединения напрямую — он только передаёт кадры, а основное приложение управляет WebRTC-пирингом.
Что входит в реализацию screen sharing?
- Архитектура и проектирование: выбор стека (WebRTC/Agora/Livekit), схема обмена кадрами, обработка lifecycle.
- Разработка Broadcast Extension (iOS) и MediaProjection Service (Android): полный цикл захвата и трансляции.
- Интеграция с сигналингом и WebRTC: настройка peer connection, ICE, ретрансляция.
- Управление разрешениями: запросы на запись экрана, ATT, foreground service.
- Обработка ошибок и edge cases: падение extension, пользователь отменил захват, потеря сети.
- Документация и обучение: описание интеграции, передача исходного кода с комментариями.
- Тестирование: на реальных устройствах с разными версиями ОС.
Как выбрать стек для screen sharing?
Выбор между WebRTC, Agora и Livekit зависит от требований к кастомизации и времени выхода на рынок. WebRTC даёт полный контроль над битрейтом и кодеком, но требует больше времени на интеграцию — в среднем 1.5 недели на обе платформы. Agora и Livekit сокращают этот срок до 5 дней за счёт готовых модулей, но ограничивают гибкость настройки. Для проектов с высокой нагрузкой (1000+ одновременных трансляций) WebRTC оказывается на 30% дешевле по затратам на инфраструктуру.
Сроки ориентировочно
iOS (ReplayKit + Broadcast Extension + WebRTC) — от 3 до 5 дней при готовом сигналинге. Android (MediaProjection + WebRTC) — от 2 до 3 дней. Обе платформы с корректным lifecycle, фоновым режимом и UX уведомления — от 1 до 1.5 недели. Стоимость рассчитывается индивидуально в зависимости от сложности и требуемого стека.
Получите консультацию по вашему проекту — наши инженеры с сертификатами Apple и Google помогут оценить объём работ и избежать типичных ошибок. Свяжитесь с нами для детального обсуждения.







