Deine Frage war die richtige. Eine native Mac-App sah an zwei Dutzend Stellen
anders aus, weil AppKit dieselben Dinge anders misst: Schriftgrößen,
Spaltenbreiten, Formularstil. Jede davon habe ich heute einzeln nachgezogen —
und wäre bei der nächsten Ansicht wieder von vorn angefangen.
Mac Catalyst nimmt die iPad-Oberfläche unverändert. Nicht nachgebaut, sondern
dieselbe: gleiche Schrift, gleiche Leiste, gleiche Abstände, und zwar auch in
allem, was noch kommt.
**Ich habe „MKV geht dann nie" gesagt. Das war falsch.** Ohne VLC spielen sie
nicht *unverändert* — der Server rechnet sie um, und das kann er längst. Nur
war die App darauf nicht vorbereitet: die Entscheidung hätte weiterhin VLC
gewählt, den es dort nicht gibt, und das Bild wäre schwarz geblieben.
`PlaybackSettings.hasFallbackEngine` fragt jetzt, ob es den zweiten Spieler auf
dieser Plattform überhaupt gibt. Wo nicht, übernimmt der Server. Das kostet ihn
Rechenzeit und sieht man nicht.
Unverändert abspielen kommt später zurück — dafür braucht es einen Decoder mit
einem Catalyst-Teil. VLCKits Binärpaket hat keinen:
ios-arm64 ios-simulator macos-arm64_x86_64 tvos watchos xros
Drei Stellen mussten Catalyst ausdrücklich ausnehmen: dort gilt `os(iOS)`, aber
ActivityKit gibt es nicht — die Typen sind da und jeder Aufruf ist als nicht
verfügbar markiert. Das ist die Art Falle, die erst der Compiler findet.
Die Anpassungen von vorhin bleiben stehen, obwohl Catalyst sie nicht braucht:
FlixyDesign baut für macOS mit, und `swift test` läuft dort. Sie kosten nichts
und halten den Weg zu einer nativen Mac-App offen, falls VLC ihn eines Tages
nötig macht.
263 Tests grün, iOS baut unverändert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
252 lines
9.5 KiB
YAML
252 lines
9.5 KiB
YAML
name: Flixy
|
|
|
|
options:
|
|
bundleIdPrefix: com.scarriffleservices
|
|
deploymentTarget:
|
|
iOS: "26.0"
|
|
macOS: "26.0"
|
|
createIntermediateGroups: true
|
|
groupSortPosition: top
|
|
developmentLanguage: en
|
|
|
|
settings:
|
|
base:
|
|
DEVELOPMENT_TEAM: PP34X97WS3
|
|
SWIFT_VERSION: "6.0"
|
|
MARKETING_VERSION: "0.1.0"
|
|
CURRENT_PROJECT_VERSION: "1"
|
|
SWIFT_STRICT_CONCURRENCY: complete
|
|
|
|
packages:
|
|
FlixyKit:
|
|
path: Packages/FlixyKit
|
|
# Eigenes Package, weil das VLCKit-Binärpaket 920 MB wiegt und sonst bei
|
|
# jedem `swift test` in FlixyKit mitgezogen würde.
|
|
FlixyVLC:
|
|
path: Packages/FlixyVLC
|
|
|
|
targets:
|
|
Flixy:
|
|
type: application
|
|
platform: iOS
|
|
sources:
|
|
# Das Icon ist ein Bündel, also technisch ein Ordner. Ohne diesen
|
|
# Ausschluss läuft XcodeGen hinein und trägt icon.json und play.svg
|
|
# einzeln ein — dann fehlt das Icon, ohne dass irgendwo ein Fehler
|
|
# auftaucht.
|
|
- path: Flixy
|
|
excludes:
|
|
- "AppIcon.icon"
|
|
- path: Flixy/AppIcon.icon
|
|
type: file
|
|
dependencies:
|
|
- target: DownloadWidget
|
|
# Die neutrale Grundschicht. Ausdrücklich genannt, obwohl sie über
|
|
# PlexKit ohnehin im Baum hängt: die App soll sie direkt benutzen und
|
|
# nicht davon abhängen, dass ein bestimmter Server sie mitschleppt.
|
|
- package: FlixyKit
|
|
product: MediaKit
|
|
- package: FlixyKit
|
|
product: PlexKit
|
|
# Der zweite Server. Steht neben PlexKit, nicht darin: die beiden teilen
|
|
# die neutrale Schicht und sonst nichts.
|
|
- package: FlixyKit
|
|
product: JellyfinKit
|
|
- package: FlixyKit
|
|
product: FlixyDesign
|
|
- package: FlixyKit
|
|
product: FlixyPlayback
|
|
- package: FlixyKit
|
|
product: FlixyDownloads
|
|
- package: FlixyVLC
|
|
product: FlixyVLC
|
|
settings:
|
|
base:
|
|
PRODUCT_BUNDLE_IDENTIFIER: com.scarriffleservices.flixy
|
|
PRODUCT_NAME: Flixy
|
|
# Verweist auf AppIcon.icon. Der frühere leere AppIcon.appiconset im
|
|
# Asset-Katalog ist entfernt — zwei Dinge namens AppIcon, und Xcode
|
|
# nimmt das falsche.
|
|
ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon
|
|
# iPhone und iPad aus demselben Target.
|
|
TARGETED_DEVICE_FAMILY: "1,2"
|
|
CODE_SIGN_STYLE: Automatic
|
|
info:
|
|
path: Flixy/Info.plist
|
|
properties:
|
|
CFBundleDisplayName: Flixy
|
|
UILaunchScreen:
|
|
UIColorName: LaunchBackground
|
|
|
|
# Der harte Schalter für „nur dunkel". Eine Ansicht mit
|
|
# .preferredColorScheme(.dark) allein reicht nicht: Systemdialoge,
|
|
# Statusleiste und Tastatur richten sich danach nicht.
|
|
UIUserInterfaceStyle: Dark
|
|
|
|
# Alle drei bleiben eingetragen: die Info.plist sagt, was die App
|
|
# grundsätzlich kann. Was davon gerade gilt, entscheidet zur Laufzeit
|
|
# OrientationLock über den App-Delegaten — Hochformat beim Blättern,
|
|
# Querformat im Player.
|
|
UISupportedInterfaceOrientations:
|
|
- UIInterfaceOrientationPortrait
|
|
- UIInterfaceOrientationLandscapeLeft
|
|
- UIInterfaceOrientationLandscapeRight
|
|
UISupportedInterfaceOrientations~ipad:
|
|
- UIInterfaceOrientationPortrait
|
|
- UIInterfaceOrientationPortraitUpsideDown
|
|
- UIInterfaceOrientationLandscapeLeft
|
|
- UIInterfaceOrientationLandscapeRight
|
|
|
|
# Ohne diesen Modus hält iOS die Wiedergabe an, sobald die App in den
|
|
# Hintergrund geht — und Bild-in-Bild gäbe es gar nicht.
|
|
UIBackgroundModes:
|
|
- audio
|
|
|
|
# Das Schema, über das Plex nach der Anmeldung zurückschickt. Ohne
|
|
# diesen Eintrag kennt iOS es nicht, und ASWebAuthenticationSession
|
|
# käme nie zurück — das Anmeldefenster bliebe offen stehen.
|
|
CFBundleURLTypes:
|
|
- CFBundleURLName: com.scarriffleservices.flixy.auth
|
|
CFBundleURLSchemes:
|
|
- com.scarriffleservices.flixy
|
|
|
|
# Die Ausfuhr-Erklärung zur Verschlüsselung.
|
|
#
|
|
# `false` heißt: die App nutzt ausschließlich Verschlüsselung, die
|
|
# unter die Ausnahmeregelung fällt. Das trifft hier zu — HTTPS über
|
|
# URLSession und der Schlüsselbund für die Tokens, beides vom
|
|
# Betriebssystem gestellt. Eigene Algorithmen gibt es keine.
|
|
#
|
|
# Ohne diesen Eintrag fragt App Store Connect bei JEDEM Build erneut
|
|
# („Missing Compliance"), und der Build lässt sich bis dahin nicht
|
|
# verteilen.
|
|
#
|
|
# Zu beachten, falls sich das ändert: VLCKit ist ein fremdes Binary
|
|
# und bringt eigene Netzwerkbibliotheken mit. Solange nur Dateien vom
|
|
# eigenen Server abgespielt werden, bleibt es bei Standardverfahren.
|
|
# Käme irgendwann etwas mit eigener Verschlüsselung dazu — DRM etwa —,
|
|
# gehört dieser Wert überprüft.
|
|
ITSAppUsesNonExemptEncryption: false
|
|
|
|
# Ohne diesen Schlüssel lehnt ActivityKit jede Anfrage ab — und
|
|
# zwar wortlos, was die Suche nach dem Grund unangenehm macht.
|
|
NSSupportsLiveActivities: true
|
|
|
|
NSAppTransportSecurity:
|
|
# Plex-Server im Heimnetz laufen überwiegend auf blankem HTTP an
|
|
# Port 32400. Diese Ausnahme erlaubt genau das, ohne die
|
|
# Transportsicherheit für das offene Netz abzuschalten.
|
|
NSAllowsLocalNetworking: true
|
|
|
|
# Seit iOS 14 verlangt jeder Zugriff auf Adressen im eigenen Netz eine
|
|
# Freigabe. Fehlt der Text, verweigert das System sie kommentarlos und
|
|
# die Serversuche findet dauerhaft nichts.
|
|
NSLocalNetworkUsageDescription: >-
|
|
Flixy benötigt Zugriff auf das lokale Netzwerk, um deinen
|
|
Plex-Server zu finden und Medien direkt von ihm zu laden.
|
|
|
|
# Die Live Activity für Downloads. Eine eigene Erweiterung, weil iOS die
|
|
# Darstellung im Sperrbildschirm in einem getrennten Prozess zeichnet — die
|
|
# App selbst läuft zu dem Zeitpunkt meist gar nicht.
|
|
# Dieselben Quellen, dasselbe Aussehen.
|
|
#
|
|
# Mac Catalyst statt einer eigenen Mac-App: die iPad-Oberfläche läuft damit
|
|
# unverändert auf dem Mac — gleiche Schriftgrößen, gleiche Seitenleiste,
|
|
# gleiche Abstände. Eine native Mac-App war der erste Versuch; sie sah an
|
|
# zwei Dutzend Stellen anders aus, weil AppKit dieselben Dinge anders misst,
|
|
# und jede davon hätte einzeln nachgezogen werden müssen.
|
|
#
|
|
# Ohne DownloadWidget (Live Activities gibt es hier nicht) und **ohne
|
|
# FlixyVLC**: dessen Binärpaket hat keinen Teil für Catalyst. MKV und DTS
|
|
# werden dort deshalb vom Server umgerechnet statt unverändert übertragen —
|
|
# siehe `PlaybackSettings.hasFallbackEngine`.
|
|
FlixyMac:
|
|
type: application
|
|
platform: iOS
|
|
sources:
|
|
- path: Flixy
|
|
excludes:
|
|
- "AppIcon.icon"
|
|
- path: Flixy/AppIcon.icon
|
|
type: file
|
|
dependencies:
|
|
- package: FlixyKit
|
|
product: MediaKit
|
|
- package: FlixyKit
|
|
product: PlexKit
|
|
- package: FlixyKit
|
|
product: JellyfinKit
|
|
- package: FlixyKit
|
|
product: FlixyDesign
|
|
- package: FlixyKit
|
|
product: FlixyPlayback
|
|
- package: FlixyKit
|
|
product: FlixyDownloads
|
|
settings:
|
|
base:
|
|
SUPPORTS_MACCATALYST: YES
|
|
# Nur Mac: dieses Ziel ist nicht dazu da, aufs iPhone zu wandern.
|
|
SUPPORTED_PLATFORMS: macosx
|
|
# „An das iPad angeglichen" statt „für den Mac optimiert" — genau
|
|
# darum geht es.
|
|
MACCATALYST_OPTIMIZE_FOR_MAC: NO
|
|
DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER: NO
|
|
PRODUCT_BUNDLE_IDENTIFIER: com.scarriffleservices.flixy
|
|
PRODUCT_NAME: Flixy
|
|
ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon
|
|
TARGETED_DEVICE_FAMILY: "2"
|
|
# Selbst signiert: ein Build zum Ansehen soll nicht jedes Mal nach dem
|
|
# Schlüsselbund-Passwort fragen.
|
|
CODE_SIGN_STYLE: Manual
|
|
CODE_SIGN_IDENTITY: "-"
|
|
DEVELOPMENT_TEAM: ""
|
|
ENABLE_HARDENED_RUNTIME: NO
|
|
info:
|
|
path: Flixy/Info-macOS.plist
|
|
properties:
|
|
CFBundleDisplayName: Flixy
|
|
UILaunchScreen:
|
|
UIColorName: LaunchBackground
|
|
UIUserInterfaceStyle: Dark
|
|
UISupportedInterfaceOrientations:
|
|
- UIInterfaceOrientationPortrait
|
|
- UIInterfaceOrientationLandscapeLeft
|
|
- UIInterfaceOrientationLandscapeRight
|
|
UIBackgroundModes:
|
|
- audio
|
|
LSApplicationCategoryType: public.app-category.entertainment
|
|
CFBundleURLTypes:
|
|
- CFBundleURLName: com.scarriffleservices.flixy.auth
|
|
CFBundleURLSchemes:
|
|
- com.scarriffleservices.flixy
|
|
ITSAppUsesNonExemptEncryption: false
|
|
NSAppTransportSecurity:
|
|
NSAllowsLocalNetworking: true
|
|
|
|
DownloadWidget:
|
|
type: app-extension
|
|
platform: iOS
|
|
sources:
|
|
- path: DownloadWidget
|
|
dependencies:
|
|
- package: FlixyKit
|
|
product: FlixyDownloads
|
|
- package: FlixyKit
|
|
product: FlixyDesign
|
|
settings:
|
|
base:
|
|
PRODUCT_BUNDLE_IDENTIFIER: com.scarriffleservices.flixy.downloadwidget
|
|
PRODUCT_NAME: DownloadWidget
|
|
CODE_SIGN_STYLE: Automatic
|
|
SKIP_INSTALL: YES
|
|
# Von XcodeGen erzeugt statt von Hand geschrieben. Eine eigene Datei ohne
|
|
# CFBundleIdentifier führt zu einer Erweiterung ganz ohne Kennung — und
|
|
# der Fehler lautet dann „not prefixed with the parent app's bundle
|
|
# identifier", was auf eine falsche Fährte führt.
|
|
info:
|
|
path: DownloadWidget/Info.plist
|
|
properties:
|
|
CFBundleDisplayName: Flixy Downloads
|
|
NSExtension:
|
|
NSExtensionPointIdentifier: com.apple.widgetkit-extension
|