Skip to main content

iOS SDK: Getting started

This guide explains how to install the Cartrack BLE Lock SDK for iOS and run the basic connection flow against a compatible BLE terminal.

Installation

  • Add the CartrackBleLock.xcframework folder to your Xcode project.
  • In Project Settings → Frameworks, Libraries, and Embedded Content, set CartrackBleLock.xcframework to Embed & Sign.

Overview

The Cartrack BLE Lock SDK provides a simple and secure way to:

  • Connect to BLE-enabled vehicle terminals
  • Lock and unlock vehicles remotely
  • Control vehicle features (headlights, horn)
  • Monitor vehicle status and statistics
  • Receive real-time connection and signal strength updates

Core Components

BleService

The entry point for the SDK. Use BleService.getTerminal(terminalID:) to obtain a BleTerminal instance for interacting with a specific vehicle terminal.

BleTerminal

Provides direct interaction with a BLE terminal. Handles connection management, authentication, and command execution.

BleTerminalDelegate

Protocol for receiving callbacks from BLE terminal events, including connection state changes, action results, and vehicle statistics updates.

VehicleStats

Data model containing comprehensive vehicle statistics including odometer, fuel level, door states, and more.

Quick Start

All examples require import CartrackBleLockSDK in the source file.

Before connecting, initialize BleTerminal and save the authentication key.

Your class must conform to BleTerminalDelegate to receive callbacks.

1. Initialize BleTerminal

Initialize BleTerminal variable to get an instance of BleTerminal and set the delegate:

var bleTerminal: BleTerminal

bleTerminal = BleService.getTerminal(terminalID: "SBS1234X")
bleTerminal.delegate = self

2. Save Authentication Key

Save the authentication key with BleTerminal.saveAuthKey(authKey:):

bleTerminal?.saveAuthKey(authKey: "<Authentication Key>")

The authentication key is saved in the keychain.

IMPORTANT: The authentication key must be saved before connecting to the BLE terminal.

The response for BleTerminal.saveAuthKey(authKey:) will be in BleTerminalDelegate.bleTerminalDidSavedKey(terminal:error:):

func bleTerminalDidSavedKey(terminal: BleTerminal, error: BleError?) {
if let error = error {
self.showMessage(title: "Save Key Failed", message: "\(error.errorCode) \(error.localizedDescription)")
} else {
self.showMessage(title: "Save Key Successful", message: "Successful save authentication key!")
}
}

3. Check Authentication Key

Check whether an authentication key exists in the keychain with BleTerminal.hasKey:

bleTerminal?.hasKey

Output: true or false

4. Get Authentication Key

Get the authentication key from the keychain with BleTerminal.authKey:

bleTerminal?.authKey

Output: <Authentication Key> or nil

5. Connect to Ble Terminal

Connect to Ble Terminal with BleTerminal.connect():

bleTerminal?.connect()

By default timeout in BleTerminal.connect(timeout:) is 10 sec.

Alternatively, if you want to extend the timeout:

bleTerminal?.connect(timeout: 20)

BleTerminal.connect() and BleTerminal.connect(timeout:) are the same function. If the key exists in the keychain, the SDK sends the connect command to the terminal; otherwise it returns BleError.keyNotFound.

The response for BleTerminal.connect(timeout:) will be in BleTerminalDelegate.bleTerminalDidConnect(terminal:error:):

func bleTerminalDidConnect(terminal: BleTerminal, error: BleError?) {
if let error = error {
showMessage(title: "Failed to connect", message: "\(error.errorCode) \(error.localizedDescription)")
} else {
showMessage(title: "Connect Successful", message: "")
}
}

6. Disconnect from Ble Terminal

Disconnect from Ble Terminal with BleTerminal.disconnect():

bleTerminal?.disconnect()

This function will send a disconnect command to the terminal.

The response for BleTerminal.disconnect() will be in BleTerminalDelegate.bleTerminalDisconnected(terminal:):

func bleTerminalDisconnected(terminal: BleTerminal) {
showMessage(title: "", message: "Disconnected")
}

7. Terminal Signal Update

