

# SDK Setup

Install the iglooworks BLE SDK and make your first lock operation.

---

## Requirements

| Requirement | Version |
|-------------|---------|
| Android minSdk | 24 (Android 7.0) |
| Android compileSdk | 35 |
| Kotlin | 2.0.21+ |
| Java compatibility | 1.8 |
| iOS deployment target | 15.0+ |
| Xcode | 16+ |
| Swift | 6.0+ (Swift 6 language mode) |

> BLE requires a physical iOS device — the iOS Simulator does not support Bluetooth.

---

## Installation (Android)

### 1. Add the GitLab Maven Repository

In your project-level `settings.gradle.kts`:

```kotlin
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven {
            url = uri("https://gitlab.com/api/v4/projects/67339313/packages/maven")
            credentials(HttpHeaderCredentials::class) {
                name = "Private-Token"
                value = providers.gradleProperty("iglooGitlabToken").get()
            }
            authentication {
                create<HttpHeaderAuthentication>("header")
            }
        }
    }
}
```

Add your GitLab Personal Access Token to `gradle.properties`:

```properties
iglooGitlabToken=glpat-XXXXXXXXXXXXXXXXXXXX
```

> **Security:** Do not commit `gradle.properties` with tokens to version control. Add it to `.gitignore`.

### 2. Add the SDK Dependency

In your module-level `build.gradle.kts`:

```kotlin
dependencies {
    implementation("co.igloo.works:sdk:2.3.0-build.2")
}
```

---

## Installation (iOS)

### 1. Add the Package

Via Swift Package Manager, in Xcode: **File → Add Package Dependencies…**, or in `Package.swift`:

```swift
dependencies: [
    .package(url: "https://gitlab.com/igloohome/iglooworks-ios-sdk.git", branch: "main")
]
```

Add the `IglooworksSDK` product to your target's dependencies.

> **Note:** the package repo is private — Xcode must be configured with credentials (SSH key or a GitLab personal access token) that can read `gitlab.com/igloohome/iglooworks-ios-sdk`.

Set **Build Libraries for Distribution** (`BUILD_LIBRARY_FOR_DISTRIBUTION = YES`) on your app target — the SDK links a prebuilt `IglooSDKCore.xcframework`.

### 2. Import

```swift
import IglooworksSDK
```

Unlike some other igloo SDKs, `IglooworksSDK` re-exports the shared Bluetooth-layer error type (`LockManagerError`) itself, so there's no need to separately `import IglooSDKCore`.

---

## Permissions

### AndroidManifest.xml

```xml
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
```

### Info.plist (iOS)

```xml
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This application uses Bluetooth to connect to the Lock</string>
```

If your app needs to keep scanning or connected while backgrounded, also add the `bluetooth-central` background mode:

```xml
<key>UIBackgroundModes</key>
<array>
    <string>bluetooth-central</string>
</array>
```

### Runtime Permissions

Request BLE permissions before calling any SDK method:

```kotlin
private val blePermissions = arrayOf(
    Manifest.permission.BLUETOOTH_SCAN,
    Manifest.permission.BLUETOOTH_CONNECT,
    Manifest.permission.ACCESS_FINE_LOCATION,
)

private val permissionLauncher = registerForActivityResult(
    ActivityResultContracts.RequestMultiplePermissions()
) { grants ->
    if (grants.values.all { it }) {
        // All permissions granted — safe to use SDK
    }
}

// Call before first SDK use
permissionLauncher.launch(blePermissions)
```

There is no iOS equivalent of this step — just declare the `Info.plist` keys above and call SDK methods directly; the OS handles prompting.

---

## Initialization

### API Key Authentication

```kotlin
val sdk = IglooPlugin(context, apiKey = "your-api-key")
```

```swift
let sdk = IglooPlugin(apiKey: "your-api-key")
```

### OAuth Authentication

```kotlin
val sdk = IglooPlugin(context)
// Pass accessToken to each method that requires it
```

```swift
let sdk = IglooPlugin()
// Pass accessToken to each method that requires it — an operation called
// without one throws IglooworksError.api(status: 401, ...) "Missing bearer token"
```

