igloo
Docs / iglooworks / BLE SDK / Getting Started

Getting Started

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:

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:

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:

dependencies {
    implementation("co.igloo.works:sdk:2.3.0")
}

Installation (iOS)

1. Add the Package

Via Swift Package Manager, in Xcode: File → Add Package Dependencies…, or in Package.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

import IglooworksSDK

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


Permissions

AndroidManifest.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)

<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:

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

Runtime Permissions

Request BLE permissions before calling any SDK method:

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

val sdk = IglooPlugin(context, apiKey = "your-api-key")
let sdk = IglooPlugin(apiKey: "your-api-key")

OAuth Authentication

val sdk = IglooPlugin(context)
// Pass accessToken to each method that requires it
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

sealed class Auth {
    data class ApiKey(val apiKey: String) : Auth()
    data object OAuth : Auth()
}
// 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

// 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 = "IGM4-XXXX", 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 = "IGM4-XXXX", 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("IGM4-XXXX")
// 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("IGM4-XXXX", 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("IGM4-XXXX", 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("IGM4-XXXX")

Next Steps