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>
184 lines
7.8 KiB
YAML
184 lines
7.8 KiB
YAML
name: Onyx
|
|
options:
|
|
bundleIdPrefix: com.scarriffleservices
|
|
deploymentTarget:
|
|
macOS: "26.0"
|
|
createIntermediateGroups: true
|
|
groupSortPosition: top
|
|
|
|
settings:
|
|
base:
|
|
DEVELOPMENT_TEAM: PP34X97WS3
|
|
SWIFT_VERSION: "6.0"
|
|
MARKETING_VERSION: "0.1.0"
|
|
CURRENT_PROJECT_VERSION: "1"
|
|
ENABLE_HARDENED_RUNTIME: YES
|
|
# KEIN --deep.
|
|
#
|
|
# Es überträgt die Entitlements der App auf jede eingebettete Binary. Der
|
|
# privilegierte Helfer bekam dadurch application-identifier, weatherkit und
|
|
# application-groups verpasst — allesamt eingeschränkte Entitlements, die
|
|
# ein Provisioning-Profil verlangen. Ein nacktes Kommandozeilenprogramm kann
|
|
# aber keines einbetten, also lehnte AMFI den Start ab:
|
|
#
|
|
# amfid: OnyxHelper not valid: Code=-413 "No matching profile found"
|
|
# taskgated-helper: Disallowing com.scarriffleservices.onyx.helper
|
|
# because no eligible provisioning profiles found
|
|
#
|
|
# Für das ad-hoc signierte MediaRemoteAdapter.framework wird --deep nicht
|
|
# gebraucht: dafür ist disable-library-validation da.
|
|
SWIFT_STRICT_CONCURRENCY: complete
|
|
# Xcode lagert im Debug-Build den Programmcode in eine eigene dylib aus
|
|
# (für SwiftUI-Vorschauen). Das Hauptprogramm ist dann nur noch ein Rumpf —
|
|
# und TCC ordnet Berechtigungsanfragen dem Rumpf zu, der weder Info.plist
|
|
# noch Entitlements trägt. Ergebnis: requestFullAccessToEvents() liefert
|
|
# kommentarlos false, ohne dass je ein Dialog erscheint.
|
|
ENABLE_DEBUG_DYLIB: NO
|
|
|
|
packages:
|
|
OnyxKit:
|
|
path: Packages/OnyxKit
|
|
|
|
targets:
|
|
# Der privilegierte Helfer. Läuft als root und tut genau eine Sache:
|
|
# Lüfterdrehzahlen setzen. Kein Netzwerk, keine Oberfläche, kein
|
|
# Dateizugriff — je weniger hier steht, desto kleiner die Angriffsfläche.
|
|
OnyxHelper:
|
|
type: tool
|
|
platform: macOS
|
|
sources:
|
|
- path: OnyxHelper
|
|
excludes:
|
|
- "*.plist"
|
|
dependencies:
|
|
- package: OnyxKit
|
|
product: OnyxHelperProtocol
|
|
settings:
|
|
base:
|
|
PRODUCT_BUNDLE_IDENTIFIER: com.scarriffleservices.onyx.helper
|
|
PRODUCT_NAME: OnyxHelper
|
|
CODE_SIGN_STYLE: Automatic
|
|
SKIP_INSTALL: YES
|
|
# Kommandozeilenprogramme haben kein Bundle. Die Kennung muss deshalb
|
|
# in die Binary selbst — sonst signiert codesign sie unter dem
|
|
# Dateinamen und die Signaturprüfung zwischen App und Helfer scheitert.
|
|
INFOPLIST_FILE: OnyxHelper/Info.plist
|
|
CREATE_INFOPLIST_SECTION_IN_BINARY: YES
|
|
|
|
Onyx:
|
|
type: application
|
|
platform: macOS
|
|
sources:
|
|
- path: Onyx
|
|
dependencies:
|
|
- target: OnyxHelper
|
|
embed: false
|
|
- package: OnyxKit
|
|
product: OnyxCore
|
|
- package: OnyxKit
|
|
product: OnyxHelperProtocol
|
|
- package: OnyxKit
|
|
product: OnyxDesign
|
|
- package: OnyxKit
|
|
product: OnyxNotch
|
|
- package: OnyxKit
|
|
product: OnyxWidgetKit
|
|
- package: OnyxKit
|
|
product: OnyxMenuBar
|
|
- package: OnyxKit
|
|
product: CalendarProvider
|
|
- package: OnyxKit
|
|
product: WeatherProvider
|
|
- package: OnyxKit
|
|
product: MediaProvider
|
|
- package: OnyxKit
|
|
product: MetricsProvider
|
|
- package: OnyxKit
|
|
product: NetworkProvider
|
|
- package: OnyxKit
|
|
product: AudioProvider
|
|
- package: OnyxKit
|
|
product: ShelfProvider
|
|
postBuildScripts:
|
|
# Der Helfer und seine Plist müssen an genau diese Stellen: SMAppService
|
|
# sucht die Plist unter Contents/Library/LaunchDaemons und liest von dort
|
|
# den Pfad zum Programm.
|
|
- name: Helfer und Launchd-Plist einbetten
|
|
script: |
|
|
APP="$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH"
|
|
mkdir -p "$APP/MacOS" "$APP/Library/LaunchDaemons"
|
|
cp "$BUILT_PRODUCTS_DIR/OnyxHelper" "$APP/MacOS/OnyxHelper"
|
|
cp "$SRCROOT/OnyxHelper/com.scarriffleservices.onyx.helper.plist" \
|
|
"$APP/Library/LaunchDaemons/"
|
|
# Der Helfer wird eigenständig signiert — die Signatur der App deckt
|
|
# ihn nicht ab, und ohne gültige eigene Signatur lehnt launchd ihn ab.
|
|
#
|
|
# `-i` ist Pflicht: Xcode signiert Kommandozeilenprogramme sonst mit
|
|
# dem Produktnamen ("OnyxHelper") als Bezeichner. Die App prüft aber
|
|
# auf com.scarriffleservices.onyx.helper und würde ihren eigenen
|
|
# Helfer ablehnen.
|
|
# Zeitstempel im Release, keiner im Debug.
|
|
#
|
|
# Die Notarisierung verlangt einen sicheren Zeitstempel; ohne ihn
|
|
# lehnt Apple das Paket ab, und zwar erst nach dem Hochladen. Im
|
|
# Debug wäre er nur eine Netzanfrage bei jedem Bauen.
|
|
if [ "$CONFIGURATION" = "Release" ]; then
|
|
TIMESTAMP="--timestamp"
|
|
else
|
|
TIMESTAMP="--timestamp=none"
|
|
fi
|
|
codesign --force --options runtime $TIMESTAMP \
|
|
-i com.scarriffleservices.onyx.helper \
|
|
--sign "$EXPANDED_CODE_SIGN_IDENTITY" "$APP/MacOS/OnyxHelper"
|
|
|
|
# Kein Neusignieren der App hier: Xcode signiert sie als letzten
|
|
# Schritt, nach diesem Skript. Das repariert das Siegel von selbst
|
|
# und legt im Debug-Build auch get-task-allow bei, ohne die im
|
|
# Skript nachzubauen wäre — nachgemessen an der Reihenfolge im
|
|
# Bauprotokoll (PhaseScriptExecution vor CodeSign Onyx.app).
|
|
# Bewusst ohne outputFiles: mit ihnen überspringt Xcode den Schritt,
|
|
# solange die Plist unverändert ist — auch wenn sich das Programm oder
|
|
# die Signaturvorgaben geändert haben.
|
|
# Der MediaRemote-Adapter wird aus dem mitgelieferten Quellcode gebaut,
|
|
# nicht als fertige Binary eingecheckt: so ist nachvollziehbar, was da
|
|
# läuft, und die Ad-hoc-Signatur passt zum restlichen Bundle.
|
|
#
|
|
# Er darf NICHT gelinkt werden. Geladen wird er von /usr/bin/perl, einem
|
|
# berechtigten Systemprogramm — im eigenen Prozess greift Apples
|
|
# Entitlement-Prüfung und es käme gar nichts an.
|
|
- name: MediaRemote-Adapter bauen und beilegen
|
|
script: |
|
|
# Im Release mit der echten Identität signieren: ad-hoc signierte
|
|
# Bibliotheken lehnt die Notarisierung ab.
|
|
if [ "$CONFIGURATION" = "Release" ]; then
|
|
export SIGN_IDENTITY="$EXPANDED_CODE_SIGN_IDENTITY"
|
|
fi
|
|
OUT="$BUILT_PRODUCTS_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH/Vendor" \
|
|
"$SRCROOT/Scripts/build-mediaremote-adapter.sh"
|
|
inputFiles:
|
|
- $(SRCROOT)/Scripts/build-mediaremote-adapter.sh
|
|
outputFiles:
|
|
- $(BUILT_PRODUCTS_DIR)/$(UNLOCALIZED_RESOURCES_FOLDER_PATH)/Vendor/mediaremote-adapter.pl
|
|
# Das Menüleistensymbol soll das Glyph aus dem App-Icon zeigen, nicht die
|
|
# abgerundete Kachel mit Verlauf. actool kompiliert das .icon-Bündel zu
|
|
# .icns und Assets.car und legt nichts Lesbares ins Bundle — und eine
|
|
# einzelne Datei daraus lässt sich nicht als Ressource referenzieren.
|
|
# Deshalb kopieren statt duplizieren: es bleibt bei einer Quelldatei.
|
|
outputFiles:
|
|
- $(BUILT_PRODUCTS_DIR)/$(UNLOCALIZED_RESOURCES_FOLDER_PATH)/quartz.svg
|
|
settings:
|
|
base:
|
|
PRODUCT_BUNDLE_IDENTIFIER: com.scarriffleservices.onyx
|
|
INFOPLIST_FILE: Onyx/Info.plist
|
|
CODE_SIGN_ENTITLEMENTS: Onyx/Onyx.entitlements
|
|
CODE_SIGN_STYLE: Automatic
|
|
# Kein App-Sandbox: der privilegierte Helper, IOKit und der
|
|
# MediaRemote-Adapter sind damit unvereinbar. Der App-Group-Container
|
|
# bleibt trotzdem erreichbar — siehe docs/spikes/D-appgroup.md.
|
|
ENABLE_APP_SANDBOX: NO
|
|
ENABLE_USER_SCRIPT_SANDBOXING: NO
|
|
COMBINE_HIDPI_IMAGES: YES
|
|
# Icon-Composer-Bündel (Onyx/AppIcon.icon). actool übernimmt daraus
|
|
# alle Größen und die Transluzenz-Darstellung von macOS 26.
|
|
ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon
|