Issues with IOBluetoothDeviceInquiry Delegate

All,

I have an issue where my IOBluetoothDeviceInquiry and IOBluetoothDevicePair objects do not seem to be triggering all of their lifecycle states. Here is some sample code below. What am I missing here. In this example, the deviceInquiryStarted trigger never fires, even though it clearly starts and finds devices. Also devices are not added to the @Published object as they are found.

Also the sender.stop() does not seem to work when coming from the delegate to stop the search.

I feel like I am just missing something here as it relates to delegates.

I am just looking to scan for HID devices like mice, keyboards and headsets. Then allow the user to pair the device, and list paired devices.

I am pretty new to IOBluetooth so any help is appreciated.

import IOBluetooth

import IOBluetoothUI

import SwiftUI



class BluetoothSearchDelegate : NSObject, ObservableObject, IOBluetoothDeviceInquiryDelegate {

    

    @Published var devices: [IOBluetoothDevice] = []

    

    func deviceInquiryDeviceFound(_ sender: IOBluetoothDeviceInquiry, device: IOBluetoothDevice) {

        debugPrint("********** DEVICE FOUND ************")

        self.devices.append(device)

    }

    

    func deviceInquiryStarted(_ sender: IOBluetoothDeviceInquiry) {

        debugPrint("inquiryStarted")

    }

    

    func deviceInquiryComplete(_ sender: IOBluetoothDeviceInquiry, error: IOReturn, aborted: Bool) {

        sender.stop()

        print("completed")

    }

}



class BluetoothController: ObservableObject {

    

    //

    // DEVICE LISTS

    //

    @Published var devices: [IOBluetoothDevice] = []

    

    //

    // SEARCH TYPE

    //

    let searchType: IOBluetoothDeviceSearchTypes = kIOBluetoothDeviceSearchClassic.rawValue

    

    //

    // BLUETOOTH DEVICE

    //

    let btDevice: IOBluetoothDevice = IOBluetoothDevice()

    

    //

    // DELEGATES

    //

    let searchDelegate = BluetoothSearchDelegate()

    

    //

    // AGENTS

    //

    let searchAgent: IOBluetoothDeviceInquiry

    let pairingAgent = IOBluetoothDevicePair()

    

    init() {

        self.searchAgent = IOBluetoothDeviceInquiry(delegate: self.searchDelegate)

        self.searchAgent.searchType = self.searchType

    }

    

    func scan() {

        self.searchAgent.inquiryLength = 1

        self.searchAgent.start()

        self.devices = self.searchDelegate.devices

    }

    

    func getPairedDevices() -> [IOBluetoothDevice] {

        let devices = IOBluetoothDevice.pairedDevices() as? [IOBluetoothDevice]

        debugPrint(devices ?? [])

        return devices ?? []

    }

    

    func stop() {

        self.searchAgent.stop()

        self.devices = self.searchAgent.foundDevices() as? [IOBluetoothDevice] ?? []

        self.searchAgent.clearFoundDevices()

        

        debugPrint("Device Count: \(self.devices.count)")

    }

    

    func pair(device: IOBluetoothDevice) -> IOBluetoothDevicePair {

        self.pairingAgent.setDevice(device)

        pairingAgent.start()

        return pairingAgent

    }

    

    func stopPairing(pairingAgent: IOBluetoothDevicePair) {

        pairingAgent.stop()

    }

    

    

    

}



struct ContentView: View {

    @State var isScanning: Bool = false

    @State var isPairing: Bool = false

    @ObservedObject var bt = BluetoothController()

    

    var body: some View {

        VStack {

            Text("Scan for bt devices").padding()

            Button(action: {

                if !self.isScanning {

                    self.bt.scan()

                    self.isScanning.toggle()

                    return

                } else {

                    self.bt.stop()

                    self.isScanning.toggle()

                    return

                }

                

            }, label: {

                Text(self.isScanning ? "Stop" : "Scan")

            }).padding()

            

            List(self.bt.searchDelegate.devices, id: \.self) { device in

                HStack {

                    Text("\(device.name)")

                    Spacer()

                    Button(action: {

                        var pairingAgent: IOBluetoothDevicePair = IOBluetoothDevicePair()

                        if !self.isPairing {

                            pairingAgent = bt.pair(device: device)

                        } else {

                            bt.stopPairing(pairingAgent: pairingAgent)

                        }

                    }, label: {

                        

                        if !self.isPairing {

                            Text("Pair")

                        } else {

                            Text("Stop")

                        }

                    })

                }

            }

        }

    }

}