Um ältere macOS-Versionen zu unterstützen, erstellen Sie die App mit einem SDK, das die neueren APIs kennt, legen Sie ein unterstütztes Mindestbereitstellungsziel fest und sichern Sie neuere Aufrufe mit Verfügbarkeitsprüfungen und funktionierenden Ausweichlösungen ab. Diese Anleitung sorgt dafür, dass ein kleines natives Notizenfenster unter macOS 12 nutzbar bleibt, während eine Ansicht für macOS 14 übernommen wird.

Welche Kompatibilitätseinstellungen müssen übereinstimmen?

Für Mac-App-Entwickler besteht die konkrete Aufgabe darin, eine App zu erstellen, die auf der ältesten unterstützten Version startet und neuere Funktionen nutzt, sofern sie verfügbar sind. Trennen Sie zunächst drei Eingaben voneinander: Der Compiler versteht die Quellsprache, das SDK stellt API-Deklarationen bereit und das Bereitstellungsziel gibt die älteste vorgesehene Laufzeitumgebung an. Apples Referenz zu Build-Einstellungen definiert SDKROOT als das SDK, dessen Header und Bibliotheken beim Build verwendet werden. Referenz zu Build-Einstellungen

Ein neueres SDK und ein älteres Bereitstellungsziel können zusammen verwendet werden. Clang dokumentiert ausdrücklich, dass sich mit dem neuesten SDK erstellen lässt, während über -mmacos-version-min= eine ältere macOS-Mindestversion ausgewählt wird. Bei dieser Kombination sind für APIs, die nach der Mindestversion eingeführt wurden, weiterhin Verfügbarkeitsprüfungen erforderlich. Clang-Spracherweiterungen

Wählen Sie eine Mindestversion, die Ihre ausgewählte Xcode-Version tatsächlich unterstützt. Apples Kompatibilitätstabelle unterscheidet zwischen der macOS-Version, die zum Ausführen von Xcode erforderlich ist, und den Bereitstellungszielen, für die damit gebaut werden kann. Liegt Ihre gewünschte Mindestversion außerhalb des unterstützten Bereichs dieser Toolchain, wählen Sie eine passende unterstützte Toolchain oder ändern Sie vor der Implementierung von Ausweichlösungen die Mindestversion der App. SDKs und Systemanforderungen

Für dieses synthetische Beispiel gilt folgender Rahmen: macOS 12 oder neuer, ein SDK mit macOS-14-APIs und ein Notizenfenster mit zwei Zuständen: eine leere Sammlung und eine Beispielnotiz. Die neuere Darstellung des leeren Zustands ist optional; die Notiz lässt sich auch auf der Basisversion anzeigen.

Legen Sie die Mindestversion in beiden Build-Konfigurationen fest

Legen Sie in den Build Settings des App-Ziels für Debug und Release den Wert von MACOSX_DEPLOYMENT_TARGET auf 12.0 fest. Wenn Sie Einstellungen in Konfigurationsdateien verwalten, ist das Folgende ein vollständiger Konfigurationsausschnitt, kein Programm:

MACOSX_DEPLOYMENT_TARGET = 12.0

Weisen Sie die Konfigurationsdatei im Tab Info des Projekts den gewünschten Konfigurationen zu. Prüfen Sie anschließend den endgültigen Zielwert: Apple dokumentiert, dass Zieleinstellungen die Werte einer zugewiesenen Konfigurationsdatei überschreiben können. Die Datei dem Projekt lediglich hinzuzufügen, aktiviert ihre Einstellungen nicht. Eine Build-Konfigurationsdatei zum Projekt hinzufügen

Wie fügen Sie eine neuere API hinzu, ohne die Mindestversion der App anzuheben?

Swifts Prüfung if #available prüft die Verfügbarkeit zur Laufzeit und informiert den Compiler darüber, welche APIs innerhalb dieses Zweigs zulässig sind. Halten Sie die Ausweichlösung in derselben Entscheidung, damit das ältere System über eine vollständige Implementierung verfügt. Das erforderliche * gilt für nicht ausdrücklich genannte Plattformen; es macht die benannte macOS-API nicht auf älteren Versionen verfügbar. Kontrollfluss — Prüfen der API-Verfügbarkeit

