Native iOS apps use the CocoaPod MentraBluetoothSDK.
Requirements
- iOS deployment target
15.1 or newer.
- Xcode 15 or newer.
- CocoaPods.
- A physical iPhone for Bluetooth, camera, microphone, direct phone photo, and direct phone WebRTC testing.
Podfile
platform :ios, '15.1'
target 'YourApp' do
use_frameworks!
pod 'MentraBluetoothSDK', '0.1.5'
end
Install pods:
Permissions
Add usage descriptions to Info.plist:
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app connects to your smart glasses over Bluetooth.</string>
<key>NSMicrophoneUsageDescription</key>
<string>This app uses the microphone when you enable audio features.</string>
<key>NSLocalNetworkUsageDescription</key>
<string>This app can connect to optional local demo servers on your network.</string>
Background Operation
If your iOS app needs to keep the glasses BLE link alive while the phone is locked or the app is backgrounded, enable Core Bluetooth background mode:
<key>UIBackgroundModes</key>
<array>
<string>bluetooth-central</string>
</array>
If your app also keeps microphone capture or an audio session active in the background, add audio as well:
<key>UIBackgroundModes</key>
<array>
<string>bluetooth-central</string>
<string>audio</string>
</array>
Configure your AVAudioSession before starting continuous microphone or playback work. Start continuous microphone capture while the app is foregrounded; iOS background mode lets an active session continue, but the SDK does not start the phone microphone from the background. For example:
let session = AVAudioSession.sharedInstance()
try session.setCategory(.playAndRecord, mode: .default, options: [.allowBluetooth, .defaultToSpeaker])
try session.setActive(true)
bluetooth-central allows iOS to continue BLE central activity in the background, subject to iOS scheduling and power-management limits. audio is required only for apps that intentionally keep recording or audio playback active after backgrounding.
This SDK version does not enable terminated-app Core Bluetooth state restoration with CBCentralManagerOptionRestoreIdentifierKey. If iOS terminates the app, relaunch the app and reconnect from your normal startup flow.
Basic Flow
import MentraBluetoothSDK
@MainActor
final class GlassesController: NSObject, MentraBluetoothSDKDelegate {
private let sdk = MentraBluetoothSDK()
private var selectedDevice: Device?
override init() {
super.init()
sdk.delegate = self
}
func scan() throws {
try sdk.scan(model: .mentraLive, timeout: 10) { [weak self] devices in
self?.renderDevicePicker(devices) { device in
self?.selectedDevice = device
}
}
}
func connect() throws {
guard let selectedDevice else { return }
try sdk.connect(to: selectedDevice)
}
func refreshStatus() {
sdk.requestVersionInfo()
let glasses = sdk.glasses
if let device = glasses.device {
let battery = glasses.battery?.level.map(String.init) ?? "unknown"
print("Connected to \(device.deviceModel?.deviceType ?? "glasses"), battery=\(battery)%")
}
}
func mentraBluetoothSDK(_ sdk: MentraBluetoothSDK, didUpdateGlasses glasses: GlassesRuntimeState) {
// Keep app UI derived from SDK status.
print("Glasses changed: \(glasses)")
}
private func renderDevicePicker(_ devices: [Device], onSelect: @escaping (Device) -> Void) {
// Render devices in SDK-provided order and call onSelect with the user's choice.
}
deinit {
sdk.invalidate()
}
}
Local SDK Override
Use this when testing SDK source changes locally:
export MENTRA_BLUETOOTH_SDK_LOCAL_PATH=/path/to/MentraOS/mobile/modules/bluetooth-sdk/ios
pod install
Keep MENTRA_BLUETOOTH_SDK_LOCAL_PATH in your shell or CI environment, not in committed project settings.