API android.media.projection
, представленные в Android 5 (уровень API 21), позволяют захватывать содержимое дисплея устройства в виде медиапотока, который можно воспроизводить, записывать или транслировать на другие устройства, например телевизоры.
В Android 14 (уровень API 34) реализован общий доступ к экрану приложения, который позволяет пользователям совместно использовать одно окно приложения, а не весь экран устройства, независимо от оконного режима. Совместное использование экрана приложения исключает строку состояния, панель навигации, уведомления и другие элементы системного пользовательского интерфейса из общего дисплея, даже если общий доступ к экрану приложения используется для захвата приложения в полноэкранном режиме. Доступен только контент выбранного приложения.
Совместное использование экрана приложений обеспечивает конфиденциальность пользователей, повышает производительность пользователей и улучшает многозадачность, позволяя пользователям запускать несколько приложений, но ограничивая общий доступ к контенту только одним приложением.
Три представления дисплея
Медиа-проекция захватывает содержимое дисплея устройства или окна приложения, а затем проецирует захваченное изображение на виртуальный дисплей, который отображает изображение на Surface
.

Surface
, предоставляемую приложением. Приложение предоставляет Surface
с помощью MediaRecorder
, SurfaceTexture
или ImageReader
, который использует содержимое захваченного дисплея и позволяет управлять изображениями, отображаемыми на Surface
в режиме реального времени. Вы можете сохранить изображения в виде записи или транслировать их на телевизор или другое устройство.
Реальный дисплей
Начните сеанс медиапроецирования, получив токен, который предоставит вашему приложению возможность захватывать содержимое дисплея устройства или окна приложения. Токен представлен экземпляром класса MediaProjection
.
Используйте метод getMediaProjection()
системной службы MediaProjectionManager
, чтобы создать экземпляр MediaProjection
при запуске нового действия. Запустите действие с намерением метода createScreenCaptureIntent()
чтобы указать операцию захвата экрана:
Котлин
val mediaProjectionManager = getSystemService(MediaProjectionManager::class.java) var mediaProjection : MediaProjection
val startMediaProjection = registerForActivityResult( StartActivityForResult() ) { result -> if (result.resultCode == RESULT_OK) { mediaProjection = mediaProjectionManager .getMediaProjection(result.resultCode, result.data!!) } }
startMediaProjection.launch(mediaProjectionManager.createScreenCaptureIntent())
Ява
final MediaProjectionManager mediaProjectionManager = getSystemService(MediaProjectionManager.class); final MediaProjection[] mediaProjection = new MediaProjection[1];
ActivityResultLauncherstartMediaProjection = registerForActivityResult( new StartActivityForResult(), result -> { if (result.getResultCode() == Activity.RESULT_OK) { mediaProjection[0] = mediaProjectionManager .getMediaProjection(result.getResultCode(), result.getData()); } } );
startMediaProjection.launch(mediaProjectionManager.createScreenCaptureIntent());
Виртуальный дисплей
Центральным элементом медиапроекции является виртуальный дисплей, который вы создаете, вызывая createVirtualDisplay()
в экземпляре MediaProjection
:
Котлин
virtualDisplay = mediaProjection.createVirtualDisplay( "ScreenCapture", width, height, screenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, surface, null, null)
Ява
virtualDisplay = mediaProjection.createVirtualDisplay( "ScreenCapture", width, height, screenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, surface, null, null);
Параметры width
и height
определяют размеры виртуального дисплея. Чтобы получить значения ширины и высоты, используйте API-интерфейсы WindowMetrics
представленные в Android 11 (уровень API 30). (Подробную информацию см. в разделе «Размер медиапроекции» .)
Поверхность
Измените размер проекционной поверхности мультимедиа, чтобы обеспечить вывод в соответствующем разрешении. Сделайте поверхность большой (низкое разрешение) для трансляции экрана на телевизоры или мониторы компьютеров и маленькой (высокое разрешение) для записи с дисплея устройства.
Начиная с Android 12L (уровень API 32), при рендеринге захваченного контента на поверхности система равномерно масштабирует контент, сохраняя соотношение сторон, так что оба размера контента (ширина и высота) равны или меньше соответствующих размеров. размеры поверхности. Захваченный контент затем центрируется на поверхности.
Подход масштабирования Android 12L улучшает трансляцию экрана на телевизоры и другие большие дисплеи за счет максимального увеличения размера изображения на поверхности, обеспечивая при этом правильное соотношение сторон.
Разрешение службы переднего плана
Если ваше приложение предназначено для Android 14 или более поздней версии, манифест приложения должен включать декларацию разрешения для типа службы переднего плана mediaProjection
:
<manifest ...>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
<application ...>
<service
android:name=".MyMediaProjectionService"
android:foregroundServiceType="mediaProjection"
android:exported="false">
</service>
</application>
</manifest>
Запустите службу медиапроекции вызовом startForeground()
.
Если вы не укажете тип службы переднего плана в вызове, по умолчанию типом будет побитовое целое число типов служб переднего плана, определенных в манифесте. Если в манифесте не указаны типы служб, система выдает MissingForegroundServiceTypeException
.
Согласие пользователя
Ваше приложение должно запрашивать согласие пользователя перед каждым сеансом медиапроекции. Сеанс — это один вызов метода createVirtualDisplay()
. Токен MediaProjection
необходимо использовать только один раз для совершения вызова.
В Android 14 или более поздней версии метод createVirtualDisplay()
выдает исключение SecurityException
, если ваше приложение выполняет одно из следующих действий:
- Передает экземпляр
Intent
, возвращенный изcreateScreenCaptureIntent()
вgetMediaProjection()
более одного раза. - Вызывает
createVirtualDisplay()
более одного раза в одном и том же экземпляреMediaProjection
.
Размер медиа-проекции
Медиа-проекция может захватывать весь дисплей устройства или окно приложения независимо от оконного режима.
Начальный размер
При полноэкранной проекции мультимедиа ваше приложение должно определять размер экрана устройства. При совместном использовании экрана приложения ваше приложение не сможет определить размер захваченного дисплея, пока пользователь не выберет область захвата. Итак, первоначальный размер любой медиапроекции — это размер экрана устройства.
Используйте метод getMaximumWindowMetrics()
платформы WindowManager
, чтобы вернуть объект WindowMetrics
для экрана устройства, даже если ведущее приложение медиапроекции находится в многооконном режиме и занимает только часть дисплея.
Для совместимости до уровня API 14 используйте метод WindowMetricsCalculator
computeMaximumWindowMetrics()
из библиотеки Jetpack WindowManager
.
Вызовите метод WindowMetrics
getBounds()
чтобы получить ширину и высоту дисплея устройства.
Изменения размера
Размер проекции мультимедиа может измениться, когда устройство поворачивается или пользователь выбирает окно приложения в качестве области захвата при совместном использовании экрана приложения. Медиа-проекция может иметь почтовый ящик, если размер захваченного контента отличается от максимальных показателей окна, полученных при настройке медиа-проекции.
Чтобы гарантировать, что проекция мультимедиа точно соответствует размеру захваченного контента для любой захваченной области и для всех поворотов устройства, используйте обратный вызов onCapturedContentResize()
чтобы изменить размер захвата. (Для получения дополнительной информации см. раздел «Настройка» ниже).
Кастомизация
Ваше приложение может настроить пользовательский интерфейс медиапроекции с помощью следующих API MediaProjection.Callback
:
onCapturedContentVisibilityChanged()
: позволяет ведущему приложению (приложению, которое запустило проекцию мультимедиа) показывать или скрывать общий контент.Используйте этот обратный вызов, чтобы настроить пользовательский интерфейс вашего приложения в зависимости от того, видна ли захваченная область пользователю. Например, если ваше приложение видимо для пользователя и отображает захваченное содержимое в пользовательском интерфейсе приложения, а захваченное приложение также видно пользователю (как указано в этом обратном вызове), пользователь видит одно и то же содержимое дважды. Используйте обратный вызов, чтобы обновить пользовательский интерфейс вашего приложения, чтобы скрыть захваченный контент и освободить место макета в вашем приложении для другого контента.
onCapturedContentResize()
: позволяет ведущему приложению изменять размер проекции мультимедиа на виртуальном дисплее иSurface
проекции мультимедиа в зависимости от размера захваченной области отображения.Запускается всякий раз, когда захваченный контент — одно окно приложения или полное отображение устройства — меняет размер (из-за поворота устройства или перехода захваченного приложения в другой оконный режим). Используйте этот API, чтобы изменить размер виртуального дисплея и поверхности, чтобы соотношение сторон соответствовало захваченному содержимому, а захват не был отправлен в почтовый ящик.
Восстановление ресурсов
Ваше приложение должно зарегистрировать обратный вызов MediaProjection
onStop()
чтобы получать информацию, когда сеанс медиапроецирования остановлен и становится недействительным. Когда сеанс остановлен, ваше приложение должно освободить имеющиеся у него ресурсы, такие как виртуальный дисплей и проекционная поверхность. Остановленный сеанс медиапроекции больше не может создавать новый виртуальный дисплей, даже если ваше приложение ранее не создавало виртуальный дисплей для этой медиапроекции.
Система вызывает обратный вызов, когда медиапроекция завершается. Такое прекращение может произойти по нескольким причинам, например:
- пользователь останавливает сеанс, используя пользовательский интерфейс приложения или чип строки состояния мультимедийной проекции системы.
- экран блокируется
- начинается еще один сеанс медиапроекции
- процесс приложения убит
Если ваше приложение не регистрирует обратный вызов, любой вызов createVirtualDisplay()
выдает IllegalStateException
.
Уклоняться
Android 14 или более поздней версии по умолчанию включает совместное использование экрана приложения. Каждый сеанс медиапроекции дает пользователям возможность поделиться окном приложения или всем дисплеем.
Ваше приложение может отказаться от совместного использования экрана приложения, вызвав метод createScreenCaptureIntent(MediaProjectionConfig)
с аргументом MediaProjectionConfig
возвращаемым в результате вызова метода createConfigForDefaultDisplay()
.
Вызов createScreenCaptureIntent(MediaProjectionConfig)
с аргументом MediaProjectionConfig
возвращенным в результате вызова createConfigForUserChoice()
аналогичен поведению по умолчанию, то есть вызову createScreenCaptureIntent()
.
Приложения с изменяемым размером
Всегда делайте приложения для медиапроекции изменяемого размера ( resizeableActivity="true"
). Приложения с изменяемым размером поддерживают изменение конфигурации устройства и многооконный режим (см. Поддержка многооконного режима ).
Если размер вашего приложения не подлежит изменению, оно должно запросить границы отображения из контекста окна и использовать getMaximumWindowMetrics()
для получения WindowMetrics
максимальной области отображения, доступной приложению:
Котлин
val windowContext = context.createWindowContext(context.display!!, WindowManager.LayoutParams.TYPE_APPLICATION, null) val projectionMetrics = windowContext.getSystemService(WindowManager::class.java) .maximumWindowMetrics
Ява
Context windowContext = context.createWindowContext(context.getDisplay(), WindowManager.LayoutParams.TYPE_APPLICATION, null); WindowMetrics projectionMetrics = windowContext.getSystemService(WindowManager.class) .getMaximumWindowMetrics();
Чип строки состояния и автоматическая остановка
屏幕投影漏洞会泄露用户的私密数据(例如财务信息),因为用户不知道自己的设备屏幕正在共享。
对于搭载 Android 15 QPR1 或更高版本的设备上运行的应用,系统会在状态栏中显示一个醒目的大条状标签,以提醒用户正在进行的任何屏幕投影。用户可以点按该条状标签,停止共享、投放或录制其屏幕。此外,当设备屏幕锁定时,屏幕投影会自动停止。

Проверьте доступность чипа строки состояния медиапроекции, запустив демонстрацию экрана, трансляцию или запись. Чип должен появиться в строке состояния.
Чтобы ваше приложение высвобождало ресурсы и обновляло свой пользовательский интерфейс, когда проецирование экрана прекращается из-за взаимодействия пользователя с чипом строки состояния или активации экрана блокировки, выполните следующие действия:
Создайте экземпляр
MediaProjection.Callback
.Реализуйте метод обратного вызова
onStop()
. Метод вызывается, когда проецирование экрана прекращается. Освободите все ресурсы, которые хранит ваше приложение, и при необходимости обновите пользовательский интерфейс приложения.
Чтобы проверить обратный вызов, коснитесь чипа строки состояния или заблокируйте экран устройства, чтобы остановить проецирование экрана. Убедитесь, что метод onStop()
вызывается и ваше приложение реагирует должным образом.
Дополнительные ресурсы
Дополнительные сведения о проецировании мультимедиа см. в разделе Захват видео и воспроизведение звука .