A Swift feature flags library that supports remote configuration, version control, and app type restrictions. Built with SwiftUI support and compatible with iOS/macOS/tvOS.
- Remote configuration via JSON
- Version and build number gating
- App type restrictions (Standard/Lite/App Store variants)
- SwiftUI integration with
@StateObjectand environment support - Cached feature states for performance
- Thread-safe updates
- Platform agnostic (iOS, macOS, tvOS, etc.)
- Comprehensive testing support
Add the following to your Package.swift file:
dependencies: [
.package(url: "https://github.com/yourusername/PVFeatureFlags.git", from: "1.0.0")
]Or add it directly in Xcode:
- File > Add Packages
- Enter the repository URL
- Click "Add Package"
Create a JSON file with your feature flags configuration:
{
"features": {
"inAppFreeROMs": {
"enabled": true,
"minVersion": "1.0.0",
"minBuildNumber": "100",
"allowedAppTypes": ["standard", "standard.appstore"],
"description": "Allows downloading free ROMs directly in the app"
}
}
}Add the PVAppType key to your Info.plist with one of these values:
standard- Standard non-App Store versionlite- Lite non-App Store versionstandard.appstore- Standard App Store versionlite.appstore- Lite App Store version
<key>PVAppType</key>
<string>standard</string>import PVFeatureFlags
// Check if a feature is enabled
if PVFeatureFlagsManager.shared.inAppFreeROMs {
// Feature is enabled
}
// Load remote configuration
Task {
try? await PVFeatureFlagsManager.shared.loadConfiguration(
from: URL(string: "https://your-domain.com/features.json")!
)
}struct ContentView: View {
@StateObject private var featureFlags = PVFeatureFlagsManager.shared
var body: some View {
if featureFlags.inAppFreeROMs {
Text("Free ROMs feature is enabled!")
}
}
}// In your App file
@main
struct MyApp: App {
@StateObject private var featureFlags = PVFeatureFlagsManager.shared
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(featureFlags)
.task {
try? await featureFlags.loadConfiguration(
from: URL(string: "https://your-domain.com/features.json")!
)
}
}
}
}
// In your views
struct ContentView: View {
@Environment(\.featureFlags) var featureFlags
var body: some View {
if featureFlags.inAppFreeROMs {
Text("Free ROMs feature is enabled!")
}
}
}{
"features": {
"featureKey": {
"enabled": true, // Required: Base enable/disable
"minVersion": "1.0.0", // Optional: Minimum app version
"minBuildNumber": "100", // Optional: Minimum build number
"allowedAppTypes": ["standard"], // Optional: Allowed app types
"description": "Feature description" // Optional: Feature description
}
}
}The library supports four app types:
standard: Regular non-App Store versionlite: Lite non-App Store versionstandard.appstore: Regular App Store versionlite.appstore: Lite App Store version
You can check app type properties:
let appType = PVAppType.standard
appType.isAppStore // false
appType.isLite // falselet customFlags = PVFeatureFlags(
appType: .standard,
buildNumber: "101",
appVersion: "1.1.0"
)
let manager = PVFeatureFlagsManager(featureFlags: customFlags)// Check any feature by key
if PVFeatureFlagsManager.shared.isEnabled("customFeature") {
// Feature is enabled
}The library includes testing-specific APIs to help with unit testing:
// Create a feature flags instance with pre-loaded configuration
let testFlags = PVFeatureFlags(
configuration: myTestConfig,
appType: .standard,
buildNumber: "101",
appVersion: "1.1.0"
)
// Or set configuration after initialization
let flags = PVFeatureFlags(appType: .standard)
flags.setConfiguration(myTestConfig)Note: These testing APIs are marked as internal and are only available when importing the module with @testable.
- Swift 6.0+
- iOS 16.0+ / macOS 13.0+ / tvOS 16.0+ / watchOS 9.0+ / visionOS 1.0+
- Mac Catalyst 16.0+
The library is designed to be thread-safe:
- All feature flag operations are actor-isolated
- SwiftUI integration is main-actor bound
- Configuration updates are atomic
This library is released under the MIT license. See LICENSE for details.