Apples ContentUnavailableView ist ab macOS 14 verfügbar und unterstützt Darstellungen für leere Inhalte. Hier bietet ein kleines VStack die entsprechende Darstellung unter macOS 12 und 13. Beide Zweige vermitteln dieselbe nächste Aktion. ContentUnavailableView

Vollständige synthetische SwiftUI-App

Erstellen Sie ein macOS-App-Projekt namens CompatibilityNotes, wählen Sie Swift und SwiftUI aus und setzen Sie das Bereitstellungsziel auf 12.0. Verwenden Sie ein SDK mit macOS-14-APIs. Ersetzen Sie die generierten Deklarationen für App und Inhalt durch die folgende einzelne Datei und achten Sie darauf, dass das Ziel nur eine @main-Deklaration enthält. Assets, Pakete oder Eingabedateien sind nicht erforderlich.

import SwiftUI

@main
struct CompatibilityNotesApp: App {
    var body: some Scene {
        WindowGroup {
            NotesView()
        }
    }
}

struct NotesView: View {
    @State private var notes: [String] = []

    var body: some View {
        VStack(spacing: 16) {
            if notes.isEmpty {
                emptyState
            } else {
                List(notes, id: \.self) { note in
                    Text(note)
                }
            }

            Button(notes.isEmpty ? "Add sample note" : "Reset sample") {
                if notes.isEmpty {
                    notes = ["Sample note: arrange the blue shapes."]
                } else {
                    notes = []
                }
            }
        }
        .padding()
        .frame(minWidth: 360, minHeight: 240)
    }

    @ViewBuilder
    private var emptyState: some View {
        if #available(macOS 14.0, *) {
            ModernEmptyState()
        } else {
            VStack(spacing: 8) {
                Text("No notes")
                    .font(.headline)
                Text("Add a sample note to begin.")
            }
        }
    }
}

@available(macOS 14.0, *)
private struct ModernEmptyState: View {
    var body: some View {
        ContentUnavailableView {
            Label("No notes", systemImage: "note.text")
        } description: {
            Text("Add a sample note to begin.")
        }
    }
}

Das vorgesehene Verhalten ist einfach: Unter macOS 12 und 13 wird der Text-Fallback angezeigt; unter macOS 14 und neuer erscheint ContentUnavailableView. Wenn Sie Add sample note auswählen, wird die synthetische Notiz angezeigt. Reset sample stellt den leeren Zustand wieder her. Diese Demonstration hält ihre Daten im Arbeitsspeicher und speichert Notizen nicht über App-Starts hinweg.

Die Annotation @available beschränkt die Verwendung der Hilfsfunktion auf macOS 14 und neuer. Der #available-Zweig des Aufrufers erfüllt diese Einschränkung. Eine Annotation beschreibt die Verfügbarkeit einer Deklaration; sie stellt keine ältere Implementierung bereit. Attribute — available

Dieses Beispiel wurde anhand der abgerufenen Dokumentation geprüft, aber nicht kompiliert oder ausgeführt: Die verfügbare Ausführungsumgebung war Linux, und weder Swift noch Clang waren installiert. Build- und Laufzeitprüfungen unter macOS sind weiterhin erforderlich.

Was bewirken Verfügbarkeitsprüfungen beim Linken?

Ein Laufzeit-Zweig ist nur dann nützlich, wenn die ausführbare Datei geladen werden kann. Clang dokumentiert, dass Deklarationen mit Verfügbarkeitsannotation, die nach dem Bereitstellungsziel eingeführt wurden, normalerweise schwach gelinkt werden können. Durch eine schwache Referenz darf die Deklaration zur Laufzeit fehlen; die Anwendung muss ihre Verwendung dennoch vermeiden, wenn sie fehlt. Daher spielen neben dem Zweig auch das Bereitstellungsziel und die beim Kompilieren sichtbaren Deklarationen eine Rolle. Attribute in Clang — Verfügbarkeit

