Best Practices
Patterns for building reliable apps with the IglooWorks BLE SDK.
Architecture
The SDK orchestrates BLE and server operations together. For example, createPin() writes the PIN to lock hardware via BLE, registers it on the server, and rolls back if the server call fails — all in one call.
Singleton Pattern
Only one IglooPlugin instance should exist at a time. Multiple instances hold separate connection state and will cause undefined BLE behavior.
Connection Management
- One operation at a time. BLE operations are serialized internally per device — don't fire multiple lock/unlock calls concurrently on the same device.
- Disconnect when done. Call
disconnect(deviceId)after your operation completes to free BLE resources. - The SDK connects automatically. There is no separate
connect()method —lock(),sync(),pair()etc. all connect internally.
Swift Concurrency Patterns
All BLE operations are async throws functions or return AsyncStream/AsyncThrowingStream. Use structured concurrency (Task, async let, task cancellation) in place of Kotlin's coroutine scopes.
Async Functions
Stream Collection
Stream with View Lifecycle
Error Handling
Catch at the UI layer, not deep in the call stack.
Retry only transient errors: TimeoutException, ConnectionException, and ApiException with 5xx status (Android); IglooworksError.timeout, LockManagerError.LockTimeoutError/.deviceDisconnected, and IglooworksError.api with 5xx status (iOS). Terminal errors like DevicePairedException/IglooworksError.devicePaired or LockStorageFullException/IglooworksError.lockStorageFull require user action.
Recommended Operation Sequences
First-Time Device Setup
scanDevice()(Android) /scansLock()(iOS) — find the lockpair()— register on accountcalibrate()— tune motor directionsync()— set clock and read batterysetWifiConfig()— if bridge, configure WiFi
Regular Operations
lock()/unlock()— control the locksync()— periodically sync time and logssyncJob()(Android) /syncJobs()(iOS) — execute queued PIN/key jobs
Access Management
createPin()/addKeycard()/addFingerprint()— add accessdeletePin()/deleteKeycard()/deleteFingerprint()— remove access
Firmware Update
checkFirmwareUpdate()— check for updatesperformDfu()— apply update (keep screen on)sync()— verify device state after update
Device Removal
unlink()— remove all accessories firstunpair()— remove the lock
Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
BluetoothException on every call |
Bluetooth disabled or permissions not granted | Check BluetoothAdapter.isEnabled and request runtime permissions |
ConnectionException frequently |
Device out of BLE range | Move within 2–3 meters of the lock |
TimeoutException on first call |
Lock in deep sleep | Retry — first connection wakes the lock |
DevicePairedException during pair |
Lock already registered | Check server if you own it; factory reset if transferring |
HasLinkedDeviceException during unpair |
Accessories still linked | Call unlink() for each accessory first |
DuplicatePinException |
Same PIN exists on lock | Choose a different PIN code |
LockStorageFullException |
Lock PIN/card slots exhausted | Delete existing access before adding new ones |
BatteryLowException during DFU |
Battery below threshold | Charge or replace batteries before DFU |
Multiple IglooPlugin instances |
Creating SDK in Activity/Fragment | Use application-scoped singleton |
| BLE operations fail silently | RxJava undeliverable exceptions | SDK handles these internally — upgrade if on old version |
The same table for iOS:
| Problem | Cause | Solution |
|---|---|---|
LockManagerError.bluetoothIsTurnedOff on every call |
Bluetooth disabled, or NSBluetoothAlwaysUsageDescription missing from Info.plist |
Enable Bluetooth; verify the Info.plist key is present |
LockManagerError.deviceDisconnected frequently |
Device out of BLE range | Move within 2–3 meters of the lock |
LockManagerError.LockTimeoutError / IglooworksError.timeout on first call |
Lock in deep sleep | Retry — first connection wakes the lock |
IglooworksError.devicePaired / LockManagerError.deviceAlreadyPaired during pair |
Lock already registered | Check server if you own it; factory reset if transferring |
IglooworksError.hasLinkedDevice during unpair |
Accessories still linked | Call unlink() for each accessory first |
IglooworksError.duplicatePin |
Same PIN exists on lock | Choose a different PIN code |
IglooworksError.lockStorageFull |
Lock PIN/card slots exhausted | Delete existing access before adding new ones |
IglooworksError.batteryLow during DFU |
Battery below threshold | Charge or replace batteries before DFU |
| Testing on Simulator does nothing | Bluetooth is unavailable in the iOS Simulator | Test on a physical device |
401 from an OAuth-mode IglooPlugin() call |
No accessToken/...Token argument passed for that call |
Pass the relevant token — required per-call under OAuth mode, unlike API Key mode |