-
Notifications
You must be signed in to change notification settings - Fork 0
iOS Usage
Preview status. The iOS surface (SKIE bridge, DCE xcconfig) is Preview in v1.0.0. The public API may change in minor releases without a major version bump.
The Package.swift manifest is updated by CI in a commit after the release tag, so resolving the Swift package by the 1.0.0 tag (.package(url: ..., from: "1.0.0")) currently fetches the previous XCFramework. For v1.0.0, consume the iOS XCFramework via the GitHub Release asset directly (download FeaturedCore.xcframework.zip from the v1.0.0 release) or pin the Swift package to the specific commit that carries the updated Package.swift, rather than the tag. This will be addressed in a future iOS-stable release.
Featured exposes its Kotlin API to Swift via SKIE. No Kotlin toolchain is needed in Xcode — the framework is built by the KMP Gradle build and consumed as a prebuilt XCFramework or Swift Package.
Import the module:
import FeaturedCoreFeaturedCore is the Swift product name. CoreConfigParam is the Kotlin ConfigParam<T> type as seen from Swift.
Call initialize() before serving any screen, then trigger a background fetch:
@MainActor
class AppState: ObservableObject {
let configValues: ConfigValues
init() {
configValues = ConfigValues(
localProvider: nil,
remoteProvider: nil,
onProviderError: { error in print("Featured error: \(error)") }
)
}
func setup() async {
do {
try await configValues.initialize()
try await configValues.fetch()
} catch {
print("Featured setup error: \(error)")
}
}
}Pass provider instances to localProvider and remoteProvider as needed. At least one must be non-nil.
let configValue = try await configValues.getValue(param: FeatureFlags.shared.newCheckout)
let isEnabled: Bool = configValue.valueFeatureFlags.shared.newCheckout is a CoreConfigParam<KotlinBoolean> — the Kotlin-generated ConfigParam accessed through the Swift wrapper your team writes (see Declaring Flags).
SKIE bridges the Kotlin Flow as an AsyncStream:
for await configValue in configValues.observe(param: FeatureFlags.shared.newCheckout) {
updateUI(configValue.value)
}Use this inside a Task tied to your view's lifetime:
.task {
for await configValue in configValues.observe(param: FeatureFlags.shared.newCheckout) {
isNewCheckoutEnabled = configValue.value
}
}Build a Combine publisher on top of AsyncStream:
import Combine
class CheckoutViewModel: ObservableObject {
@Published var isNewCheckoutEnabled: Bool = false
private let configValues: ConfigValues
init(configValues: ConfigValues) {
self.configValues = configValues
}
func startObserving() {
Task {
for await configValue in configValues.observe(param: FeatureFlags.shared.newCheckout) {
await MainActor.run {
self.isNewCheckoutEnabled = configValue.value
}
}
}
}
}If your Swift wrapper exposes a publisher(for:) method:
featureFlags.publisher(for: newCheckoutFlag)
.receive(on: DispatchQueue.main)
.sink { isEnabled in updateUI(isEnabled) }
.store(in: &cancellables)struct CheckoutView: View {
@StateObject private var viewModel: CheckoutViewModel
var body: some View {
Group {
if viewModel.isNewCheckoutEnabled {
NewCheckoutFlow()
} else {
LegacyCheckoutFlow()
}
}
.onAppear { viewModel.startObserving() }
}
}For release builds, Featured can physically strip code behind disabled flags at compile time. A flag declared with default = false in the KMP module generates an xcconfig condition DISABLE_<FLAG_KEY> that feeds into Xcode as a Swift compilation condition. See iOS — xcconfig DCE for the setup procedure.