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