Integration Guide
Package name (shown in Xcode): FBxSDK
Swift Package Registry identity: product.ios-sdk
Version: 1.0.0
Platform: iOS 17+
Xcode: 26+
Delivery: Swift Package via Swift Package Registry
1) Overview
FBxSDK provides a SwiftUI integration point and a small public API designed for straightforward embedding into an iOS application using:
- A SwiftUI view (
FBxView) that hosts the SDK’s rendering surface - A manager singleton (
FBxManager.shared) that provides configuration + lifecycle control (configure,start,stop,setFrame,restartFaceDetection) and emits events
High-level lifecycle:
- Configure (validates license online)
- Attach view (
FBxView) → SDK prepares and becomes ready - Explicitly start/stop the try-on session
2) Distribution & installation
FBxSDK is distributed via Swift Package Registry.
One-time registry setup and login
Configure the registry scope and login once on your machine :
swift package-registry set --global --scope product <https://fittingbox.jfrog.io/artifactory/api/swift/product.swift>
swift package-registry login \\
--username client-swift-sdk \\
--password '<PASSWORD>' \\
--no-confirm \\
<https://fittingbox.jfrog.io/artifactory/api/swift/product.swift>
Add package dependency
Add the package to your project using:
- Xcode → File → Add Package Dependencies…
- Package identity:
product.ios-sdk - Version: exact
1.0.0
Notes / Troubleshooting
- After setting the Swift Package Registry scope, it is recommended to restart Xcode, as it may not refresh registry sources until relaunch.
- In the Add Package Dependencies search, even if the full package identity (
product.ios-sdk) is typed in, Xcode can incorrectly show no packages found. Pressing enter usually resolves this issue, as it forces the lookup and the package should appear.
3) App-level requirements & constraints
Camera permission handling
Camera permission is intentionally treated as an application concern, as UX, timing, copy, and fallback flows tend to be product-specific.
The standard iOS camera usage string is expected in the host app’s Info.plist:
NSCameraUsageDescription
If camera permission is unavailable, start() fails with:
cameraPermissionNotGivencameraPermissionRestrictedcameraPermissionDenied
Full-screen mode
FBxSDK is designed and tested for full-screen usage. FBxView should occupy the full available screen and should not be embedded as a small partial view, because camera rendering and try-on alignment are optimized for a full-screen experience.
Embedded static resources
FBxSDK includes resource data embedded inside the SDK framework binary. These resources are not delivered as a visible resource bundle inside the .xcframework.
The embedded resource data is approximately 1.6 MB. On first preparation, or when the embedded resource version changes, the SDK extracts a managed copy into the host app container under Application Support and uses the extracted data folder internally. Because of this extracted copy, the resource storage impact is roughly doubled after first use, to around 3.2 MB.
The extracted files are SDK-managed implementation details. The host application should not modify, delete, or rely on the internal structure of this folder. If extraction fails, the SDK reports the failure through its normal error flow.
4) Integration model
FBxSDK follows a three-phase model: configure, attach/prepare, then run the session.
Phase A - Configure (explicit)
Call configure(_:) with FBxConfiguration that contains an apiKey and optional initialSku :
- Validates the license via network call
- Stores
apiKeyand optionalinitialSku - Starts preloading the initial frame data, if
initialSkuis provided - State transitions to
.configured(or.configurationFailed)
If initial frame preloading fails, the error is emitted through errors, but configuration can still complete successfully.
Phase B - Attach / prepare (automatic)
When FBxView is on-screen and has a non-trivial size:
- The SDK transitions
.configured → .preparing → .ready
Phase C - Run session (explicit)
start()starts the try-on session and renders the camera insideFBxView, transitions the state to.activestop()stops the session and returns the state to.readysetFrame(_:)can be called only when the session is.activerestartFaceDetection()can be called only when the session is.activeand should be called whenfaceDetectionStateis.failed
5) Public API surface
5.1 FBxView
FBxView is the SwiftUI entry point and rendering container.
- Should be full-screen
- When
FBxManager.shared.start()is called, the camera preview is rendered inside this view - When
FBxViewis attached and has a valid non-zero size, SDK preparation is triggered and state transitions to.preparing - When
FBxViewdisappears, the SDK detaches the rendering layer and returns to.configured, if configuration was previously successful
5.2 FBxManager
Singleton access:
FBxManager.shared
Primary methods:
configure(_ configuration: FBxConfiguration)- validates the license, stores theapiKeyand an optionalinitialSku, which is used as the initial frame when the try-on session starts (async, can throw)start()- starts the try-on session (async, can throw)stop()- stops the try-on session (async, can throw)setFrame(_ sku: String)- sets a selected frame by its SKU (async, can throw)restartFaceDetection()- restarts face detection when the session is active, should be called whenfaceDetectionStateis.failed(async, can throw)
Observability:
events- anAsyncStream<FBxEvent>(see below)errors- anAsyncStream<FBxError>(see below)state- currentFBxStatefaceDetectionState- currentFBxFaceDetectionState
5.3 FBxConfiguration
FBxConfiguration is a lightweight configuration value passed into FBxManager.shared.configure(_:).
It contains:
apiKey: String- requiredinitialSku: String?- optional, used as the initial frame when the session starts
6) State models
6.1 FBxState
FBxState reflects configuration, preparation, and session lifecycle:
unconfigured- no configuration provided yetconfiguring- validating/applying configurationconfigured- configured successfully, no view/session activeconfigurationFailed- configuration failed, must re-configurepreparing- preparing triggered byFBxViewattachmentpreparationFailed- preparation failed and SDK could not become.readyready- ready forstart()starting- start requested, session bootstrapping in progressactive- session is active (camera preview visible inFBxView)stopping- stop requested, session shutting down
State transitions are emitted via the event stream.
6.2 FBxFaceDetectionState
FBxFaceDetectionState reflects the face detection lifecycle:
uninitialized- face detection has not been initialized yetidle- face detection is initialized but not actively scanningscanning- face detection is actively looking for a facedetected- a face was successfully detected and is being trackedrecovery- face tracking was temporarily lost and the system is trying to recoverfailed- face detection failed and needs to be restarted withrestartFaceDetection()
Face detection state transitions are emitted via the event stream.
7) Async Streams
7.1 Events
events emits FBxEvent updates and supports multiple concurrent subscribers.
On subscription, the stream immediately emits:
.stateChanged(state).faceDetectionStateChanged(faceDetectionState)
In the current version, it contains the following events:
stateChanged(FBxState)frameLoaded(String)faceDetectionStateChanged(FBxFaceDetectionState)
7.2 Errors
errors emits FBxError updates and supports multiple concurrent subscribers. On subscription, errors emits the latest error if one exists, then future errors as they occur.
8) Errors
FBxError represents failures that can be thrown by the FBxSDK:
- Configuration
configurationNotSetconfigurationFailedlicenseForAPIKeyNotFoundapiKeyNotFoundinvalidAPIKeynoInternetConnection
- Lifecycle / ordering
invalidState(String)
- Frame loading
frameNotFound(String)
- Camera
cameraPermissionDeniedcameraPermissionRestrictedcameraPermissionNotGiven
- Generic
internalError(String)
9) Usage example
import SwiftUI
import FBxSDK
@main
struct FBxSDKTestApp: App {
var body: some Scene {
WindowGroup {
NavigationStack {
ContentView()
}
.task {
do {
try await FBxManager.shared.configure(
FBxConfiguration(apiKey: "123", initialSku: nil)
)
} catch {
print("configuration failed: \\(error)")
}
}
}
}
}
struct ContentView: View {
@State private var state: FBxState?
@State private var faceDetectionState: FBxFaceDetectionState?
var body: some View {
ZStack(alignment: .top) {
FBxView()
.ignoresSafeArea()
VStack(spacing: 16) {
Text("SDK State: \\(state?.description, default: "nil")")
.font(.footnote)
HStack(spacing: 12) {
Button("Start") {
Task {
do { try await FBxManager.shared.start() }
catch { print("start failed: \\(error)") }
}
}
Button("Stop") {
Task {
do { try await FBxManager.shared.stop() }
catch { print("stop failed: \\(error)") }
}
}
}
Button("Set Frame A") {
Task {
do { try await FBxManager.shared.setFrame("A") }
catch { print("setFrame failed: \\(error)") }
}
}
if faceDetectionState == .failed {
Button("Restart face detection") {
Task {
do { try await FBxManager.shared.restartFaceDetection() }
catch { print("restartFaceDetectionFailed: \\(error)") }
}
}
}
}
.padding()
}
.task {
for await event in FBxManager.shared.events {
switch event {
case .stateChanged(let newState):
state = newState
case .frameLoaded(let sku):
print("successfully loaded frame \\(sku)")
case .faceDetectionStateChanged(let newFaceDetectionState):
faceDetectionState = newFaceDetectionState
@unknown default:
break
}
}
}
.task {
for await error in FBxManager.shared.errors {
print("error occurred: \\(error)")
}
}
}
}
10) Operational notes
configure(_:)must complete successfully before starting a sessionstart()requiresstate == .readysetFrame(_:)requiresstate == .activerestartFaceDetection()requiresstate == .activestop()can be called when the SDK is.activeor.starting
start()/stop() can be called repeatedly (e.g. start → stop → start) as long as each start() happens when the SDK is back in .ready state.
11) Integration checklist
- Xcode 26+
- Swift Package Registry scope configured
- Package added
NSCameraUsageDescriptionincluded inInfo.plist- SDK-managed resources can be extracted into Application Support
- Internet access available
- SDK configured via
configure(_:) FBxViewplaced in the UI hierarchy- Application requests camera permission before calling
start() - Application observes
eventsfor UI and troubleshooting - Application observes
errorsfor troubleshooting - Application observes
faceDetectionStateand callsrestartFaceDetection()when it reaches.failedstate - Session controlled via
start()/stop()