Die Einrichtung beim ersten Start erklärt jede der vier Sachen einzeln und fragt jede einzeln an. Vier Systemdialoge hintereinander wären der übliche Weg und der falsche: wer nicht weiß wofür, klickt viermal „Nicht erlauben", und danach fragt macOS nie wieder. Sie kommt beim ersten Start immer, auch wenn zufällig schon alles erlaubt ist — sie erklärt auch den Helfer und den Autostart. Beim Autostart ist `requiresApproval` der Zustand, der weh tut. Wer das Anmeldeobjekt in den Systemeinstellungen abgeschaltet hat, kann in Onyx auf den Schalter drücken, so oft er will. Als „aus" angezeigt führt das in eine Schleife, also steht dort jetzt, wo es weitergeht. Der Mixer verliert den Schalter je Programm. Zehn Mini-Schalter untereinander sind das, was den Eindruck macht; am Regler zu ziehen ist ohnehin die Entscheidung, dieses Programm zu regeln, und der große Ausschalter stellt alles zurück. Der Regler ist selbst gezeichnet — der Systemregler bringt sein eigenes Erscheinungsbild mit und kann nicht zeigen, worauf es hier ankommt: den Pegel und die Grenze bei 100 %. Der Pegel wird im selben Durchlauf gemessen, in dem verstärkt wird, und über `Atomic` weitergereicht. Eine gewöhnliche Eigenschaft wäre ein Wettlauf, eine Sperre im Audiothread der klassische Weg zu Aussetzern. Dabei fällt das `Date()` aus dem Echtzeitpfad, das dort nie hingehört hat. Zwei Funde beim Bauen des Release-Wegs, beide hätten erst nach dem Hochladen zur Ablehnung geführt: der Helfer wurde ohne sicheren Zeitstempel signiert, und das Adapter-Framework ad-hoc. Beides gilt jetzt nur noch im Debug. Scripts/release.sh prüft Zertifikat und Notarisierungsprofil vorweg, statt nach zehn Minuten Bauen zu scheitern. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
110 lines
4.4 KiB
Markdown
110 lines
4.4 KiB
Markdown
# Onyx
|
|
|
|
**Notch-Erweiterung für macOS.** Beim Überfahren der Notch fährt ein Panel mit
|
|
eigenen Widgets aus — Kalender, Wetter, Medien, Hardware, Netzwerk, Audio-Mixer,
|
|
Ablage und AirDrop.
|
|
|
|
Zielgerät: MacBook Pro mit Apple Silicon, macOS 26+.
|
|
|
|
---
|
|
|
|
## Bauen
|
|
|
|
```bash
|
|
xcodegen generate # erzeugt Onyx.xcodeproj aus project.yml
|
|
open Onyx.xcodeproj # dann ⌘R
|
|
```
|
|
|
|
Voraussetzungen: Xcode 26, [XcodeGen](https://github.com/yonaskolb/XcodeGen),
|
|
Signierung mit Team `PP34X97WS3`.
|
|
|
|
Tests laufen ohne Xcode:
|
|
|
|
```bash
|
|
cd Packages/OnyxKit && swift test
|
|
```
|
|
|
|
Ein notarisiertes DMG baut `Scripts/release.sh`. Es braucht zwei Dinge, die
|
|
einmalig einzurichten sind — ein „Developer ID Application“-Zertifikat und ein
|
|
notarytool-Zugangsprofil; beides steht im Kopf des Skripts. Das Skript prüft
|
|
beides vorweg und bricht ab, statt nach zehn Minuten Bauen zu scheitern.
|
|
|
|
---
|
|
|
|
## Aufbau
|
|
|
|
Die Projektdefinition liegt als `project.yml` vor, nicht als handgepflegte
|
|
`.xcodeproj` — so ist im Diff lesbar, was sich an den Build-Einstellungen ändert.
|
|
|
|
```
|
|
Onyx/ App-Target (nicht sandboxed, Hardened Runtime)
|
|
Packages/OnyxKit/ Alle Module als lokales Swift-Package
|
|
OnyxCore Einzelinstanz-Sicherung
|
|
OnyxDesign Farben, Maße, Bewegung — einzige Quelle
|
|
OnyxNotch Panel-Fenster, Geometrie, Zustandsmaschine
|
|
OnyxWidgetKit Widget-Protokoll, Layout-Engine, Persistenz
|
|
OnyxMenuBar Modul-Protokoll für Menüleisten-Elemente
|
|
CalendarProvider EventKit (und später Calendarr)
|
|
WeatherProvider WeatherKit + CoreLocation
|
|
MediaProvider MediaRemote-Adapter, AppleScript, Medientasten
|
|
Vendor/ Fremdcode im Quellzustand (siehe unten)
|
|
Spikes/ Wegwerf-Werkzeuge zur API-Verifikation
|
|
docs/spikes/ Was dabei herauskam — auch die Sackgassen
|
|
```
|
|
|
|
---
|
|
|
|
## Entscheidungen, die man sonst für Fehler hält
|
|
|
|
**Keine App-Sandbox.** Sie ist mit dem privilegierten Helper, mit IOKit und mit
|
|
dem MediaRemote-Adapter unvereinbar. Der App-Group-Container für Calendarr
|
|
bleibt trotzdem erreichbar — auf macOS ist er von der Sandbox unabhängig.
|
|
Nachgemessen in [docs/spikes/D-appgroup.md](docs/spikes/D-appgroup.md).
|
|
|
|
**TCC-Entitlements trotz fehlender Sandbox.** Bei aktivierter Hardened Runtime
|
|
verlangt macOS `com.apple.security.personal-information.*` auch ohne Sandbox.
|
|
Fehlt eine davon, erscheint der Berechtigungsdialog gar nicht erst — ohne
|
|
Fehlermeldung. Das hat einen halben Abend gekostet:
|
|
[docs/spikes/E-tcc-hardened-runtime.md](docs/spikes/E-tcc-hardened-runtime.md).
|
|
|
|
**`ENABLE_DEBUG_DYLIB = NO`.** Xcode lagert im Debug-Build den Programmcode in
|
|
eine eigene dylib aus. TCC ordnet Berechtigungsanfragen dann dem verbleibenden
|
|
Rumpf zu, der weder Info.plist noch Entitlements trägt.
|
|
|
|
**Eigenes Einstellungsfenster.** SwiftUIs `Settings`-Szene öffnet über einen
|
|
privaten Selektor, der bei Apps ohne Menüleiste unzuverlässig ankommt.
|
|
|
|
**Der MediaRemote-Adapter wird nicht gelinkt.** Er wird von `/usr/bin/perl`
|
|
geladen, einem berechtigten Systemprogramm — im eigenen Prozess greift Apples
|
|
Entitlement-Prüfung und es käme nichts an.
|
|
|
|
**Signiert wird im Release anders als im Debug.** Der Helfer und der Adapter
|
|
bekommen nur im Release einen sicheren Zeitstempel, und der Adapter wird dort
|
|
mit der echten Identität statt ad-hoc signiert. Beides verlangt die
|
|
Notarisierung, und beides fällt sonst erst nach dem Hochladen auf. Im Debug
|
|
wären es nur Netzanfragen bei jedem Bauen.
|
|
|
|
**Die Abdeckung eines Calendarr-Schnappschusses steht nicht in der Datei.** Sie
|
|
ist zugesagtes Verhalten des Schreibers (49 Tage nach vorn) und wird von
|
|
`CalendarrSnapshotReader` daraus abgeleitet. Sie aus dem frühesten Termin zu
|
|
erschließen wäre naheliegend und falsch: mehrtägige Termine ragen ins Fenster
|
|
hinein und werden mitgeschrieben, obwohl ihr Anfang nicht abgedeckt ist. Ein
|
|
Test hält das fest.
|
|
|
|
**Der Audiomixer hat keinen Schalter je Programm mehr.** Am Regler zu ziehen
|
|
*ist* die Entscheidung, dieses Programm zu regeln. Ein Schalter davor wäre eine
|
|
Hürde, die nichts schützt — der große Ausschalter stellt ohnehin alles zurück.
|
|
|
|
---
|
|
|
|
## Fremdcode
|
|
|
|
`Vendor/mediaremote-adapter` — [ungive/mediaremote-adapter](https://github.com/ungive/mediaremote-adapter),
|
|
BSD-3-Clause. Als Quellcode eingebettet und beim Bauen kompiliert, nicht als
|
|
fertige Binary: so ist nachvollziehbar, was läuft. Stand siehe
|
|
`ONYX-VERSION.txt`.
|
|
|
|
---
|
|
|
|
© 2026 Scarriffleservices
|