diff --git a/.github/workflows/featureflags_example.yml b/.github/workflows/featureflags_example.yml
new file mode 100644
index 0000000..9a592cc
--- /dev/null
+++ b/.github/workflows/featureflags_example.yml
@@ -0,0 +1,53 @@
+name: FeatureFlagsExample
+
+on:
+ push:
+ branches: [main]
+ paths:
+ - 'FeatureFlags/**'
+ - 'Example/FeatureFlagsExample/**'
+ - 'Example/Resources/**'
+ - 'Example/Project.swift'
+ - 'Example/Tuist.swift'
+ - 'Example/Tuist/**'
+ - 'Example/mise.toml'
+ - 'Package.swift'
+ - '.github/actions/build-example/**'
+ - '.github/workflows/featureflags_example.yml'
+ pull_request:
+ branches: [main]
+ paths:
+ - 'FeatureFlags/**'
+ - 'Example/FeatureFlagsExample/**'
+ - 'Example/Resources/**'
+ - 'Example/Project.swift'
+ - 'Example/Tuist.swift'
+ - 'Example/Tuist/**'
+ - 'Example/mise.toml'
+ - 'Package.swift'
+ - '.github/actions/build-example/**'
+ - '.github/workflows/featureflags_example.yml'
+
+jobs:
+ build:
+ name: Build FeatureFlagsExample (${{ matrix.platform }})
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - platform: iOS
+ destination: "generic/platform=iOS"
+ - platform: iOS Simulator
+ destination: "generic/platform=iOS Simulator"
+ - platform: macOS
+ destination: "platform=macOS"
+ runs-on:
+ - macos-15
+ - xcode-26.6
+ steps:
+ - uses: actions/checkout@v4
+ - uses: ./.github/actions/build-example
+ with:
+ scheme: FeatureFlagsExample
+ destination: ${{ matrix.destination }}
+ xcode-version: "26.6"
diff --git a/Example/FeatureFlagsExample/ContentView.swift b/Example/FeatureFlagsExample/ContentView.swift
new file mode 100644
index 0000000..943f05a
--- /dev/null
+++ b/Example/FeatureFlagsExample/ContentView.swift
@@ -0,0 +1,50 @@
+//
+// ContentView.swift
+// DarwinPrivateFrameworks
+
+import FeatureFlags
+import SwiftUI
+
+private struct GestureContainerKey: FeatureFlagsKey {
+ var domain: StaticString { "SwiftUI" }
+
+ var feature: StaticString { "gestureContainer" }
+}
+
+struct ContentView: View {
+ @State private var isEnabled = FeatureFlags.isFeatureEnabled(GestureContainerKey())
+
+ var body: some View {
+ NavigationStack {
+ Form {
+ Section {
+ LabeledContent("Domain", value: "SwiftUI")
+ LabeledContent("Feature", value: "gestureContainer")
+ LabeledContent("Status") {
+ Label(
+ isEnabled ? "Enabled" : "Disabled",
+ systemImage: isEnabled ? "checkmark.circle.fill" : "minus.circle"
+ )
+ .foregroundStyle(isEnabled ? .green : .secondary)
+ }
+ } footer: {
+ Text("The result comes from the system feature flag service.")
+ }
+ }
+ .formStyle(.grouped)
+ .navigationTitle("Feature Flags")
+ .toolbar {
+ Button("Refresh", systemImage: "arrow.clockwise") {
+ isEnabled = FeatureFlags.isFeatureEnabled(GestureContainerKey())
+ }
+ }
+ }
+ #if os(macOS)
+ .frame(minWidth: 400, minHeight: 260)
+ #endif
+ }
+}
+
+#Preview {
+ ContentView()
+}
diff --git a/Example/FeatureFlagsExample/ExampleApp.swift b/Example/FeatureFlagsExample/ExampleApp.swift
new file mode 100644
index 0000000..8f24a84
--- /dev/null
+++ b/Example/FeatureFlagsExample/ExampleApp.swift
@@ -0,0 +1,14 @@
+//
+// ExampleApp.swift
+// DarwinPrivateFrameworks
+
+import SwiftUI
+
+@main
+struct ExampleApp: App {
+ var body: some Scene {
+ WindowGroup {
+ ContentView()
+ }
+ }
+}
diff --git a/Example/Project.swift b/Example/Project.swift
index 8f91b2a..28ff850 100644
--- a/Example/Project.swift
+++ b/Example/Project.swift
@@ -135,6 +135,24 @@ let project = Project(
],
settings: .settings(base: baseSettings)
),
+ // MARK: FeatureFlagsExample
+ .target(
+ name: "FeatureFlagsExample",
+ destinations: [.iPhone, .iPad, .mac],
+ product: .app,
+ bundleId: "\(bundleIdPrefix).FeatureFlagsExample",
+ deploymentTargets: .multiplatform(
+ iOS: "18.5",
+ macOS: "15.0"
+ ),
+ infoPlist: .extendingDefault(with: defaultInfoPlist),
+ sources: ["FeatureFlagsExample/**"],
+ resources: sharedResources,
+ dependencies: [
+ .external(name: "FeatureFlags"),
+ ],
+ settings: .settings(base: baseSettings)
+ ),
// MARK: SFSymbolsExample
.target(
name: "SFSymbolsExample",
diff --git a/Example/README.md b/Example/README.md
index f61d7c7..df7a379 100644
--- a/Example/README.md
+++ b/Example/README.md
@@ -39,6 +39,10 @@ This generates `Example.xcworkspace` — open it in Xcode to build and run the e
| BLSExample_2024 | BacklightServices | iOS, visionOS |
| SFSymbolsExample_2024 | SFSymbols | iOS, macOS |
| GFExample_2025 | Gestures | iOS, macOS |
+| FeatureFlagsExample | FeatureFlags | iOS, macOS |
+
+`FeatureFlagsExample` queries the system `SwiftUI.gestureContainer` flag and
+displays its enabled state. Use Refresh to query the flag again.
## Regenerating
diff --git a/Example/Tuist/Package.resolved b/Example/Tuist/Package.resolved
index ce722f5..dfb6df8 100644
--- a/Example/Tuist/Package.resolved
+++ b/Example/Tuist/Package.resolved
@@ -1,5 +1,5 @@
{
- "originHash" : "7866d60ad2f4815a011f3cf7861bd2655f5c3bcf38fd586b2147856e73f85c3d",
+ "originHash" : "0c63bc8cfeb9fa1ca4827a57b55d8680c0df6c5b5b09a1359a78b55eaa008fa1",
"pins" : [
{
"identity" : "swift-collections",
diff --git a/FeatureFlags/2024/FeatureFlags.xcframework/Info.plist b/FeatureFlags/2024/FeatureFlags.xcframework/Info.plist
new file mode 100644
index 0000000..5c3e402
--- /dev/null
+++ b/FeatureFlags/2024/FeatureFlags.xcframework/Info.plist
@@ -0,0 +1,55 @@
+
+
+
+
+ AvailableLibraries
+
+
+ LibraryIdentifier
+ macos-arm64e-arm64-x86_64
+ LibraryPath
+ FeatureFlags.framework
+ SupportedArchitectures
+
+ arm64e
+ arm64
+ x86_64
+
+ SupportedPlatform
+ macos
+
+
+ LibraryIdentifier
+ ios-arm64-arm64e
+ LibraryPath
+ FeatureFlags.framework
+ SupportedArchitectures
+
+ arm64
+ arm64e
+
+ SupportedPlatform
+ ios
+
+
+ LibraryIdentifier
+ ios-arm64-x86_64-simulator
+ LibraryPath
+ FeatureFlags.framework
+ SupportedArchitectures
+
+ arm64
+ x86_64
+
+ SupportedPlatform
+ ios
+ SupportedPlatformVariant
+ simulator
+
+
+ CFBundlePackageType
+ XFWK
+ XCFrameworkFormatVersion
+ 1.0
+
+
diff --git a/FeatureFlags/2024/FeatureFlags.xcframework/ios-arm64-arm64e/FeatureFlags.framework/FeatureFlags.tbd b/FeatureFlags/2024/FeatureFlags.xcframework/ios-arm64-arm64e/FeatureFlags.framework/FeatureFlags.tbd
new file mode 100644
index 0000000..cb9e5d1
--- /dev/null
+++ b/FeatureFlags/2024/FeatureFlags.xcframework/ios-arm64-arm64e/FeatureFlags.framework/FeatureFlags.tbd
@@ -0,0 +1,45 @@
+{
+ "main_library": {
+ "current_versions": [
+ {
+ "version": "97"
+ }
+ ],
+ "exported_symbols": [
+ {
+ "data": {
+ "global": [
+ "_$s12FeatureFlags02isA7EnabledySbAA0aB3Key_pF",
+ "_$s12FeatureFlags0aB3KeyMp",
+ "_$s12FeatureFlags0aB3KeyP6domains12StaticStringVvgTj",
+ "_$s12FeatureFlags0aB3KeyP6domains12StaticStringVvgTq",
+ "_$s12FeatureFlags0aB3KeyP7features12StaticStringVvgTj",
+ "_$s12FeatureFlags0aB3KeyP7features12StaticStringVvgTq",
+ "_$s12FeatureFlags0aB3KeyTL"
+ ]
+ }
+ }
+ ],
+ "install_names": [
+ {
+ "name": "/System/Library/PrivateFrameworks/FeatureFlags.framework/FeatureFlags"
+ }
+ ],
+ "swift_abi": [
+ {
+ "abi": 7
+ }
+ ],
+ "target_info": [
+ {
+ "min_deployment": "18.0",
+ "target": "arm64-ios"
+ },
+ {
+ "min_deployment": "18.0",
+ "target": "arm64e-ios"
+ }
+ ]
+ },
+ "tapi_tbd_version": 5
+}
diff --git a/FeatureFlags/2024/FeatureFlags.xcframework/ios-arm64-arm64e/FeatureFlags.framework/Info.plist b/FeatureFlags/2024/FeatureFlags.xcframework/ios-arm64-arm64e/FeatureFlags.framework/Info.plist
new file mode 100644
index 0000000..9c78393
--- /dev/null
+++ b/FeatureFlags/2024/FeatureFlags.xcframework/ios-arm64-arm64e/FeatureFlags.framework/Info.plist
@@ -0,0 +1,16 @@
+
+
+
+
+ CFBundleExecutable
+ FeatureFlags
+ CFBundleIdentifier
+ com.apple.FeatureFlags
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundlePackageType
+ FMWK
+ CFBundleShortVersionString
+ 1.0.0
+
+
diff --git a/FeatureFlags/2024/FeatureFlags.xcframework/ios-arm64-arm64e/FeatureFlags.framework/Modules/FeatureFlags.swiftmodule/arm64-apple-ios.swiftinterface b/FeatureFlags/2024/FeatureFlags.xcframework/ios-arm64-arm64e/FeatureFlags.framework/Modules/FeatureFlags.swiftmodule/arm64-apple-ios.swiftinterface
new file mode 100644
index 0000000..79c07f9
--- /dev/null
+++ b/FeatureFlags/2024/FeatureFlags.xcframework/ios-arm64-arm64e/FeatureFlags.framework/Modules/FeatureFlags.swiftmodule/arm64-apple-ios.swiftinterface
@@ -0,0 +1,11 @@
+// swift-interface-format-version: 1.0
+// swift-compiler-version: Apple Swift version 6.1
+// swift-module-flags: -target arm64-apple-ios18.0 -enable-objc-interop -enable-library-evolution -swift-version 5 -module-name FeatureFlags
+public import Swift
+
+public protocol FeatureFlagsKey {
+ var domain: Swift.StaticString { get }
+ var feature: Swift.StaticString { get }
+}
+
+public func isFeatureEnabled(_ key: any FeatureFlags.FeatureFlagsKey) -> Swift.Bool
diff --git a/FeatureFlags/2024/FeatureFlags.xcframework/ios-arm64-arm64e/FeatureFlags.framework/Modules/FeatureFlags.swiftmodule/arm64e-apple-ios.swiftinterface b/FeatureFlags/2024/FeatureFlags.xcframework/ios-arm64-arm64e/FeatureFlags.framework/Modules/FeatureFlags.swiftmodule/arm64e-apple-ios.swiftinterface
new file mode 100644
index 0000000..cd5016e
--- /dev/null
+++ b/FeatureFlags/2024/FeatureFlags.xcframework/ios-arm64-arm64e/FeatureFlags.framework/Modules/FeatureFlags.swiftmodule/arm64e-apple-ios.swiftinterface
@@ -0,0 +1,11 @@
+// swift-interface-format-version: 1.0
+// swift-compiler-version: Apple Swift version 6.1
+// swift-module-flags: -target arm64e-apple-ios18.0 -enable-objc-interop -enable-library-evolution -swift-version 5 -module-name FeatureFlags
+public import Swift
+
+public protocol FeatureFlagsKey {
+ var domain: Swift.StaticString { get }
+ var feature: Swift.StaticString { get }
+}
+
+public func isFeatureEnabled(_ key: any FeatureFlags.FeatureFlagsKey) -> Swift.Bool
diff --git a/FeatureFlags/2024/FeatureFlags.xcframework/ios-arm64-x86_64-simulator/FeatureFlags.framework/FeatureFlags.tbd b/FeatureFlags/2024/FeatureFlags.xcframework/ios-arm64-x86_64-simulator/FeatureFlags.framework/FeatureFlags.tbd
new file mode 100644
index 0000000..5456c14
--- /dev/null
+++ b/FeatureFlags/2024/FeatureFlags.xcframework/ios-arm64-x86_64-simulator/FeatureFlags.framework/FeatureFlags.tbd
@@ -0,0 +1,45 @@
+{
+ "main_library": {
+ "current_versions": [
+ {
+ "version": "97"
+ }
+ ],
+ "exported_symbols": [
+ {
+ "data": {
+ "global": [
+ "_$s12FeatureFlags02isA7EnabledySbAA0aB3Key_pF",
+ "_$s12FeatureFlags0aB3KeyMp",
+ "_$s12FeatureFlags0aB3KeyP6domains12StaticStringVvgTj",
+ "_$s12FeatureFlags0aB3KeyP6domains12StaticStringVvgTq",
+ "_$s12FeatureFlags0aB3KeyP7features12StaticStringVvgTj",
+ "_$s12FeatureFlags0aB3KeyP7features12StaticStringVvgTq",
+ "_$s12FeatureFlags0aB3KeyTL"
+ ]
+ }
+ }
+ ],
+ "install_names": [
+ {
+ "name": "/System/Library/PrivateFrameworks/FeatureFlags.framework/FeatureFlags"
+ }
+ ],
+ "swift_abi": [
+ {
+ "abi": 7
+ }
+ ],
+ "target_info": [
+ {
+ "min_deployment": "18.5",
+ "target": "x86_64-ios-simulator"
+ },
+ {
+ "min_deployment": "18.5",
+ "target": "arm64-ios-simulator"
+ }
+ ]
+ },
+ "tapi_tbd_version": 5
+}
diff --git a/FeatureFlags/2024/FeatureFlags.xcframework/ios-arm64-x86_64-simulator/FeatureFlags.framework/Info.plist b/FeatureFlags/2024/FeatureFlags.xcframework/ios-arm64-x86_64-simulator/FeatureFlags.framework/Info.plist
new file mode 100644
index 0000000..9c78393
--- /dev/null
+++ b/FeatureFlags/2024/FeatureFlags.xcframework/ios-arm64-x86_64-simulator/FeatureFlags.framework/Info.plist
@@ -0,0 +1,16 @@
+
+
+
+
+ CFBundleExecutable
+ FeatureFlags
+ CFBundleIdentifier
+ com.apple.FeatureFlags
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundlePackageType
+ FMWK
+ CFBundleShortVersionString
+ 1.0.0
+
+
diff --git a/FeatureFlags/2024/FeatureFlags.xcframework/ios-arm64-x86_64-simulator/FeatureFlags.framework/Modules/FeatureFlags.swiftmodule/arm64-apple-ios-simulator.swiftinterface b/FeatureFlags/2024/FeatureFlags.xcframework/ios-arm64-x86_64-simulator/FeatureFlags.framework/Modules/FeatureFlags.swiftmodule/arm64-apple-ios-simulator.swiftinterface
new file mode 100644
index 0000000..7b23051
--- /dev/null
+++ b/FeatureFlags/2024/FeatureFlags.xcframework/ios-arm64-x86_64-simulator/FeatureFlags.framework/Modules/FeatureFlags.swiftmodule/arm64-apple-ios-simulator.swiftinterface
@@ -0,0 +1,11 @@
+// swift-interface-format-version: 1.0
+// swift-compiler-version: Apple Swift version 6.1
+// swift-module-flags: -target arm64-apple-ios18.5-simulator -enable-objc-interop -enable-library-evolution -swift-version 5 -module-name FeatureFlags
+public import Swift
+
+public protocol FeatureFlagsKey {
+ var domain: Swift.StaticString { get }
+ var feature: Swift.StaticString { get }
+}
+
+public func isFeatureEnabled(_ key: any FeatureFlags.FeatureFlagsKey) -> Swift.Bool
diff --git a/FeatureFlags/2024/FeatureFlags.xcframework/ios-arm64-x86_64-simulator/FeatureFlags.framework/Modules/FeatureFlags.swiftmodule/x86_64-apple-ios-simulator.swiftinterface b/FeatureFlags/2024/FeatureFlags.xcframework/ios-arm64-x86_64-simulator/FeatureFlags.framework/Modules/FeatureFlags.swiftmodule/x86_64-apple-ios-simulator.swiftinterface
new file mode 100644
index 0000000..1cc3d25
--- /dev/null
+++ b/FeatureFlags/2024/FeatureFlags.xcframework/ios-arm64-x86_64-simulator/FeatureFlags.framework/Modules/FeatureFlags.swiftmodule/x86_64-apple-ios-simulator.swiftinterface
@@ -0,0 +1,11 @@
+// swift-interface-format-version: 1.0
+// swift-compiler-version: Apple Swift version 6.1
+// swift-module-flags: -target x86_64-apple-ios18.5-simulator -enable-objc-interop -enable-library-evolution -swift-version 5 -module-name FeatureFlags
+public import Swift
+
+public protocol FeatureFlagsKey {
+ var domain: Swift.StaticString { get }
+ var feature: Swift.StaticString { get }
+}
+
+public func isFeatureEnabled(_ key: any FeatureFlags.FeatureFlagsKey) -> Swift.Bool
diff --git a/FeatureFlags/2024/FeatureFlags.xcframework/macos-arm64e-arm64-x86_64/FeatureFlags.framework/FeatureFlags.tbd b/FeatureFlags/2024/FeatureFlags.xcframework/macos-arm64e-arm64-x86_64/FeatureFlags.framework/FeatureFlags.tbd
new file mode 120000
index 0000000..4401793
--- /dev/null
+++ b/FeatureFlags/2024/FeatureFlags.xcframework/macos-arm64e-arm64-x86_64/FeatureFlags.framework/FeatureFlags.tbd
@@ -0,0 +1 @@
+Versions/Current/FeatureFlags.tbd
\ No newline at end of file
diff --git a/FeatureFlags/2024/FeatureFlags.xcframework/macos-arm64e-arm64-x86_64/FeatureFlags.framework/Modules b/FeatureFlags/2024/FeatureFlags.xcframework/macos-arm64e-arm64-x86_64/FeatureFlags.framework/Modules
new file mode 120000
index 0000000..5736f31
--- /dev/null
+++ b/FeatureFlags/2024/FeatureFlags.xcframework/macos-arm64e-arm64-x86_64/FeatureFlags.framework/Modules
@@ -0,0 +1 @@
+Versions/Current/Modules
\ No newline at end of file
diff --git a/FeatureFlags/2024/FeatureFlags.xcframework/macos-arm64e-arm64-x86_64/FeatureFlags.framework/Resources b/FeatureFlags/2024/FeatureFlags.xcframework/macos-arm64e-arm64-x86_64/FeatureFlags.framework/Resources
new file mode 120000
index 0000000..953ee36
--- /dev/null
+++ b/FeatureFlags/2024/FeatureFlags.xcframework/macos-arm64e-arm64-x86_64/FeatureFlags.framework/Resources
@@ -0,0 +1 @@
+Versions/Current/Resources
\ No newline at end of file
diff --git a/FeatureFlags/2024/FeatureFlags.xcframework/macos-arm64e-arm64-x86_64/FeatureFlags.framework/Versions/A/FeatureFlags.tbd b/FeatureFlags/2024/FeatureFlags.xcframework/macos-arm64e-arm64-x86_64/FeatureFlags.framework/Versions/A/FeatureFlags.tbd
new file mode 100644
index 0000000..3adeb80
--- /dev/null
+++ b/FeatureFlags/2024/FeatureFlags.xcframework/macos-arm64e-arm64-x86_64/FeatureFlags.framework/Versions/A/FeatureFlags.tbd
@@ -0,0 +1,15 @@
+--- !tapi-tbd
+tbd-version: 4
+targets: [ x86_64-macos, x86_64-maccatalyst, arm64-macos, arm64-maccatalyst,
+ arm64e-macos, arm64e-maccatalyst ]
+install-name: '/System/Library/PrivateFrameworks/FeatureFlags.framework/Versions/A/FeatureFlags'
+current-version: 97
+swift-abi-version: 7
+exports:
+ - targets: [ x86_64-macos, x86_64-maccatalyst, arm64-macos, arm64-maccatalyst,
+ arm64e-macos, arm64e-maccatalyst ]
+ symbols: [ '_$s12FeatureFlags02isA7EnabledySbAA0aB3Key_pF', '_$s12FeatureFlags0aB3KeyMp',
+ '_$s12FeatureFlags0aB3KeyP6domains12StaticStringVvgTj', '_$s12FeatureFlags0aB3KeyP6domains12StaticStringVvgTq',
+ '_$s12FeatureFlags0aB3KeyP7features12StaticStringVvgTj', '_$s12FeatureFlags0aB3KeyP7features12StaticStringVvgTq',
+ '_$s12FeatureFlags0aB3KeyTL' ]
+...
diff --git a/FeatureFlags/2024/FeatureFlags.xcframework/macos-arm64e-arm64-x86_64/FeatureFlags.framework/Versions/A/Modules/FeatureFlags.swiftmodule/arm64-apple-macos.swiftinterface b/FeatureFlags/2024/FeatureFlags.xcframework/macos-arm64e-arm64-x86_64/FeatureFlags.framework/Versions/A/Modules/FeatureFlags.swiftmodule/arm64-apple-macos.swiftinterface
new file mode 100644
index 0000000..a5d1c1d
--- /dev/null
+++ b/FeatureFlags/2024/FeatureFlags.xcframework/macos-arm64e-arm64-x86_64/FeatureFlags.framework/Versions/A/Modules/FeatureFlags.swiftmodule/arm64-apple-macos.swiftinterface
@@ -0,0 +1,11 @@
+// swift-interface-format-version: 1.0
+// swift-compiler-version: Apple Swift version 6.1
+// swift-module-flags: -target arm64-apple-macos15.0 -enable-objc-interop -enable-library-evolution -swift-version 5 -module-name FeatureFlags
+public import Swift
+
+public protocol FeatureFlagsKey {
+ var domain: Swift.StaticString { get }
+ var feature: Swift.StaticString { get }
+}
+
+public func isFeatureEnabled(_ key: any FeatureFlags.FeatureFlagsKey) -> Swift.Bool
diff --git a/FeatureFlags/2024/FeatureFlags.xcframework/macos-arm64e-arm64-x86_64/FeatureFlags.framework/Versions/A/Modules/FeatureFlags.swiftmodule/arm64e-apple-macos.swiftinterface b/FeatureFlags/2024/FeatureFlags.xcframework/macos-arm64e-arm64-x86_64/FeatureFlags.framework/Versions/A/Modules/FeatureFlags.swiftmodule/arm64e-apple-macos.swiftinterface
new file mode 100644
index 0000000..aeef743
--- /dev/null
+++ b/FeatureFlags/2024/FeatureFlags.xcframework/macos-arm64e-arm64-x86_64/FeatureFlags.framework/Versions/A/Modules/FeatureFlags.swiftmodule/arm64e-apple-macos.swiftinterface
@@ -0,0 +1,11 @@
+// swift-interface-format-version: 1.0
+// swift-compiler-version: Apple Swift version 6.1
+// swift-module-flags: -target arm64e-apple-macos15.0 -enable-objc-interop -enable-library-evolution -swift-version 5 -module-name FeatureFlags
+public import Swift
+
+public protocol FeatureFlagsKey {
+ var domain: Swift.StaticString { get }
+ var feature: Swift.StaticString { get }
+}
+
+public func isFeatureEnabled(_ key: any FeatureFlags.FeatureFlagsKey) -> Swift.Bool
diff --git a/FeatureFlags/2024/FeatureFlags.xcframework/macos-arm64e-arm64-x86_64/FeatureFlags.framework/Versions/A/Modules/FeatureFlags.swiftmodule/x86_64-apple-macos.swiftinterface b/FeatureFlags/2024/FeatureFlags.xcframework/macos-arm64e-arm64-x86_64/FeatureFlags.framework/Versions/A/Modules/FeatureFlags.swiftmodule/x86_64-apple-macos.swiftinterface
new file mode 100644
index 0000000..8b273b1
--- /dev/null
+++ b/FeatureFlags/2024/FeatureFlags.xcframework/macos-arm64e-arm64-x86_64/FeatureFlags.framework/Versions/A/Modules/FeatureFlags.swiftmodule/x86_64-apple-macos.swiftinterface
@@ -0,0 +1,11 @@
+// swift-interface-format-version: 1.0
+// swift-compiler-version: Apple Swift version 6.1
+// swift-module-flags: -target x86_64-apple-macos15.0 -enable-objc-interop -enable-library-evolution -swift-version 5 -module-name FeatureFlags
+public import Swift
+
+public protocol FeatureFlagsKey {
+ var domain: Swift.StaticString { get }
+ var feature: Swift.StaticString { get }
+}
+
+public func isFeatureEnabled(_ key: any FeatureFlags.FeatureFlagsKey) -> Swift.Bool
diff --git a/FeatureFlags/2024/FeatureFlags.xcframework/macos-arm64e-arm64-x86_64/FeatureFlags.framework/Versions/A/Resources/Info.plist b/FeatureFlags/2024/FeatureFlags.xcframework/macos-arm64e-arm64-x86_64/FeatureFlags.framework/Versions/A/Resources/Info.plist
new file mode 100644
index 0000000..9c78393
--- /dev/null
+++ b/FeatureFlags/2024/FeatureFlags.xcframework/macos-arm64e-arm64-x86_64/FeatureFlags.framework/Versions/A/Resources/Info.plist
@@ -0,0 +1,16 @@
+
+
+
+
+ CFBundleExecutable
+ FeatureFlags
+ CFBundleIdentifier
+ com.apple.FeatureFlags
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundlePackageType
+ FMWK
+ CFBundleShortVersionString
+ 1.0.0
+
+
diff --git a/FeatureFlags/2024/FeatureFlags.xcframework/macos-arm64e-arm64-x86_64/FeatureFlags.framework/Versions/Current b/FeatureFlags/2024/FeatureFlags.xcframework/macos-arm64e-arm64-x86_64/FeatureFlags.framework/Versions/Current
new file mode 120000
index 0000000..8c7e5a6
--- /dev/null
+++ b/FeatureFlags/2024/FeatureFlags.xcframework/macos-arm64e-arm64-x86_64/FeatureFlags.framework/Versions/Current
@@ -0,0 +1 @@
+A
\ No newline at end of file
diff --git a/FeatureFlags/2024/Info.plist b/FeatureFlags/2024/Info.plist
new file mode 100644
index 0000000..5c3e402
--- /dev/null
+++ b/FeatureFlags/2024/Info.plist
@@ -0,0 +1,55 @@
+
+
+
+
+ AvailableLibraries
+
+
+ LibraryIdentifier
+ macos-arm64e-arm64-x86_64
+ LibraryPath
+ FeatureFlags.framework
+ SupportedArchitectures
+
+ arm64e
+ arm64
+ x86_64
+
+ SupportedPlatform
+ macos
+
+
+ LibraryIdentifier
+ ios-arm64-arm64e
+ LibraryPath
+ FeatureFlags.framework
+ SupportedArchitectures
+
+ arm64
+ arm64e
+
+ SupportedPlatform
+ ios
+
+
+ LibraryIdentifier
+ ios-arm64-x86_64-simulator
+ LibraryPath
+ FeatureFlags.framework
+ SupportedArchitectures
+
+ arm64
+ x86_64
+
+ SupportedPlatform
+ ios
+ SupportedPlatformVariant
+ simulator
+
+
+ CFBundlePackageType
+ XFWK
+ XCFrameworkFormatVersion
+ 1.0
+
+
diff --git a/FeatureFlags/2024/Sources/Info.plist b/FeatureFlags/2024/Sources/Info.plist
new file mode 100644
index 0000000..9c78393
--- /dev/null
+++ b/FeatureFlags/2024/Sources/Info.plist
@@ -0,0 +1,16 @@
+
+
+
+
+ CFBundleExecutable
+ FeatureFlags
+ CFBundleIdentifier
+ com.apple.FeatureFlags
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundlePackageType
+ FMWK
+ CFBundleShortVersionString
+ 1.0.0
+
+
diff --git a/FeatureFlags/2024/Sources/Modules/FeatureFlags.swiftmodule/template.swiftinterface b/FeatureFlags/2024/Sources/Modules/FeatureFlags.swiftmodule/template.swiftinterface
new file mode 100644
index 0000000..6800816
--- /dev/null
+++ b/FeatureFlags/2024/Sources/Modules/FeatureFlags.swiftmodule/template.swiftinterface
@@ -0,0 +1,8 @@
+public import Swift
+
+public protocol FeatureFlagsKey {
+ var domain: Swift.StaticString { get }
+ var feature: Swift.StaticString { get }
+}
+
+public func isFeatureEnabled(_ key: any FeatureFlags.FeatureFlagsKey) -> Swift.Bool
diff --git a/FeatureFlags/2024/tbds/ios-arm64-arm64e/FeatureFlags.tbd b/FeatureFlags/2024/tbds/ios-arm64-arm64e/FeatureFlags.tbd
new file mode 100644
index 0000000..cb9e5d1
--- /dev/null
+++ b/FeatureFlags/2024/tbds/ios-arm64-arm64e/FeatureFlags.tbd
@@ -0,0 +1,45 @@
+{
+ "main_library": {
+ "current_versions": [
+ {
+ "version": "97"
+ }
+ ],
+ "exported_symbols": [
+ {
+ "data": {
+ "global": [
+ "_$s12FeatureFlags02isA7EnabledySbAA0aB3Key_pF",
+ "_$s12FeatureFlags0aB3KeyMp",
+ "_$s12FeatureFlags0aB3KeyP6domains12StaticStringVvgTj",
+ "_$s12FeatureFlags0aB3KeyP6domains12StaticStringVvgTq",
+ "_$s12FeatureFlags0aB3KeyP7features12StaticStringVvgTj",
+ "_$s12FeatureFlags0aB3KeyP7features12StaticStringVvgTq",
+ "_$s12FeatureFlags0aB3KeyTL"
+ ]
+ }
+ }
+ ],
+ "install_names": [
+ {
+ "name": "/System/Library/PrivateFrameworks/FeatureFlags.framework/FeatureFlags"
+ }
+ ],
+ "swift_abi": [
+ {
+ "abi": 7
+ }
+ ],
+ "target_info": [
+ {
+ "min_deployment": "18.0",
+ "target": "arm64-ios"
+ },
+ {
+ "min_deployment": "18.0",
+ "target": "arm64e-ios"
+ }
+ ]
+ },
+ "tapi_tbd_version": 5
+}
diff --git a/FeatureFlags/2024/tbds/ios-arm64-x86_64-simulator/FeatureFlags.tbd b/FeatureFlags/2024/tbds/ios-arm64-x86_64-simulator/FeatureFlags.tbd
new file mode 100644
index 0000000..5456c14
--- /dev/null
+++ b/FeatureFlags/2024/tbds/ios-arm64-x86_64-simulator/FeatureFlags.tbd
@@ -0,0 +1,45 @@
+{
+ "main_library": {
+ "current_versions": [
+ {
+ "version": "97"
+ }
+ ],
+ "exported_symbols": [
+ {
+ "data": {
+ "global": [
+ "_$s12FeatureFlags02isA7EnabledySbAA0aB3Key_pF",
+ "_$s12FeatureFlags0aB3KeyMp",
+ "_$s12FeatureFlags0aB3KeyP6domains12StaticStringVvgTj",
+ "_$s12FeatureFlags0aB3KeyP6domains12StaticStringVvgTq",
+ "_$s12FeatureFlags0aB3KeyP7features12StaticStringVvgTj",
+ "_$s12FeatureFlags0aB3KeyP7features12StaticStringVvgTq",
+ "_$s12FeatureFlags0aB3KeyTL"
+ ]
+ }
+ }
+ ],
+ "install_names": [
+ {
+ "name": "/System/Library/PrivateFrameworks/FeatureFlags.framework/FeatureFlags"
+ }
+ ],
+ "swift_abi": [
+ {
+ "abi": 7
+ }
+ ],
+ "target_info": [
+ {
+ "min_deployment": "18.5",
+ "target": "x86_64-ios-simulator"
+ },
+ {
+ "min_deployment": "18.5",
+ "target": "arm64-ios-simulator"
+ }
+ ]
+ },
+ "tapi_tbd_version": 5
+}
diff --git a/FeatureFlags/2024/tbds/macos-arm64e-arm64-x86_64/FeatureFlags.tbd b/FeatureFlags/2024/tbds/macos-arm64e-arm64-x86_64/FeatureFlags.tbd
new file mode 100644
index 0000000..3adeb80
--- /dev/null
+++ b/FeatureFlags/2024/tbds/macos-arm64e-arm64-x86_64/FeatureFlags.tbd
@@ -0,0 +1,15 @@
+--- !tapi-tbd
+tbd-version: 4
+targets: [ x86_64-macos, x86_64-maccatalyst, arm64-macos, arm64-maccatalyst,
+ arm64e-macos, arm64e-maccatalyst ]
+install-name: '/System/Library/PrivateFrameworks/FeatureFlags.framework/Versions/A/FeatureFlags'
+current-version: 97
+swift-abi-version: 7
+exports:
+ - targets: [ x86_64-macos, x86_64-maccatalyst, arm64-macos, arm64-maccatalyst,
+ arm64e-macos, arm64e-maccatalyst ]
+ symbols: [ '_$s12FeatureFlags02isA7EnabledySbAA0aB3Key_pF', '_$s12FeatureFlags0aB3KeyMp',
+ '_$s12FeatureFlags0aB3KeyP6domains12StaticStringVvgTj', '_$s12FeatureFlags0aB3KeyP6domains12StaticStringVvgTq',
+ '_$s12FeatureFlags0aB3KeyP7features12StaticStringVvgTj', '_$s12FeatureFlags0aB3KeyP7features12StaticStringVvgTq',
+ '_$s12FeatureFlags0aB3KeyTL' ]
+...
diff --git a/FeatureFlags/README.md b/FeatureFlags/README.md
new file mode 100644
index 0000000..5196c9a
--- /dev/null
+++ b/FeatureFlags/README.md
@@ -0,0 +1,52 @@
+# FeatureFlags
+
+Swift declarations and linker stubs for the system FeatureFlags framework.
+The xcframework contains no replacement implementation. Consumers link to the
+system framework through its absolute install name.
+
+## API
+
+```swift
+import FeatureFlags
+
+struct GestureContainerKey: FeatureFlagsKey {
+ var domain: StaticString { "SwiftUI" }
+ var feature: StaticString { "gestureContainer" }
+}
+
+let enabled = isFeatureEnabled(GestureContainerKey())
+```
+
+Add the `FeatureFlags` product from `DarwinPrivateFrameworks` to the consumer
+SwiftPM target. Keep the system domain and feature names when querying a system
+flag.
+
+## Sources
+
+- macOS stub: macOS 15.5 SDK in Xcode 16.4, FeatureFlags version 97.
+- Simulator stub: `tapi stubify` output from the iOS 18.5 Simulator runtime,
+ FeatureFlags version 97.
+- Device stub: the simulator export list with arm64/arm64e iOS targets, following
+ the existing SFSymbols device stub pattern. SwiftUICore 6.5.4 imports the same
+ protocol and function symbols.
+- Swift declarations: protocol requirements and function signature recovered
+ from these exports and SwiftUICore 6.5.4 conformances.
+
+## Supported platforms
+
+- macOS 15.0: arm64, arm64e, x86_64.
+- iOS 18.0: arm64, arm64e.
+- iOS Simulator 18.5: arm64, x86_64.
+
+Mac Catalyst, tvOS, watchOS, and visionOS slices are not included.
+
+## Update
+
+After editing `2024/Sources` or `2024/tbds`, run:
+
+```shell
+./FeatureFlags/update.sh
+```
+
+The update plugin and `Scripts/update_frameworks.sh all` also regenerate this
+framework.
diff --git a/FeatureFlags/reset.sh b/FeatureFlags/reset.sh
new file mode 100755
index 0000000..06f51da
--- /dev/null
+++ b/FeatureFlags/reset.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+VERSION=${DARWINPRIVATEFRAMEWORKS_TARGET_RELEASE:-2024}
+if [[ "$VERSION" != "2024" ]]; then
+ echo "FeatureFlags supports release 2024." >&2
+ exit 1
+fi
+rm -rf "$SCRIPT_DIR/$VERSION/FeatureFlags.xcframework"
diff --git a/FeatureFlags/update.sh b/FeatureFlags/update.sh
new file mode 100755
index 0000000..0e924d8
--- /dev/null
+++ b/FeatureFlags/update.sh
@@ -0,0 +1,69 @@
+#!/bin/bash
+
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+VERSION=${DARWINPRIVATEFRAMEWORKS_TARGET_RELEASE:-2024}
+if [[ "$VERSION" != "2024" ]]; then
+ echo "FeatureFlags supports release 2024." >&2
+ exit 1
+fi
+FRAMEWORK_ROOT="$SCRIPT_DIR/$VERSION"
+OUTPUT_ROOT="$FRAMEWORK_ROOT/FeatureFlags.xcframework"
+
+write_interface() {
+ local modules="$1"
+ local name="$2"
+ local target="$3"
+ local output="$modules/$name.swiftinterface"
+ cat > "$output" <> "$output"
+}
+
+generate_framework() {
+ local slice="$1"
+ local framework="$OUTPUT_ROOT/$slice/FeatureFlags.framework"
+ local contents="$framework"
+ if [[ "$slice" == macos-* ]]; then
+ contents="$framework/Versions/A"
+ mkdir -p "$contents/Resources"
+ cp "$FRAMEWORK_ROOT/Sources/Info.plist" "$contents/Resources/Info.plist"
+ ln -sfn A "$framework/Versions/Current"
+ ln -sfn Versions/Current/Modules "$framework/Modules"
+ ln -sfn Versions/Current/Resources "$framework/Resources"
+ ln -sfn Versions/Current/FeatureFlags.tbd "$framework/FeatureFlags.tbd"
+ else
+ mkdir -p "$contents"
+ cp "$FRAMEWORK_ROOT/Sources/Info.plist" "$contents/Info.plist"
+ fi
+ cp "$FRAMEWORK_ROOT/tbds/$slice/FeatureFlags.tbd" "$contents/FeatureFlags.tbd"
+ local modules="$contents/Modules/FeatureFlags.swiftmodule"
+ mkdir -p "$modules"
+ case "$slice" in
+ macos-*)
+ for arch in arm64 arm64e x86_64; do
+ write_interface "$modules" "$arch-apple-macos" "$arch-apple-macos15.0"
+ done
+ ;;
+ ios-arm64-arm64e)
+ for arch in arm64 arm64e; do
+ write_interface "$modules" "$arch-apple-ios" "$arch-apple-ios18.0"
+ done
+ ;;
+ ios-arm64-x86_64-simulator)
+ for arch in arm64 x86_64; do
+ write_interface "$modules" "$arch-apple-ios-simulator" "$arch-apple-ios18.5-simulator"
+ done
+ ;;
+ esac
+}
+
+mkdir -p "$OUTPUT_ROOT"
+cp "$FRAMEWORK_ROOT/Info.plist" "$OUTPUT_ROOT/Info.plist"
+generate_framework macos-arm64e-arm64-x86_64
+generate_framework ios-arm64-arm64e
+generate_framework ios-arm64-x86_64-simulator
diff --git a/Package.swift b/Package.swift
index a0e5b79..f46042a 100644
--- a/Package.swift
+++ b/Package.swift
@@ -157,6 +157,7 @@ var products: [PackageDescription.Product] = [
.library(name: "BacklightServices", targets: ["BacklightServices"]),
.library(name: "SFSymbols", targets: ["SFSymbols"]),
.library(name: "CoreSVG", targets: ["CoreSVG"]),
+ .library(name: "FeatureFlags", targets: ["FeatureFlags"]),
]
if releaseVersion >= 2025 {
@@ -185,6 +186,7 @@ let package = Package(
.binaryTarget(name: "BacklightServices", path: "BLS/2024/BacklightServices.xcframework"),
.binaryTarget(name: "SFSymbols", path: "SFSymbols/2024/SFSymbols.xcframework"),
.binaryTarget(name: "CoreSVG", path: "CoreSVG/2024/CoreSVG.xcframework"),
+ .binaryTarget(name: "FeatureFlags", path: "FeatureFlags/2024/FeatureFlags.xcframework"),
.binaryTarget(name: "Gestures", path: "GF/2025/Gestures.xcframework"),
.target(
name: "_GesturesDeviceSwiftShims",
diff --git a/Plugins/UpdateXCFrameworks/UpdateXCFrameworksCommand.swift b/Plugins/UpdateXCFrameworks/UpdateXCFrameworksCommand.swift
index c852877..37f8cfd 100644
--- a/Plugins/UpdateXCFrameworks/UpdateXCFrameworksCommand.swift
+++ b/Plugins/UpdateXCFrameworks/UpdateXCFrameworksCommand.swift
@@ -37,6 +37,8 @@ struct UpdateXCFrameworksCommand: CommandPlugin {
// CoreSVG
try run(context: context, command: "CoreSVG/reset.sh", environment: ["DARWINPRIVATEFRAMEWORKS_TARGET_RELEASE": "2024"])
try run(context: context, command: "CoreSVG/update.sh", environment: ["DARWINPRIVATEFRAMEWORKS_TARGET_RELEASE": "2024"])
+ // FeatureFlags
+ try run(context: context, command: "FeatureFlags/update.sh", environment: ["DARWINPRIVATEFRAMEWORKS_TARGET_RELEASE": "2024"])
#if compiler(>=6.2)
// Gestures
try run(context: context, command: "GF/reset.sh", environment: ["DARWINPRIVATEFRAMEWORKS_TARGET_RELEASE": "2025"])
diff --git a/README.md b/README.md
index 70c940f..3f0ebc1 100644
--- a/README.md
+++ b/README.md
@@ -8,8 +8,9 @@
|[](https://github.com/OpenSwiftUIProject/DarwinPrivateFrameworks/actions/workflows/bls_example.yml)|
|[](https://github.com/OpenSwiftUIProject/DarwinPrivateFrameworks/actions/workflows/gf_example.yml)|
|[](https://github.com/OpenSwiftUIProject/DarwinPrivateFrameworks/actions/workflows/sfsymbols_example.yml)|
+|[](https://github.com/OpenSwiftUIProject/DarwinPrivateFrameworks/actions/workflows/featureflags_example.yml)|
-This project contains private frameworks for Darwin platforms, including `AttributeGraph`, `RenderBox`, `CoreUI`, `BacklightServices`, `Gestures`, and `SFSymbols`.
+This project contains private frameworks for Darwin platforms, including `AttributeGraph`, `RenderBox`, `CoreUI`, `BacklightServices`, `Gestures`, `SFSymbols`, and `FeatureFlags`.
The frameworks are provided as xcframeworks available for macOS, iOS Simulator, iOS[^1], and visionOS Simulator platforms.
@@ -32,6 +33,7 @@ The frameworks are provided as xcframeworks available for macOS, iOS Simulator,
- `BLS/`: Contains the `BacklightServices` framework.
- `Examples/`: Contains example projects demonstrating usage of the private frameworks.
- `GF/`: Contains the `Gestures` framework.
+- `FeatureFlags/`: Contains the `FeatureFlags` Swift framework.
- `RB/`: Contains the `RenderBox` framework.
- `SFSymbols/`: Contains the `SFSymbols` framework.
- `Plugins/UpdateModule/`: Contains the `UpdateModule` plugin for updating the frameworks.
diff --git a/Scripts/update_frameworks.sh b/Scripts/update_frameworks.sh
index 904af85..8dc65cf 100755
--- a/Scripts/update_frameworks.sh
+++ b/Scripts/update_frameworks.sh
@@ -74,7 +74,7 @@ if [ $# -eq 0 ]; then
echo " $0 AttributeGraph RenderBox CoreUI SFSymbols"
echo " $0 all"
echo ""
- echo "Frameworks: AttributeGraph (or AG), RenderBox (or RB), CoreUI, SFSymbols"
+ echo "Frameworks: AttributeGraph (or AG), RenderBox (or RB), CoreUI, SFSymbols, FeatureFlags"
echo ""
echo "To specify version, set DARWINPRIVATEFRAMEWORKS_TARGET_RELEASE:"
echo " DARWINPRIVATEFRAMEWORKS_TARGET_RELEASE=2021 $0 all"
@@ -83,7 +83,7 @@ fi
# Check if "all" was specified
if [ "$1" = "all" ]; then
- frameworks=("AttributeGraph" "RenderBox" "CoreUI" "SFSymbols")
+ frameworks=("AttributeGraph" "RenderBox" "CoreUI" "SFSymbols" "FeatureFlags")
else
frameworks=("$@")
fi