> **Important:** Only one `IglooPlugin` instance should exist at a time. Multiple instances cause undefined BLE behavior — each holds its own connection state.

---

## Authentication Modes

```kotlin
sealed class Auth {
    data class ApiKey(val apiKey: String) : Auth()
    data object OAuth : Auth()
}
```

```swift
// IglooPlugin has two initializers, one per mode — no separate Auth type.
public init(apiKey: String)  // API Key mode
public init()                // OAuth mode
```

| Mode | Constructor | Token Handling |
|------|------------|---------------|
| API Key | `IglooPlugin(context, apiKey)` | SDK manages auth headers automatically. |
| OAuth | `IglooPlugin(context)` | Pass `accessToken` parameter to methods that require server calls. |

The same table on iOS:

| Mode | Constructor | Token Handling |
|------|------------|---------------|
| API Key | `IglooPlugin(apiKey:)` | SDK manages auth headers automatically. |
| OAuth | `IglooPlugin()` | Pass the relevant `...Token`/`accessToken` parameter to methods that require server calls. |

When using OAuth, methods that call the server accept an `accessToken: String?` parameter. This token must be a valid OAuth bearer token with the required scopes for the operation.

---

## Quick Start

```kotlin
// 1. Initialize
val sdk = IglooPlugin(context, apiKey = "your-api-key")

// 2. Scan for nearby locks
try {
    sdk.scanDevice().collect { result ->
        println("Found: ${result.deviceId}, paired=${result.isPaired}, rssi=${result.rssi}")
    }
} catch (e: IglooWorksException.BluetoothException) {
    println("Please enable Bluetooth")
} catch (e: IglooWorksException) {
    println("Scan failed: ${e.message}")
}

// 3. Lock a device
try {
    sdk.lock(deviceId = "IGM401abc123", key = guestKey)
    println("Locked")
} catch (e: IglooWorksException.ConnectionException) {
    println("unexpected bluetooth connection issue")
} catch (e: IglooWorksException) {
    println("Error: ${e.message}")
}

// 4. Sync device state
try {
    val sync = sdk.sync(deviceId = "IGM401abc123", key = guestKey)
    println("Battery: ${sync.batteryLevel}%")
} catch (e: IglooWorksException.ConnectionException) {
    println("unexpected bluetooth connection issue")
} catch (e: IglooWorksException) {
    println("Sync failed: ${e.message}")
}

// 5. Disconnect when done
sdk.disconnect("IGM401abc123")
```

```swift
// 1. Initialize
let sdk = IglooPlugin(apiKey: "your-api-key")

// 2. Scan for nearby locks
let scanTask = Task {
    do {
        for try await result in sdk.scansLock() {
            print("Found: \(result.bluetoothDeviceName), paired=\(result.isPaired)")
        }
    } catch LockManagerError.bluetoothIsTurnedOff {
        print("Please enable Bluetooth")
    } catch {
        print("Scan failed: \(error.localizedDescription)")
    }
}
// Stop scanning once you've found what you need:
sdk.stopScan()
scanTask.cancel()

// 3. Lock a device
do {
    try await sdk.lock("IGM401abc123", key: guestKey)
    print("Locked")
} catch LockManagerError.deviceDisconnected {
    print("unexpected bluetooth connection issue")
} catch {
    print("Error: \(error.localizedDescription)")
}

// 4. Sync device state
do {
    let result = try await sdk.sync("IGM401abc123", key: guestKey)
    print("Battery: \(result.batteryLevel)%")
} catch LockManagerError.deviceDisconnected {
    print("unexpected bluetooth connection issue")
} catch {
    print("Sync failed: \(error.localizedDescription)")
}

// 5. Disconnect when done
try? await sdk.disconnect("IGM401abc123")
```

---

## Next Steps

- [Lock & Unlock](/works/sdk_lock_unlock) — Control locks via BLE
- [Scanning](/works/sdk_scanning) — Discover nearby devices
- [Pairing](/works/sdk_pairing) — Register new locks
- [Error Reference](/works/sdk_errors) — All exception types and codes