Verknüpfen Sie SwiftUI für dieses Beispiel wie gewohnt: Das Framework ist bereits auf der Basisversion macOS 12 vorhanden. Die Kompatibilitätsgrenze umschließt die neuere Ansicht. Wenn ein völlig neues Framework auf Ihrer Basisversion fehlt, prüfen Sie die Framework-Abhängigkeit selbst; die Absicherung eines einzelnen Aufrufs löst nicht alle Ladeanforderungen. Apples Anleitung zum schwachen Linken erläutert den Unterschied zwischen dem Zulassen eines fehlenden Symbols und seiner tatsächlichen Verwendung. Frameworks und schwaches Linken

Verwenden Sie die Verfügbarkeitssyntax der jeweiligen Quellsprache:

Quellsprache Bedingung für die Laufzeitverfügbarkeit
Swift if #available(macOS 14.0, *)
Objective-C oder Objective-C++ if (@available(macOS 14.0, *))
C oder C++ mit Clangs Unterstützung für Apple-Plattformen if (__builtin_available(macOS 14.0, *))

Clang dokumentiert die Objective-C-Schreibweise und das C/C++-Builtin zusammen mit -Wunguarded-availability. Aktivieren Sie Verfügbarkeitsdiagnosen für C-Familien-Code und prüfen Sie Warnungen, bevor Sie ein älteres Bereitstellungsziel als nutzbar einstufen. Clang-Spracherweiterungen

Was, wenn das Build-SDK die API nicht enthält?

Eine Laufzeitprüfung kann keine Deklaration bereitstellen, die im SDK fehlt. Kann der Compiler ContentUnavailableView nicht auflösen, erstellen Sie die App mit einem SDK, das die Deklaration enthält. Muss das Projekt auch mit älteren SDKs erstellt werden, verwalten Sie eine gezielte bedingte Quellanordnung, die nicht unterstützte Verweise bei diesen Builds ausschließt.

Swifts #if compiler(...) prüft die Compilerversion, während #if canImport(...) prüft, ob ein Modul importiert werden kann. Keine der beiden Bedingungen stellt fest, ob ein einzelnes Element eines vorhandenen Moduls auf dem laufenden Mac verfügbar ist. Verwenden Sie diese Kompilierungsbedingungen für die dokumentierten Zwecke und anschließend bei Bedarf Laufzeit-Verfügbarkeitsprüfungen. Anweisungen — Block für bedingte Kompilierung

Wann ändern Swift-ABI- und C++-Bibliotheksgrenzen die Antwort?

Swifts ABI-Stabilität macht nicht jede neuere Standardbibliotheks- oder Laufzeitfunktion auf älteren Systemen verfügbar. Swifts Erläuterung unterscheidet zwischen Quellsprachenmodus und Laufzeitunterstützung: Eine Änderung des Sprachmodus ist eine Kompilierungsentscheidung, während Funktionen, die neue Laufzeitfunktionalität benötigen, Betriebssystemanforderungen haben können. Richten Sie sich nach der Verfügbarkeit der konkreten Funktion, die Sie verwenden. Weiterentwicklung von Swift auf Apple-Plattformen nach der ABI-Stabilität

Bei C++ gibt es eine ähnliche Trennung zwischen Compiler- und Bibliotheksunterstützung. Apple stellt Apple Clang über Xcode und die Laufzeitumgebung libc++ über seine SDKs und Betriebssysteme bereit. Die Funktionstabelle nennt Anforderungen, die von der vom Betriebssystem bereitgestellten Shared Library abhängen können. Die Auswahl von -std=c++17 oder -std=c++20 installiert diese Laufzeitfunktionalität nicht auf dem Mac des Nutzers. Unterstützung der C++-Sprache

Ein anschauliches Beispiel ist die numerische Konvertierung: Apple nennt macOS 10.15 als Mindestversion für die ganzzahligen Funktionen std::to_chars und std::from_chars, aber macOS 13.3 für deren Gleitkomma-Überladungen. Eine macOS-12-App benötigt daher eine kompatible Konvertierungsimplementierung, wenn sie andernfalls diese Gleitkomma-Überladungen voraussetzen würde. Prüfen Sie die genaue Überladung, nicht nur den Header oder die C++-Standardversion. Unterstützung der C++-Sprache

