Sie können ein Fenster auf macOS 15 nicht verstecken.
Auf modernen macOS-Systemen lässt sich ein Fenster nicht zuverlässig vor Bildschirmaufnahmen verstecken — nicht von einer anderen Anwendung und auch nicht von Ihrer eigenen. Dies ist die technische Geschichte davon, dass die Methode CGSSetWindowCaptureExcluded entfernt wurde, dass SLSSetWindowSharingState bei mehrprozessverwendung stumm ignoriert wird, und warum NSWindow.sharingType = .none eine schwache Empfehlung für Zoom und QuickTime darstellt, nicht jedoch eine starke Garantie.
Eine kurze technische Nachbesprechung zum Erstellen einer „privaten Fenster“-App, die leider nicht ganz funktioniert.
Die Idee
Wie viele Menschen arbeite ich mit einem offenen Claude-Desktop-Fenster während Meetings. Und wie viele Menschen teilen ich manchmal meinen Bildschirm auf Zoom und würde gerne, dass dieses Fenster nicht allen Anwesenden sichtbar ist. Nicht wegen sensibler Inhalte – einfach, weil es ein privates Arbeitszustandsfenster ist.
Ich wusste, dass Apps wie 1Password und Hand Mirror ihre eigenen Fenster von Bildschirmaufnahmen verstecken können. Ich dachte, ich könnte eine kleine Menüleiste-Utility bauen, die es mir ermöglicht, ein beliebiges App – Claude, Notizen, egal – auszuwählen und deren Fenster während der Aufnahme unsichtbar zu machen, während sie vollständig sichtbar und interaktiv auf meinem eigenen Bildschirm bleiben. jedes App — Claude, Notizen, egal — und deren Fenster während der Aufnahme unsichtbar zu machen, während sie vollständig sichtbar und interaktiv auf meinem eigenen Bildschirm bleiben.
Ein Wochenende-Projekt. Maximal zwei Stunden.
Es hat länger gedauert. Und die Kernbotschaft ist: Auf modernen macOS-Systemen kann man das nicht tun. Nicht für eine andere App, und – wie sich herausstellt – nicht zuverlässig selbst für eigene Apps.
Dies ist die technische Geschichte dafür.
Versuch 1: ein anderes App-Fenster verstecken
Der klassische Weg, um ein macOS-Fenster von Bildschirmaufnahmen unsichtbar zu machen, ist NSWindow.sharingType = .none. Aber dies ist ein pro-Fenster-Flag, das nur vom eigenen Prozess auf seine eigenen Fenster setzen kann. AppKit erlaubt es nicht, in die Fensterliste einer anderen App vorzudringen.
Der bekannte Workaround, der seit Jahren von Tools wie Hand Mirror und verschiedenen Bildschirm-Blank-Tools verwendet wird, ist die private SkyLight-Funktion:
OSStatus CGSSetWindowCaptureExcluded(CGSConnectionID cid, CGWindowID wid, bool excluded);
Sie durchgehen Fenster über CGWindowListCopyWindowInfo, filtern auf den Ziel-App-PID und rufen diese auf jeder Fenster-ID auf. Da der Aufruf über den WindowServer (nicht über den Eigentümerprozess) erfolgt, kann jedes Fenster von der Aufnahme ausgenommen werden.
Ich habe dies über dlsym auf /System/Library/PrivateFrameworks/SkyLight.framework/...aufgebaut, gebaut, auf macOS 15.3.1 ausgeführt und bekam:
[InvisibleApp] symbol not found: CGSSetWindowCaptureExcluded
[InvisibleApp] symbol not found: SLSSetWindowCaptureExcluded
Die Funktion ist verschwunden. Apple hat sie entfernt. Ich habe nach einer umbenannten Version (SLSSetWindowExcludedFromCapture, CGSSetWindowSharingState, alle offensichtlichen Varianten) gesucht. Die meisten existieren nicht, aber ich habe zwei gefunden:
SLSSetWindowSharingState(CGSConnectionID, CGWindowID, int sharingState)— die unterliegende Aufruf, dieNSWindow.sharingType = .noneintern verwendet. Teilen von Zustand0IstNSWindowSharingNone.SLSGetWindowOwner— gibt Ihnen die Verbindung-ID des Fenster-Eigentümers.
Daher habe ich die Brücke neu aufgebaut, um SLSSetWindowSharingState auf das Ziel-Fenster aufzurufen, versuchte sowohl meine eigene Verbindung als auch die Verbindung des Fenster-Eigentümers.
Bauen, ausführen, schalten ein, Protokoll sagt, dass es zurückgegeben wurde noErr, nehmen ein Screenshot – Claude ist immer noch im Screenshot. Versuchen Zoom – Claude ist immer noch im Geteilten.
SLSSetWindowSharingState erfolgt bei Aufruf über Prozessgrenze, aber der WindowServer ignoriert es schweigend. Nur der Eigentümerprozess kann den eigenen Fenster-Zustand auf macOS 15 ändern.
Ich habe auch die offensichtliche Ausnahmeverschließung bestätigt: DYLD_INSERT_LIBRARIES injection in den Claude-Prozess ist blockiert, weil Claude (wie die meisten modernen Apps) einen hardened Runtime hat und ohne die disable-library-validation Berechtigung.
Das ist also abgeschlossen: Keine dritte Partei kann ein Fenster einer anderen App von Aufnahmen verstecken auf macOS 15. Die Schlussfolgerung stimmt mit dem, was Apple sagt, sie wollen: Der Fenster-Ebene-Aufnahmestatus ist das Eigentum des App-Eigentümers, fertig.
Versuch 2: unser eigenes Fenster verstecken
Plan B: verändern Sie das Produkt. Statt eine App zu bauen, die Claude versteckt, erstellen Sie ein kleines Chat-Fenster für sich selbst – dieselbe Aufgabe, andere Form. Meins, mein sharingType = .none. Dies ist das wohlbekannte Mechanismus, den jede Aufnahmeverstellung nutzt, und es ist eine einzeilige Anweisung:
window.sharingType = .none
Verbinden Sie einen Streaming-Chat mit der Anthropic Messages-API (oder mit der lokalen claude CLI für Abonnement-Authentifizierung), setzen Sie sharingType = .none auf das Chat-Fenster und verteilen Sie es. Dies ist eindeutig, unterstützt, öffentliches API.
Es wurde gebaut. Ich habe den tatsächlichen Sharing-Typ-Wert im Laufzeitprotokoll aufgezeichnet, um sicherzustellen, dass macOS ihn akzeptierte:
[InvisibleApp] window 151526 sharingType=0
Ein Screenshot – das Chat-Fenster war korrekt nicht sichtbar. ✅
Ein Bild mit QuickTime aufgenommen – das Chat-Fenster erschien im Aufnahme. ❌
Ein Bildteilen auf Zoom – das Chat-Fenster war für die andere Seite sichtbar. ❌
Das war unerwartet. Das ganze Punkt von NSWindowSharingNone ist es, es aus diesen Flüssen herauszubekommen. Daher habe ich eine Selbst-Test-Funktion innerhalb der App gebaut, die einen Bildschirmaufnahme mit ScreenCaptureKit (der moderne, öffentliche Aufnahmeeinbindung) durchführt, die das gleiche Framework wie QuickTime verwendet. Ich habe sowohl eine einzelne Aufnahme (SCScreenshotManager.captureImage) als auch eine kontinuierliche Aufnahme (SCStream) getestet – beide produzierten ein PNG mit dem Chat-Fenster korrekt ausgeschlossen.
Daher:
| Aufnahmeverfahren | Versteckt unser Fenster? |
|---|---|
| Cmd-Shift-3/4/5 (System-Screenshot) | ✅ |
| Unser App-SCK-Einzel-Aufnahme | ✅ |
| Unser App-SCK-Continent-SCStream | ✅ |
| QuickTime „Neue Bildschirmaufnahme“ | ❌ |
| Zoom „Bildschirm teilen → Desktop“ | ❌ |
Gleiche OS, gleiche Maschine, gleiche Fenster, gleiche sharingType = .none. Die einzige Sache, die variiert, ist, wer die Aufnahme durchführt.
Berechtigte Aufnahmepfade
Dies ist der Teil, den die meisten Ingenieure nicht erkennen: Auf macOS 15 ist Bildschirmaufnahme nicht ein einziges API; es gibt mindestens zwei – ein öffentliches und ein privates mit zusätzlichen Berechtigungen.
Ich habe die Berechtigungen von QuickTime Player ausgedruckt:
codesign -d --entitlements - /System/Applications/QuickTime\ Player.app
com.apple.private.screencapturekit.noprompt = true
com.apple.private.tcc.allow = [
kTCCServiceMicrophone,
kTCCServiceCamera,
kTCCServiceScreenCapture,
]
Diese com.apple.private.* Schlüssel können nur von Apple an seine eigenen ersten Parteien vergeben werden. Sie und ich können sie nicht anfordern. Die Notarisation würde sie ablehnen. Der App Store würde es sicherlich tun.
Und was sie vergeben, zusätzlich zum Überspringen der Aufnahmeprompt, ist die Möglichkeit, ein Bildschirmbild vor der Anwendung der Sharing-Typ-Filterung durch den WindowServerzu erfassen. Das Fenster ist im Framebuffer, der herauskommt – Apple’s Tools sehen alles.
Zoom verwendet einen ähnlichen privilegierten Pfad. Es könnte eine Kernelerweiterung, eine Systemerweiterung oder ein privates API sein, das durch langjährige Genehmigung für ein Konferenz-App erhalten wurde – ich habe nicht tief genug untersucht, um zu sagen, welches. Aber das Verhalten ist das gleiche: Die standardmäßige öffentliche Exklusion-Mechanismus gilt nicht für es.
Was dies bedeutet
Wenn Sie ein Drittanbieter-Entwickler sind und Ihr Ziel ist „dieses Fenster muss in keiner Aufnahme auf jedem Mac erscheinen“, können Sie auf macOS 15 nicht garantieren. Ihr Fenster ist aus allen Aufnahmepfaden, die Sie selbst schreiben können, ausgeblendet. Es ist aus Google Meet (Browser → getDisplayMedia → SCK), Microsoft Teams (SCK), OBS (SCK), allen konformen Drittanbieter-Aufnahmetools ausgeblendet. Aber Apple’s eigene QuickTime und Apple’s genehmigte Konferenzpartner können es immer noch sehen.
Die Funktion „Bildschirmaufnahmenschutz“ von 1Password / Hand Mirror hat die gleiche Beschränkung. Die Leute screenen ihre 1Password-Vault nicht mit QuickTime, daher bleibt das Leck unbemerkt.
Die ehrliche Zusammenfassung, die ich Apple geben würde: Veröffentlichen Sie ein öffentliches Berechtigungsgleiches zu com.apple.private.screencapturekit.noprompt, oder verpflichten Sie sich, dass NSWindow.sharingType = .none eine starke Garantie gegen alle Aufnahmepfade ist. Bis macOS 15.3.1 ist es weder – es ist eine starke Garantie gegen meisten Pfade und eine schwache Empfehlung, dass privilegierte Werkzeuge es umgehen können. Der Status Quo schafft eine Sicherheitslage, in der Benutzer glauben, dass ein Fenster während der Aufnahme unsichtbar ist, was schlimmer ist als keine Schutzmaßnahme überhaupt.
Die Workarounds, sortiert nach dem Grad, wie sie schaden
Für meinen Anwendungsfall – ein Chat-Fenster während einer Zoom-Teilung zu verstecken – funktionieren alle und sind keine guten Lösungen:
- Teilen Sie ein einzelnes Fenster in Zoom, nicht den Desktop. Das Share Screen-Dialogfeld hat eine „Fenster“-Registerkarte. Zoom erfassen nur die Pixel des Fensters und nichts anderes, sodass mein Chat – und alles andere auf dem Bildschirm – automatisch fehlt. Dies ist die zuverlässigste Lösung und erfordert keine Code-Änderung. Nachteil: Die Zuschauer sehen keine Bildschirmkontext.
- Verwenden Sie Meet oder Teams anstatt Zoom. Beide respektieren
sharingType = .none. Dies ist gut, wenn Sie das Meeting-Tool kontrollieren, schlecht, wenn Sie es nicht tun. - Platzieren Sie das Chat-Fenster auf einem separaten Space. Mission Control bietet Ihnen mehrere Desktops. Teilen Sie Space 1, halten Sie das Chat-Fenster auf Space 2. Swipe, um zu interagieren. Langsam, bricht den Fluss, aber es funktioniert.
- Verwenden Sie ein zweites Gerät. Ein Smartphone oder ein iPad neben Ihrem Laptop ist undefeitbar durch jedes Aufnahmewerkzeug, definitionsgemäß.
Ich habe mich für Option 1 plus die bereits gebaute Chat-App entschieden. Das Chat-Fenster ist unsichtbar für etwa 95% von Aufnahmepfaden, und im Fall der Zoom-Desktop-Teilung verwende ich einfach keine Zoom-Desktop-Teilung.
Was ich nächstes wollen würde
- Ein öffentliches Berechtigung die es einem nichtarisierten App erlaubt, „mein Fenster ist von alle Aufnahmen ausgeschlossen, auch von privilegierten Aufrufern“ zu erklären. Heute ist das nicht möglich.
- Ehrlichkeit in
NSWindow.sharingTypeDokumentation. Die Dokumentation macht es so aus, als wäre es eine starke Garantie. Es ist nicht – zumindest sollten die Dokumentationen erwähnen, dass privilegierte Apple-Werkzeuge und Apps mit privaten Berechtigungen unabhängig von der Aufnahme sind. Heute werden sie nicht erwähnt. - Eine Möglichkeit, zu überprüfen welche Apps auf einem System privilegierte Aufnahmefunktionen haben – analog zu „Dateien und Ordner“ in Privacy & Security. Heute gibt es keine Oberfläche, auf die Benutzer sehen können, wer ihre Privatsphäre umgehen kann.
Bis eines davon eingeführt ist, ist die praktische Empfehlung: Annahme, dass jedes Fenster auf Ihrem Bildschirm von der OS und von den wichtigsten Konferenz-Apps aufgenommen werden kann, unabhängig von dem, was sharingType Sie setzen. Die Exklusions-APIs sind echt – sie funktionieren gegen die meisten Welt – aber sie sind keine Sicherheitsgrenze, die Sie gegen die Teile der Welt vertrauen können, die am meisten zählen.
Code
Die vollständige Quelle für die Menüleiste-Chat-App – einschließlich der SkyLight-Brücke, des streambasierten SCK-Selbsttests und der experimentellen Bestätigung – ist hier verfügbar (dieses Verzeichnis). Es sind etwa 700 Zeilen Swift, ein einzelner Binär-Code, keine Abhängigkeiten. Nützlich als Referenz für alle, die nach NSWindow.sharingType = .none und fragen, was sie tatsächlich erhalten.
Die TL;DR für diese Zielgruppe:
NSWindow.sharingType = .noneist das richtige API. Es ist nur nicht so stark, wie Sie denken. Testen Sie es gegen das spezifische Werkzeug, das Ihre Benutzer übermitteln, nicht gegen Screenshot und Ihren eigenen SCK-Code, bevor Sie etwas versprechen.
Das könnte Ihnen auch gefallen
Erweiterungen installieren
IO-Tools zu Ihrem Lieblingsbrowser hinzufügen für sofortigen Zugriff und schnellere Suche
恵 Die Anzeigetafel ist eingetroffen!
Anzeigetafel ist eine unterhaltsame Möglichkeit, Ihre Spiele zu verfolgen. Alle Daten werden in Ihrem Browser gespeichert. Weitere Funktionen folgen in Kürze!
Unverzichtbare Tools
Alle Neuheiten
AlleAktualisieren: Unser neuestes Werkzeug hinzugefügt am 26. Apr. 2026
