Skip to content
English
  • There are no suggestions because the search field is empty.

Integration Guide

Package name (shown in Xcode): FBxSDK

Swift Package Registry identity: product.ios-sdk

Version: 0.4.1

Platform: iOS 17+

Xcode: 26+

Orientation: Portrait only

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:

  1. Configure (validates license online)
  2. Attach view (FBxView) → SDK prepares and becomes ready
  3. 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 0.4.1

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:

  • cameraPermissionNotGiven
  • cameraPermissionRestricted
  • cameraPermissionDenied

Portrait mode

FBxSDK is designed for portrait usage only.


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 apiKey and optional initialSku
  • Starts preloading the initial frame data, if initialSku is 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 inside FBxView , transitions the state to .active
  • stop() stops the session and returns the state to .ready
  • setFrame(_:) can be called only when the session is .active
  • restartFaceDetection() can be called only when the session is .active and should be called when faceDetectionState is .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 FBxView is attached and has a valid non-zero size, SDK preparation is triggered and state transitions to .preparing
  • When FBxView disappears, 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 the apiKey and an optional initialSku , 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 when faceDetectionState is .failed (async, can throw)

Observability:

  • events - an AsyncStream<FBxEvent> (see below)
  • errors - an AsyncStream<FBxError> (see below)
  • state - current FBxState
  • faceDetectionState - current FBxFaceDetectionState

5.3 FBxConfiguration

FBxConfiguration is a lightweight configuration value passed into FBxManager.shared.configure(_:).

It contains:

  • apiKey: String - required
  • initialSku: 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 yet
  • configuring - validating/applying configuration
  • configured - configured successfully, no view/session active
  • configurationFailed - configuration failed, must re-configure
  • preparing - preparing triggered by FBxView attachment
  • preparationFailed - preparation failed and SDK could not become .ready
  • ready - ready for start()
  • starting - start requested, session bootstrapping in progress
  • active - session is active (camera preview visible in FBxView)
  • 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 yet
  • idle - face detection is initialized but not actively scanning
  • scanning - face detection is actively looking for a face
  • detected - a face was successfully detected and is being tracked
  • recovery - face tracking was temporarily lost and the system is trying to recover
  • failed - face detection failed and needs to be restarted with restartFaceDetection()

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
    • configurationNotSet
    • configurationFailed
    • licenseForAPIKeyNotFound
    • apiKeyNotFound
    • invalidAPIKey
    • noInternetConnection
  • Lifecycle / ordering
    • invalidState(String)
  • Frame loading
    • frameNotFound(String)
  • Camera
    • cameraPermissionDenied
    • cameraPermissionRestricted
    • cameraPermissionNotGiven
  • 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 session
  • start() requires state == .ready
  • setFrame(_:) requires state == .active
  • restartFaceDetection() requires state == .active
  • stop() can be called when the SDK is .active or .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
  • NSCameraUsageDescription included in Info.plist
  • Internet access available
  • SDK configured via configure(_:)
  • Hosting screen locked to portrait
  • FBxView placed in the UI hierarchy
  • Application requests camera permission before calling start()
  • Application observes events for UI and troubleshooting
  • Application observes errors for troubleshooting
  • Application observes faceDetectionState and calls restartFaceDetection() when it reaches .failed state
  • Session controlled via start() / stop()

12) Known issues

The following limitations are known in version 0.4.1 . They are currently being in addressed and are expected to be resolved in the next release.

Main-thread work during session runtime

Some runtime work is currently still executed on the main thread.

This includes camera grabbing, which means that when the camera frame rate is low, the rest of the session may also be impacted.

As a result, the host app may feel less responsive during an active try-on session, particularly on slower devices and under low frame-rate conditions.

Landscape orientation is not supported

FBxSDK currently supports portrait orientation only.

When the device is rotated to landscape, face detection and rendering behavior may become inconsistent. In some cases:

  • face detection may fail or become unstable
  • the rendered glasses may appear at an incorrect size or position

Re-entering the SDK screen after navigation

In some navigation flows, especially when FBxView is nested inside parent/child view hierarchies, leaving the SDK screen and entering it again does not fully reset the SDK session state.

A typical affected flow is:

  1. User opens the screen containing FBxView
  2. Session starts and stops correctly
  3. User navigates away from the screen
  4. User navigates back to the same screen
  5. Starting a new session fails and/or produces internal errors

This is caused by some session resources not being fully released when the SDK view disappears.