Gehen Sie nicht davon aus, dass es ausreicht, jeden C++-Bibliotheksaufruf in __builtin_available einzuschließen. Clangs Verfügbarkeitsattribute umfassen eine strict-Form, die die Verwendung für frühere Zielplattformen ablehnt, und libc++ verwendet Verfügbarkeitsmarkierungen, um fehlende Laufzeitunterstützung beim Kompilieren zu diagnostizieren. Wenn die ausgewählten Header den Vorgang ablehnen, verwenden Sie eine mit der Basisversion kompatible Implementierung oder heben Sie die Mindestversion an. Attribute in Clang — Verfügbarkeit, Dokumentation der Anbieter — Verfügbarkeitsmarkierungen

Behalten Sie die ABI-Konfiguration der Bibliothek über Abhängigkeiten hinweg bei. LLVM dokumentiert konkrete ABI-Garantien und deren Grenzen, darunter den Hinweis, dass mit neueren libc++-Headern kompilierter Code möglicherweise nicht mit einer älteren Bibliothek funktioniert. Die ABI-ändernden Konfigurationsflags sind Steuerungsmöglichkeiten des Anbieters. Sie im Anwendungscode zu ändern, ist kein Ersatz für eine kompatible Laufzeitumgebung. ABI-Garantien von libc++

Wie diagnostizieren und überprüfen Sie den fertigen Build?

Wählen Sie anhand der Fehlerphase, was Sie als Nächstes untersuchen. Diese Entscheidungshilfe folgt den oben beschriebenen Grenzen von Compiler, Verfügbarkeit und Laufzeit; sie ist eine Diagnosesequenz und keine Behauptung, dass das Beispiel Tests bestanden hat.

Symptom Zuerst untersuchen Nächster praktischer Schritt
Neuer API-Name unbekannt SDK-Deklarationen Wählen Sie ein SDK mit dieser API.
API ist neuer als das Bereitstellungsziel Nicht abgesicherte Verwendung Fügen Sie eine unterstützte Verfügbarkeitsgrenze und eine Ausweichlösung hinzu.
C++-Bibliotheksvorgang wird weiterhin abgelehnt Genaue Überladung und Bibliotheksanforderungen Verwenden Sie eine kompatible Implementierung oder ändern Sie die Mindestversion.
App stürzt ab, bevor das Fenster erscheint Ladeanforderungen und Abhängigkeiten Untersuchen Sie die gemeldete fehlende Bibliothek oder das fehlende Symbol.
Nur die neuere Funktion schlägt fehl Vorgänge außerhalb des abgesicherten Zweigs Prüfen Sie Erzeugung, Initialisierung und Hilfsaufrufe.
Build funktioniert nur auf einer Prozessorfamilie Architekturen von ausführbarer Datei und Abhängigkeiten Erstellen und testen Sie die erforderlichen Architekturslices.

Die Architekturunterstützung ist eine zusätzliche Anforderung. Apples Anleitung zu Universal-Binaries behandelt arm64 und x86_64, einschließlich kompilierter Bibliotheken und Frameworks. Prüfen Sie neben der ausführbaren App auch die Abhängigkeiten; ein erfolgreicher Build für Ihren Entwicklungs-Mac belegt nur die Kompatibilität dieses Builds. Ein universelles macOS-Binary erstellen

Erstellen Sie für dieses Beispiel die Release-Konfiguration und testen Sie die resultierende App unter macOS 12, macOS 13 und macOS 14 oder neuer auf unterstützter Hardware. Starten Sie auf jedem System mit der leeren Sammlung, fügen Sie die Beispielnotiz hinzu und setzen Sie sie zurück. Auf den älteren Versionen sollte die Interaktion über die Ausweichlösung vollständig erhalten bleiben. Testen Sie jede Architektur, die Sie verteilen möchten.

Halten Sie die Supportgrenze beim Ausbau der App ausdrücklich fest: ein unterstütztes Bereitstellungsziel, Deklarationen aus einem geeigneten SDK, abgesicherte neuere Funktionen und eine nützliche Implementierung für die Basisversion. Jede zusätzliche API oder Abhängigkeit sollte denselben Rahmen erfüllen, bevor sie Teil des Builds wird.

Quellen