Called periodically to update the BLE signal strength to Ble Terminal:

func bleTerminalSignalUpdate(rssi: Int, strength: BleSignalStrength) {
rssiLabel.text = "RSSI: \(rssi) dBm (\(strength))"
}

8. Remove Authentication Key

Remove the authentication key in the keychain with BleTerminal.removeAuthKey():

bleTerminal?.removeAuthKey()

Call this function when vehicle rental is done.

The authentication key in the keychain will be removed.

9. Send Ble Action to Terminal

Send lock action to terminal:

bleTerminal?.sendAction(.lock)

Send unlock action to terminal:

bleTerminal?.sendAction(.unlock)

Send headlight action to terminal:

bleTerminal?.sendAction(.headlight)

Send horn action to terminal:

bleTerminal?.sendAction(.horn)

Get the current state of vehicle's lock status - possible value - locked/unlocked:

bleTerminal?.sendAction(.lockState)

The default value of BleTerminal.lockState is LockState.unknown, send BleAction.lockState action to refresh the state.

Send unlock with no key fob action to terminal:

bleTerminal?.sendAction(.unlockNoKeyFob)

Get the current state of vehicle's ignition status - possible value - on/off:

bleTerminal?.sendAction(.ignitionState)

The default value of BleTerminal.ignitionState is IgnitionState.unknown, send BleAction.ignitionState action to refresh the state.

The response for all BleAction will be in BleTerminalDelegate.bleTerminalDidAction(terminal:action:error:):

func bleTerminalDidAction(terminal: BleTerminal, action: BleAction, error: BleError?) { 
if let error = error {
showMessage(title: "Action Failed", message: "[\(error.actionCode)] get vehicle stats Failed\nReason: [\(error.errorCode)] \(error.localizedDescription)")
} else {
switch action {
case .lock:
showMessage(title: "Action", message: "Lock Action Success\nLock state: [\(terminal.lockState)]")
case .unlock:
showMessage(title: "Action", message: "Unlock Action Success\nLock state: [\(terminal.lockState)]")
case .horn:
showMessage(title: "Action", message: "Horn Action Success")
case .headlight:
showMessage(title: "Action", message: "Headlight Action Success")
case .lockState:
showMessage(title: "Action", message: "Vehicle's door is \(terminal.lockState)")
case .unlockNoKeyFob:
showMessage(title: "Action", message: "Unlock with No Key Fob Action Success\nLock state: [\(terminal.lockState)]")
case .ignitionState:
showMessage(title: "Action", message: "Vehicle's ignition state is \(terminal.ignitionState)")
@unknown default:
break
}
}
}

10. Get Vehicle Stats from Terminal

Send vehicle stats to Terminal:

bleTerminal?.getVehicleStats()

The response for BleTerminal.getVehicleStats() will be in BleTerminalDelegate.bleTerminalDidGetVehicleStats(terminal:vehicleStats:error:):

func bleTerminalDidGetVehicleStats(terminal: BleTerminal, vehicleStats: VehicleStats?, error: BleError?) {
if let error = error {
showMessage(title: "Action Failed", message: "[\(error.errorCode)] get vehicle stats Failed\nReason: \(error.localizedDescription)")
} else {
print(vehicleStats?.odometer)
print(vehicleStats?.fuelLevel)
}
}

API Reference

Core Classes

Protocols

Enumerations

Best Practices

Connection Management

  • Always check hasKey before attempting to connect
  • Use appropriate timeout values (default 10 seconds recommended)
  • Handle disconnection events gracefully

Signal Strength Monitoring

  • Monitor signal strength via bleTerminalSignalUpdate delegate method
  • Avoid sending actions when signal is .weak
  • Prompt users to move closer to the vehicle when signal is poor

Error Handling

  • Always handle errors in delegate callbacks
  • Check for specific error types to provide better user feedback
  • Use error.localizedDescription for user-facing error messages

Resource Cleanup

  • Call removeAuthKey() when rental period ends
  • Call disconnect() when done with terminal interaction
  • Properly manage delegate lifecycle to avoid memory leaks

Next Steps