Mit den android.media.projection
APIs, die in Android 5 (API-Level 21) eingeführt wurden, können Sie den Inhalt eines Gerätedisplays als Medienstream erfassen, der auf anderen Geräten wie Fernsehern wiedergegeben, aufgezeichnet oder gestreamt werden kann.
Mit Android 14 (API-Level 34) wird die Bildschirmfreigabe für Apps eingeführt. Nutzer können dann unabhängig vom Fenstermodus ein einzelnes App-Fenster anstelle des gesamten Gerätebildschirms freigeben. Bei der App-Bildschirmfreigabe werden die Statusleiste, die Navigationsleiste, Benachrichtigungen und andere System-UI-Elemente vom freigegebenen Display ausgeschlossen – auch wenn die App-Bildschirmfreigabe verwendet wird, um eine App im Vollbildmodus aufzuzeichnen. Es werden nur die Inhalte der ausgewählten App freigegeben.
Die Bildschirmfreigabe von Apps schützt die Privatsphäre der Nutzer, steigert ihre Produktivität und verbessert das Multitasking, da Nutzer mehrere Apps ausführen, die Freigabe von Inhalten jedoch auf eine einzelne App beschränken können.
Drei Displaydarstellungen
Bei einer Medienprojektion wird der Inhalt eines Gerätedisplays oder App-Fensters erfasst und dann auf ein virtuelles Display projiziert, das das Bild auf einem Surface
darstellt.
Die Anwendung stellt den Surface
über einen MediaRecorder
, SurfaceTexture
oder ImageReader
bereit, der den Inhalt des erfassten Displays nutzt und es Ihnen ermöglicht, Bilder, die auf dem Surface
gerendert werden, in Echtzeit zu verwalten. Sie können die Bilder als Aufnahme speichern oder auf einen Fernseher oder ein anderes Gerät streamen.
Echte Anzeige
Um eine Sitzung zur Projektion von Medien zu starten, müssen Sie ein Token abrufen, das Ihrer App die Möglichkeit gibt, den Inhalt des Displays oder App-Fensters des Geräts zu erfassen. Das Token wird durch eine Instanz der Klasse MediaProjection
dargestellt.
Verwenden Sie die Methode getMediaProjection()
des Systemdienstes MediaProjectionManager
, um eine MediaProjection
-Instanz zu erstellen, wenn Sie eine neue Aktivität starten. Starten Sie die Aktivität mit einem Intent aus der Methode createScreenCaptureIntent()
, um einen Vorgang zum Aufnehmen von Screenshots anzugeben:
Kotlin
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())
Java
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());
Virtuelles Display
Das Herzstück einer Medienprojektion ist das virtuelle Display, das Sie erstellen, indem Sie createVirtualDisplay()
auf einer MediaProjection
-Instanz aufrufen:
Kotlin
virtualDisplay = mediaProjection.createVirtualDisplay( "ScreenCapture", width, height, screenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, surface, null, null)
Java
virtualDisplay = mediaProjection.createVirtualDisplay( "ScreenCapture", width, height, screenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, surface, null, null);
Die Parameter width
und height
geben die Abmessungen des virtuellen Displays an. Verwenden Sie die WindowMetrics
APIs, die in Android 11 (API-Level 30) eingeführt wurden, um Werte für Breite und Höhe zu erhalten. Weitere Informationen finden Sie im Abschnitt Größe der Medienprojektion.
Surface
Größe der Projektionsfläche für Medien festlegen, um eine Ausgabe in der richtigen Auflösung zu erzielen Wählen Sie eine große Oberfläche (niedrige Auflösung) für das Streamen von Inhalten auf Fernseher oder Computermonitore und eine kleine Oberfläche (hohe Auflösung) für die Aufzeichnung des Displays des Geräts.
Ab Android 12L (API-Level 32) skaliert das System beim Rendern aufgenommener Inhalte auf der Oberfläche die Inhalte einheitlich und beibehält dabei das Seitenverhältnis, sodass beide Abmessungen der Inhalte (Breite und Höhe) gleich oder kleiner als die entsprechenden Abmessungen der Oberfläche sind. Die erfassten Inhalte werden dann auf der Oberfläche zentriert.
Die Skalierungsmethode von Android 12L verbessert das Streamen von Inhalten auf Fernseher und andere große Displays, indem die Größe des Oberflächenbilds maximiert und gleichzeitig das richtige Seitenverhältnis beibehalten wird.
Berechtigung für Dienste im Vordergrund
Wenn Ihre App auf Android 14 oder höher ausgerichtet ist, muss das App-Manifest eine Berechtigungsdeklaration für den Typ mediaProjection
von Diensten im Vordergrund enthalten:
<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>
Starten Sie den Medienprojektionsservice mit einem Aufruf von startForeground()
.
Wenn Sie den Typ des Dienstes im Vordergrund nicht im Aufruf angeben, wird standardmäßig eine binäre Ganzzahl der im Manifest definierten Typen von Diensten im Vordergrund verwendet. Wenn im Manifest keine Diensttypen angegeben sind, wirft das System MissingForegroundServiceTypeException
aus.
Nutzereinwilligung
Ihre App muss vor jeder Medienprojektionssitzung die Einwilligung des Nutzers einholen. Eine Sitzung ist ein einzelner Aufruf von createVirtualDisplay()
. Ein MediaProjection
-Token muss nur einmal verwendet werden, um den Anruf zu starten.
Unter Android 14 oder höher wird von der createVirtualDisplay()
-Methode eine SecurityException
geworfen, wenn Ihre App eine der folgenden Aktionen ausführt:
- Eine
Intent
-Instanz, die voncreateScreenCaptureIntent()
angetMediaProjection()
zurückgegeben wird, wird mehrmals übergeben createVirtualDisplay()
wird mehrmals auf dieselbeMediaProjection
-Instanz aufgerufen
Größe der Medienprojektion
Eine Medienprojektion kann unabhängig vom Fenstermodus das gesamte Display des Geräts oder ein App-Fenster erfassen.
Anfangsgröße
Bei der Medienprojektion im Vollbildmodus muss Ihre App die Größe des Gerätebildschirms ermitteln. Bei der Bildschirmfreigabe in Apps kann Ihre App die Größe des aufgenommenen Displays erst dann bestimmen, wenn der Nutzer den Aufnahmebereich ausgewählt hat. Die anfängliche Größe einer Medienprojektion entspricht also der Größe des Displays des Geräts.
Verwende die Plattformmethode WindowManager
getMaximumWindowMetrics()
, um ein WindowMetrics
-Objekt für den Gerätebildschirm zurückzugeben, auch wenn die Host-App der Medienprojektion sich im Multifenstermodus befindet und nur einen Teil des Displays belegt.
Für die Kompatibilität bis API-Level 14 verwenden Sie die Methode WindowMetricsCalculator
computeMaximumWindowMetrics()
aus der Jetpack-Bibliothek WindowManager
.
Rufen Sie die Methode WindowMetrics
getBounds()
auf, um die Breite und Höhe des Gerätedisplays abzurufen.
Größenänderungen
Die Größe der Medienprojektion kann sich ändern, wenn das Gerät gedreht wird oder der Nutzer ein App-Fenster als Aufnahmebereich für die Bildschirmfreigabe der App auswählt. Die Medienprojektion wird möglicherweise als Letterbox angezeigt, wenn die erfassten Inhalte eine andere Größe als die maximalen Fenstermesswerte haben, die bei der Einrichtung der Medienprojektion ermittelt wurden.
Damit die Medienprojektion für jede erfasste Region und bei jeder Gerätedrehung genau mit der Größe der erfassten Inhalte übereinstimmt, verwenden Sie den onCapturedContentResize()
-Callback, um die Größe der Aufnahme zu ändern. Weitere Informationen finden Sie im folgenden Abschnitt Anpassen.
Personalisierung
Mit den folgenden MediaProjection.Callback
APIs können Sie die Nutzererfahrung bei der Medienprojektion anpassen:
onCapturedContentVisibilityChanged()
: Ermöglicht es der Host-App (der App, die die Medienprojektion gestartet hat), die freigegebenen Inhalte ein- oder auszublenden.Mit diesem Callback können Sie die Benutzeroberfläche Ihrer App anpassen, je nachdem, ob der erfasste Bereich für den Nutzer sichtbar ist. Wenn Ihre App beispielsweise für den Nutzer sichtbar ist und die erfassten Inhalte in der Benutzeroberfläche der App angezeigt werden und die erfasste App ebenfalls für den Nutzer sichtbar ist (wie durch diesen Rückruf angegeben), sieht der Nutzer dieselben Inhalte zweimal. Verwenden Sie den Rückruf, um die Benutzeroberfläche Ihrer App zu aktualisieren, um die erfassten Inhalte auszublenden und Layoutplatz in Ihrer App für andere Inhalte freizugeben.
onCapturedContentResize()
: Ermöglicht es der Host-App, die Größe der Medienprojektion auf dem virtuellen Display und der MedienprojektionSurface
basierend auf der Größe des erfassten Displaybereichs zu ändern.Wird ausgelöst, wenn sich die Größe der erfassten Inhalte – ein einzelnes App-Fenster oder das gesamte Display des Geräts – ändert (z. B. durch die Drehung des Geräts oder wenn die erfasste App in einen anderen Fenstermodus wechselt). Mit dieser API können Sie sowohl das virtuelle Display als auch die Oberfläche so anpassen, dass das Seitenverhältnis zu den aufgenommenen Inhalten passt und die Aufnahme nicht letterboxed ist.
Ressourcenwiederherstellung
Ihre App sollte den Rückruf MediaProjection
onStop()
registrieren, um benachrichtigt zu werden, wenn die Medienprojektionssitzung beendet und ungültig wird. Wenn die Sitzung beendet wird, sollte Ihre App die von ihr gehaltenen Ressourcen freigeben, z. B. das virtuelle Display und die Projektionsfläche. Bei einer angehaltenen Medienprojektionssitzung kann kein neues virtuelles Display mehr erstellt werden, auch wenn Ihre App zuvor kein virtuelles Display für diese Medienprojektion erstellt hat.
Das System ruft den Callback auf, wenn die Medienprojektion beendet wird. Das kann verschiedene Gründe haben, z. B.:
- der Nutzer die Sitzung über die Benutzeroberfläche der App oder über den Status-Chip für die Medienprojektion des Systems beendet
- das Display gesperrt wird.
- eine weitere Sitzung zur Medienprojektion gestartet wird
- der App-Prozess beendet wird
Wenn Ihre App den Rückruf nicht registriert, wird bei jedem Aufruf von createVirtualDisplay()
IllegalStateException
geworfen.
Widerrufen
Unter Android 14 oder höher ist die App-Bildschirmfreigabe standardmäßig aktiviert. Bei jeder Medienprojektionssitzung haben Nutzer die Möglichkeit, ein App-Fenster oder das gesamte Display zu teilen.
Sie können die Bildschirmfreigabe für Ihre App deaktivieren, indem Sie die Methode createScreenCaptureIntent(MediaProjectionConfig)
mit dem Argument MediaProjectionConfig
aufrufen, das von einem Aufruf von createConfigForDefaultDisplay()
zurückgegeben wird.
Ein Aufruf von createScreenCaptureIntent(MediaProjectionConfig)
mit einem MediaProjectionConfig
-Argument, das von einem Aufruf von createConfigForUserChoice()
zurückgegeben wird, entspricht dem Standardverhalten, d. h. einem Aufruf von createScreenCaptureIntent()
.
Größe kann geändert werden
Ihre Apps für die Medienprojektion müssen immer skalierbar sein (resizeableActivity="true"
). Skalierbare Apps unterstützen Änderungen der Gerätekonfiguration und den Mehrfenstermodus (siehe Unterstützung für den Mehrfenstermodus).
Wenn Ihre App nicht skalierbar ist, muss sie die Displaygrenzen aus einem Fensterkontext abfragen und mit getMaximumWindowMetrics()
die WindowMetrics
des maximalen Displaybereichs abrufen, der für die App verfügbar ist :
Kotlin
val windowContext = context.createWindowContext(context.display!!, WindowManager.LayoutParams.TYPE_APPLICATION, null) val projectionMetrics = windowContext.getSystemService(WindowManager::class.java) .maximumWindowMetrics
Java
Context windowContext = context.createWindowContext(context.getDisplay(), WindowManager.LayoutParams.TYPE_APPLICATION, null); WindowMetrics projectionMetrics = windowContext.getSystemService(WindowManager.class) .getMaximumWindowMetrics();
Statusleisten-Chip und automatisches Beenden
Bei Ausnutzung von Bildschirmprojektion werden personenbezogene Nutzerdaten wie Finanzinformationen offengelegt, da Nutzer nicht wissen, dass ihr Gerätedisplay geteilt wird.
Unter Android 15 (API-Level 35) und höher wird ein großer und gut sichtbarer Status-Bar-Chip angezeigt, um Nutzer auf eine laufende Bildschirmprojektion hinzuweisen. Nutzer können auf den Chip tippen, um zu verhindern, dass ihr Bildschirm geteilt, gestreamt oder aufgezeichnet wird. Außerdem wird die Bildschirmprojektion automatisch beendet, wenn das Display des Geräts gesperrt wird.
Testen Sie die Verfügbarkeit des Chips in der Statusleiste für die Medienprojektion, indem Sie die Bildschirmfreigabe, das Streamen oder die Aufzeichnung starten. Der Chip sollte in der Statusleiste angezeigt werden.
Damit Ihre App Ressourcen freigibt und die Benutzeroberfläche aktualisiert, wenn die Bildschirmprojektion durch die Interaktion des Nutzers mit dem Chip in der Statusleiste oder durch die Aktivierung des Sperrbildschirms beendet wird, gehen Sie so vor:
Erstellen Sie eine Instanz von
MediaProjection.Callback
.Implementieren Sie die Callback-Methode
onStop()
. Die Methode wird aufgerufen, wenn die Bildschirmprojektion beendet wird. Geben Sie alle Ressourcen frei, die von Ihrer App gehalten werden, und aktualisieren Sie die App-Benutzeroberfläche nach Bedarf.
Wenn Sie den Rückruf testen möchten, tippen Sie auf den Chip in der Statusleiste oder sperren Sie das Display, um die Bildschirmprojektion zu beenden. Prüfen Sie, ob die onStop()
-Methode aufgerufen wird und Ihre App wie vorgesehen reagiert.
Weitere Informationen
Weitere Informationen zur Medienprojektion finden Sie unter Video- und Audiowiedergabe erfassen.