> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ones1ght.com/llms.txt
> Use this file to discover all available pages before exploring further.

# iOS Setup Guide

## System requirements

| Item | Requirement |
| - | - |
| OS | iOS 27 or later (minimum app deployment target is iOS 18) |
| Supported devices | iPhone 12 or later with a UWB chip (iPhone SE, iPad and Apple Watch are not supported) |
| Development environment | Xcode 27 or later |
| Language | Swift 5 or later · Objective-C ([via bridge](/en/developers/sdk/reference/ios#objective-c-bridge)) |
| Package manager | Swift Package Manager |

On devices that cannot receive positioning data, the SDK stops itself and does not affect the rest of your app.

## Installing the SDK

**Step 1**

In Xcode, choose **\[File] → \[Add Package Dependencies…]**.

**Step 2**

Enter the URL below in the search field at the top left.

```text theme={null}
https://github.com/onecheck-inc/OneS1ght-iOS-SDK
```

**Step 3**

Set **Dependency Rule** to `Up to Next Major Version` and the value to `0.2.2`.

**Step 4**

Click **\[Add Package]** to add the `OneS1ght` library to your app target.

## iOS permissions

Add all five usage descriptions below to `Info.plist`. None of them can be left out.

| Key | Permission | Purpose |
| - | - | - |
| `NSBluetoothAlwaysUsageDescription` | Bluetooth | Receiving locator BLE signals |
| `NSLocationWhenInUseUsageDescription` | Location | Determining the locator's location |
| `NSLocationAlwaysAndWhenInUseUsageDescription` | Location (Always) | Detecting the floor (required for BLE floor detection on iOS 27.2 and later) |
| `NSLocationTemporaryUsageDescriptionDictionary` | Precise location | Computing the precise indoor position The key inside must be `Positioning` |
| `NSNearbyInteractionUsageDescription` | Nearby Interaction | Precise positioning of the user |

Add them to the list in the **\[Info]** tab of your app target in Xcode.

**1. Four String keys**

Hover over a row, click the **\[+]** that appears, type the key name in Key and the text in Value. Type is String.

**2. One Dictionary key**

`NSLocationTemporaryUsageDescriptionDictionary` has two levels.

1. **\[+]** → type the key name in Key → change Type to **Dictionary** (leave Value empty).
2. Expand the **▸** on the left of the row, then click **\[+]** on that row → Key `Positioning`, Type String, and the text in Value.

**3. Check**

You are done when all five entries appear in the list. It is fine if the section header reads **Custom macOS Application Target Properties**.

For Value you can use the `<string>` values below as they are. To write to the file directly instead of using the Xcode UI, see the [Appendix](#appendix).

```xml Info.plist theme={null}
<key>NSBluetoothAlwaysUsageDescription</key>
<string>Used to find nearby positioning devices.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Used to determine your location inside the venue.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Used on iOS 27.2 and later to find the floor you are on.</string>
<key>NSLocationTemporaryUsageDescriptionDictionary</key>
<dict>
    <key>Positioning</key>
    <string>Used to compute your precise indoor position.</string>
</dict>
<key>NSNearbyInteractionUsageDescription</key>
<string>Used for precise UWB positioning.</string>
```

## Initializing the SDK

The SDK must be initialized before its internal engine can run.

| Function · Property | Description | Returns |
| - | - | - |
| `initialize(sdkKey:)` | Validates the key and fetches the configuration. Once at app launch | None |
| `isInitialized` | Whether initialization succeeded | `Bool` |
| `sdkVersion` | SDK version | `String` (e.g. `"0.2.3"`) |

The Objective-C bridge exposes methods with the same names and returns results through a completion block. \

Register bridge callbacks (`onPosition`, `onZoneEnter`, `onFloorDetected`, `onConfigChanged`, `onStopped`, etc.) only after `initialize` succeeds. Registering earlier has no effect (`onDebugLog` is the exception).

```swift Swift icon="swift" theme={null}
import OneS1ght

#if DEBUG
let sdkKey = "YOUR_DEVELOPMENT_API_KEY" // for development (test) builds
#else
let sdkKey = "YOUR_PRODUCTION_API_KEY"  // for production builds
#endif
try await OneS1ght.initialize(sdkKey: sdkKey)
```

```objc Objective-C icon="apple" theme={null}
#import "MyApp-Swift.h"   // MyApp = Product Module Name. Generated after you add the bridge file and build once.

#ifdef DEBUG
NSString *sdkKey = @"YOUR_DEVELOPMENT_API_KEY"; // for development (test) builds
#else
NSString *sdkKey = @"YOUR_PRODUCTION_API_KEY";  // for production builds
#endif
[OneS1ghtBridge initializeWithSdkKey:sdkKey completion:^(NSError *error) {
    if (error) { return; }   // handle failure
}];
```

## Profiles

Each user (account or device) is tracked as a **profile**. \

Profile IDs are unique and cannot be recovered once lost, so store them carefully.

| Function · Property | Description | Returns |
| - | - | - |
| `createProfile(_:)` | Creates a profile from attributes | `String` (profile ID) |
| `identify(profileId:)` | Links this device's positioning to the profile.  Pass `nil` to unlink | None |
| `fetchProfile(_:)` | Fetches attributes by profile ID | `[String: String]` |
| `replaceProfile(_:attributes:)` | Replaces all attributes | None |
| `deleteProfile(_:)` | Deletes the profile | None |

### Creating a profile

Creating a profile returns its profile ID. Attributes are used as segments in reports and metrics, and there are no restrictions on the key-value pairs.\

Store the returned ID in your app (or on your server) and link it with `identify` before positioning on every launch.

> [!WARNING]
>
> Do not put sensitive data such as names, phone numbers or member IDs in profile attributes.\\
>
> Use only non-identifying values such as an age band (`"20s"`).

```swift Swift icon="swift" theme={null}
let profileId = try await OneS1ght.createProfile(["gender": "F", "ageBand": "20s"])   // create a profile → returns the profile ID
save(profileId)                                                                     // store in the app or on your server

OneS1ght.identify(profileId: savedProfileId)   // link before positioning on every launch; nil on logout
```

```objc Objective-C icon="apple" theme={null}
[OneS1ghtBridge createProfile:@{ @"gender": @"F", @"ageBand": @"20s" }                 // create a profile → returns the profile ID
                    completion:^(NSString *profileId, NSError *error) {
    if (!error) { [self save:profileId]; }                                          // store in the app or on your server
}];

[OneS1ghtBridge identifyWithProfileId:savedProfileId];   // link before positioning on every launch; nil on logout
```

### Fetching a profile

Fetches the personalization attributes stored for a profile ID.

```swift Swift icon="swift" theme={null}
let attributes = try await OneS1ght.fetchProfile(profileId)   // ["gender": "F", "ageBand": "20s"]
```

```objc Objective-C icon="apple" theme={null}
[OneS1ghtBridge fetchProfile:profileId completion:^(NSDictionary *attributes, NSError *error) {
    if (error) { return; }   // unknown ID
}];
```

### Updating a profile

Personalization attributes are **replaced as a whole**. The previous values are deleted and cannot be restored.

```swift Swift icon="swift" theme={null}
try await OneS1ght.replaceProfile(profileId, attributes: ["gender": "F", "ageBand": "30s"])   // replace all attributes
```

```objc Objective-C icon="apple" theme={null}
[OneS1ghtBridge replaceProfile:profileId attributes:@{ @"gender": @"F", @"ageBand": @"30s" }   // replace all attributes
                    completion:^(NSError *error) { }];
```

### Deleting a profile

Deletes the profile's personalization attributes. Deleted attributes cannot be restored.

```swift Swift icon="swift" theme={null}
try await OneS1ght.deleteProfile(profileId)
```

```objc Objective-C icon="apple" theme={null}
[OneS1ghtBridge deleteProfile:profileId completion:^(NSError *error) { }];
```

## Selecting a building and floor

Selecting a floor is optional. Without it, the positioning engine finds the floor from the locators' BLE signals and still delivers coordinates. \

To receive zone events, however, you must set the floor (see [Zone events](#zone-events)).

| Function · Property | Description | Returns |
| - | - | - |
| `floorSession()` | Positioning session | `FloorSession` |
| `session.onFloorDetected` | Called when the engine finds a floor.  `nil` when the floor is lost | `(String?)` (floor ID) |
| `buildings()` | Buildings registered in the console | `[Building]`  `id`: building ID  `name`: building name  `floorCount`: number of floors |
| `floors(buildingId:)` | Floors of a building (without floor plan image) | `[Floor]` |
| `floor(buildingId:floorId:)` | One floor (with floor plan image) | `Floor` |
| `setFloorMap(_:buildingId:)` | Sets the floor  `nil` to clear | None |
| `session.floor` | Currently set floor | `Floor?` |

### Selecting from BLE

When the SDK's positioning engine finds a floor from locator BLE signals, the floor ID arrives in `onFloorDetected`. \

`nil` arrives when the floor is lost.

```swift Swift icon="swift" theme={null}
let session = try OneS1ght.floorSession()   // get the positioning session
session.onFloorDetected = { floorId in      // the engine passes the floor ID when it finds a floor
    guard let floorId else { return }
    Task {
        let floor = try await OneS1ght.floor(buildingId: buildingId, floorId: floorId)   // fetch the floor
        try await OneS1ght.setFloorMap(floor, buildingId: buildingId)                   // set the floor
    }
}
```

```objc Objective-C icon="apple" theme={null}
[OneS1ghtBridge onFloorDetected:^(NSString *floorId) {   // the engine passes the floor ID when it finds a floor
    if (!floorId) { return; }
    [OneS1ghtBridge setFloorMapWithBuildingId:buildingId floorId:floorId completion:^(NSError *error) { }];   // set the floor
}];
```

### Selecting manually

Set the building and floor yourself when the user picks the floor, or when you want to draw the map before positioning starts.

```swift Swift icon="swift" theme={null}
let buildings = try await OneS1ght.buildings()                            // buildings registered in the console
let floors    = try await OneS1ght.floors(buildingId: buildings[0].id)   // floors of the building

try await OneS1ght.setFloorMap(floors[0], buildingId: buildings[0].id)   // set the floor
try await OneS1ght.setFloorMap(nil)                                      // clear the floor
```

```objc Objective-C icon="apple" theme={null}
[OneS1ghtBridge buildings:^(NSArray<NSDictionary *> *buildings, NSError *error) {                 // buildings registered in the console
    NSString *buildingId = buildings.firstObject[@"id"];
    [OneS1ghtBridge floorsWithBuildingId:buildingId completion:^(NSArray<NSDictionary *> *floors, NSError *error) {   // floors of the building
        [OneS1ghtBridge setFloorMapWithBuildingId:buildingId floorId:floors.firstObject[@"id"]
                                       completion:^(NSError *error) { }];   // set the floor
    }];
}];
[OneS1ghtBridge setFloorMapWithBuildingId:nil floorId:nil completion:^(NSError *error) { }];   // clear the floor
```

## Receiving live positions

Get a positioning session with `floorSession()`, start it with `begin()` and stop it with `end()`. \

Positions arrive in `onPosition` as coordinates in meters, at the rate the engine produces them. \

Only the coordinates uploaded to the server are downsampled to the console-configured rate (4 per second by default).

| Situation | What to do |
| - | - |
| App goes to the background | Nothing — the SDK stops positioning and restarts it automatically when the app returns to the foreground. |
| User leaves the screen briefly | Stop with `pause()` and continue with `resume()`. The engine stays on, so positioning picks up right away. |
| Stopping positioning for good | `end()`. The engine shuts down too, so the next `begin()` searches for locators from scratch. |

| Function · Property | Description | Returns |
| - | - | - |
| `session.onPosition` | Live coordinates | `(Coordinates)`  `x` · `y`: meters on the floor plan  `z`: height |
| `session.begin()` | Starts positioning | None |
| `session.end()` | Stops positioning and uploads the remaining coordinates | None |
| `session.pause()` / `resume()` | Pause / resume | None |
| `session.isRunning` / `isPaused` | Whether positioning is running / paused | `Bool` |

```swift Swift icon="swift" theme={null}
let session = try OneS1ght.floorSession()
session.onPosition = { coord in updateMyLocationMarker(x: coord.x, y: coord.y) }   // coord.z: height

try await session.begin()   // start positioning
await session.end()         // stop positioning and upload the remaining coordinates
```

```objc Objective-C icon="apple" theme={null}
[OneS1ghtBridge onPosition:^(double x, double y, double z) { [self updateMyLocationMarkerX:x y:y]; }];

[OneS1ghtBridge beginWithCompletion:^(NSError *error) { }];   // start positioning
[OneS1ghtBridge endWithCompletion:^{ }];                       // stop positioning and upload the remaining coordinates
```

## Zone events

Receive enter, exit and dwell events for the zones drawn in the console's [Space Management](/en/console/areas). Detection happens on the device, so events arrive immediately. \

Campaigns attached to a zone (coupons, signage, etc.) are matched by the server and delivered through `onTriggers`. \

The zone list comes from the floor set with `setFloorMap`. Without a floor, the zone list is empty, so `onZoneEnter` / `onZoneExit` never fire and `E3009` is logged.

| Function · Property | Description | Returns |
| - | - | - |
| `session.onZoneEnter` / `onZoneExit` | Zone entered / exited | `(Zone)`  `id`: zone ID  `name`: zone name  `polygon`: zone shape (list of vertices)  `dwellSeconds`: dwell threshold (seconds) |
| `session.onZoneDwell` | Dwelling in a zone  Once per visit when `dwellSeconds` is reached | `(Zone, TimeInterval)`  zone, dwell time (seconds) |
| `session.onTriggers` | Personalized actions matched by the server | `(String, [Trigger])`  zone ID, list of triggers  (`triggerId`: trigger ID  `type`: type — `signage` · `coupon` · `tracking` · `merch` · `generic`  `payload`: extra data per type) |
| `session.onConfigChanged` | Zone settings changed in the console | `(ConfigChange)`  `.zonesChanged`: zones changed  `.planChanged`: floor plan changed  `.rulesChanged`: campaigns changed  `.sdkConfigChanged`: SDK remote config changed  `.resyncNeeded`: refetch everything (after a reconnect, or when events may have been missed) |
| `refreshZones()` | Refreshes zone data | `[Zone]` |

```swift Swift icon="swift" theme={null}
session.onZoneEnter = { zone in showBanner("Entered: \(zone.name)") }
session.onZoneExit  = { zone in hideBanner() }
session.onZoneDwell = { zone, seconds in showBanner("Dwell: \(zone.name) — \(Int(seconds))s") }
session.onTriggers  = { zoneId, triggers in triggers.forEach(handle) }   // type: signage · coupon · tracking · merch · generic
```

```objc Objective-C icon="apple" theme={null}
[OneS1ghtBridge onZoneEnter:^(NSDictionary *zone) { [self showBanner:zone[@"name"]]; }];
[OneS1ghtBridge onZoneExit:^(NSDictionary *zone)  { [self hideBanner]; }];
[OneS1ghtBridge onZoneDwell:^(NSDictionary *zone, double seconds) { [self showDwell:zone[@"name"] seconds:seconds]; }];
[OneS1ghtBridge onTriggers:^(NSString *zoneId, NSArray<NSDictionary *> *triggers) {
    for (NSDictionary *trigger in triggers) { [self handle:trigger]; }   // triggerId · type · payload
}];
```

### Refreshing zone data

`onConfigChanged` is called when zone data changes in the console. The SDK does not throttle these calls. \

Each zone reload restarts enter/exit detection from scratch, so collapse bursts in your app (about 1 second) and handle them once.

```swift Swift icon="swift" theme={null}
var refreshTask: Task<Void, Never>?
session.onConfigChanged = { change in
    switch change {
    case .zonesChanged, .resyncNeeded:
        refreshTask?.cancel()                             // only the last one in a burst
        refreshTask = Task {
            try? await Task.sleep(for: .seconds(1))
            guard !Task.isCancelled else { return }
            _ = await OneS1ght.refreshZones()
        }
    case .planChanged:                 reloadFloorPlan()   // floor plan changed
    default:                           break
    }
}
```

```objc Objective-C icon="apple" theme={null}
[OneS1ghtBridge onConfigChanged:^(NSString *kind, NSString *targetId) {
    if ([kind isEqualToString:@"zonesChanged"] || [kind isEqualToString:@"resyncNeeded"]) {
        [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(reloadZones) object:nil];
        [self performSelector:@selector(reloadZones) withObject:nil afterDelay:1.0];   // collapse for 1 s — reloadZones calls refreshZones:
    } else if ([kind isEqualToString:@"planChanged"]) {
        [self reloadFloorPlan];   // floor plan changed
    }
}];
```

## Displaying the floor plan

You can display the floor plan the locators are installed on, together with the user's current position. \

If no floor plan is set, the background is shown as a grid.

| Function · Property | Description | Returns |
| - | - | - |
| `floor(buildingId:floorId:)` | Floor details | `Floor` `image: Data?`: floor plan image `hasPlan`: whether a floor plan is registered `originX`: floor plan origin X (meters) `originY`: floor plan origin Y (meters) `widthM`: width (meters) `heightM`: height (meters)  `minX`: minimum X  `minY`: minimum Y `maxX`: maximum X `maxY`: maximum Y |
| `locators(buildingId:floorId:)` | Locators on the floor | `FloorLocators` `locators`: locator data (`address`: last 2 bytes of the UWB MAC as `Int`,  `x` · `y` · `z`: locator coordinates) `sessionId`: UWB session ID `positioningReady`: whether positioning is possible |

```swift Swift icon="swift" theme={null}
let floor = try await OneS1ght.floor(buildingId: buildingId, floorId: floorId)
planView.image = floor.image.flatMap(UIImage.init(data:))
setBounds(minX: floor.minX, minY: floor.minY, maxX: floor.maxX, maxY: floor.maxY)
```

```objc Objective-C icon="apple" theme={null}
[OneS1ghtBridge floorWithBuildingId:buildingId floorId:floorId completion:^(NSDictionary *floor, NSError *error) {
    self.planView.image = floor[@"image"] ? [UIImage imageWithData:floor[@"image"]] : nil;
    // bounds: originX · originY · widthM · heightM (meters)
}];
```

## Other options

| Function · Property | Description | Returns |
| - | - | - |
| `uploadPendingPositions()` | Uploads the coordinates buffered in the app right away | None |
| `discardPendingPositions()` | Discards the coordinates buffered in the app | None |
| `reset()` | Discards the session (call `initialize` again afterwards) | None |
| `session.onStopped` | Session stopped | `(StopReason)`: why the session stopped  `.ended`: ended normally  `.engineFailed`: engine failure |
| `OneS1ght.onDebugLog` | SDK debugging hook | `(LogLevel, String)` log output |

### Controlling data upload

Coordinates are uploaded automatically **when 300 have been buffered**, and **every 60 seconds** from `begin()` (a 300-point upload does not restart the 60-second timer). \

Remaining coordinates are also uploaded when the app enters the background and on `end()`. If the app is force-quit, buffered coordinates are discarded.

```swift Swift icon="swift" theme={null}
await OneS1ght.uploadPendingPositions()   // upload the buffered coordinates now
OneS1ght.discardPendingPositions()        // discard without uploading
```

```objc Objective-C icon="apple" theme={null}
[OneS1ghtBridge uploadPendingPositions:^{ }];   // upload the buffered coordinates now
[OneS1ghtBridge discardPendingPositions];       // discard without uploading
```

### Resetting the session

Stops positioning and discards the session. The stored key is cleared too, so APIs throw `notInitialized` until you call `initialize` again. \

Use it to switch to another key without rebuilding the app.

```swift Swift icon="swift" theme={null}
await OneS1ght.reset()
```

```objc Objective-C icon="apple" theme={null}
[OneS1ghtBridge reset:^{ }];
```

### Handling positioning shutdown

When the positioning engine shuts down, `onStopped` fires and you can bring the app back to a state where positioning can start again.

```swift Swift icon="swift" theme={null}
session.onStopped = { reason in
    if case .engineFailed = reason { showRetrySearch() }   // fix the cause, then call begin() again
}
```

```objc Objective-C icon="apple" theme={null}
[OneS1ghtBridge onStopped:^(NSString *reason) {
    if ([reason isEqualToString:@"engineFailed"]) { [self showRetrySearch]; }   // fix the cause, then call begin again
}];
```

### Checking device support

`deviceAvailability` can be read right away without a network (internet) connection.\

Devices that do not support positioning do not affect the rest of your app.

| Function · Property | Description | Returns |
| - | - | - |
| `deviceAvailability` | Device support (detailed) | `DeviceAvailability` `.available`: supported `.osVersionTooLow`: OS not supported  `.deviceNotSupported`: device cannot receive positioning data |
| `isDeviceAvailable` | Device support (summary) | `Bool` |

```swift Swift icon="swift" theme={null}
switch OneS1ght.deviceAvailability {
case .available:          break
case .osVersionTooLow:    showNotice("iOS 27 or later is required")
case .deviceNotSupported: hidePositioningFeatures()     // device without UWB
@unknown default:         break
}
```

```objc Objective-C icon="apple" theme={null}
NSString *availability = OneS1ghtBridge.deviceAvailability;   // @"available" · @"osVersionTooLow" · @"deviceNotSupported"
if (![availability isEqualToString:@"available"]) {
    [self hidePositioningFeatures];
}
```

## Appendix

### Writing Info.plist directly

The list shown in Xcode's **\[Info]** tab is actually the contents of a file named `Info.plist`. Projects created with recent versions of Xcode do not show
this file and generate it at build time, so to write to it directly you first have to create it.
This method also works if Xcode crashes while you add the Dictionary key.

**1. Check whether the file exists**

If `Info.plist` is visible in the Project Navigator on the left, skip to step 3.

**2. Create the file**

In **\[File] → \[New] → \[File from Template…]** choose **Property List**, name it `Info.plist` and save it in the app target folder.
Then search for `Info.plist File` in the **\[Build Settings]** tab and set its value to `TargetName/Info.plist`.
Leave `Generate Info.plist File` set to **Yes** — Xcode merges the generated entries with this file.

**3. Paste the XML**

Right-click `Info.plist` → **Open As → Source Code**, then paste the XML from [iOS permissions](#ios-permissions) between `<dict>` and `</dict>`.

### Requesting permission (Nearby Interaction)

Locator positioning uses Apple's Nearby Interaction. `requestPermission()` shows the system permission prompt, and the user decides whether to allow it. \

Once denied, the app cannot ask again, so guide the user to turn the permission on in Settings.

| Function · Property | Description | Returns |
| - | - | - |
| `requestPermission()` | Requests the Nearby Interaction permission | `PermissionStatus` `.authorized`: granted `.denied`: denied `.unsupported`: unsupported device |

```swift Swift icon="swift" theme={null}
switch await OneS1ght.requestPermission() {
case .authorized:  break
case .denied:      showSettingsGuide()        // cannot ask again from the app — send the user to the Settings app
case .unsupported: showUnsupportedNotice()    // device without positioning support
@unknown default:  break
}
```

```objc Objective-C icon="apple" theme={null}
[OneS1ghtBridge requestPermission:^(NSString *status) {
    if ([status isEqualToString:@"denied"])      { [self showSettingsGuide]; }       // cannot ask again from the app — send the user to the Settings app
    if ([status isEqualToString:@"unsupported"]) { [self showUnsupportedNotice]; }   // device without positioning support
}];
```

### Always location permission

On iOS 27.2 and later, location access must be **'Always'** for the floor to be detected (BLE beacon region monitoring). On iOS 27.1 and earlier, 'While Using the App' is enough. \

The SDK does not request 'Always'. Without it the SDK still starts but cannot find the floor. If the user declined, guide them to Settings.

```swift Swift icon="swift" theme={null}
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
    if manager.authorizationStatus == .authorizedWhenInUse {
        manager.requestAlwaysAuthorization()   // iOS shows this prompt only once per app
    }
}
```

```objc Objective-C icon="apple" theme={null}
- (void)locationManagerDidChangeAuthorization:(CLLocationManager *)manager {
    if (manager.authorizationStatus == kCLAuthorizationStatusAuthorizedWhenInUse) {
        [manager requestAlwaysAuthorization];   // iOS shows this prompt only once per app
    }
}
```

### Debug logs

To see debug logs, register the handler **right before** calling `initialize`. \

Logs printed with `print` as below appear in the Xcode debug console.

```swift Swift icon="swift" theme={null}
#if DEBUG
OneS1ght.onDebugLog = { level, line in print("[OneS1ght][\(level)] \(line)") }
#endif
```

```objc Objective-C icon="apple" theme={null}
#ifdef DEBUG
[OneS1ghtBridge onDebugLog:^(NSString *level, NSString *line) { NSLog(@"[OneS1ght][%@] %@", level, line); }];
#endif
```

## Troubleshooting

> **[Error codes](/en/developers/sdk/troubleshooting/error-codes)**
>
> Explains the errors you may run into during development.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.