swiftcore-audiocore-bluetoothmidicoremidi

Open MIDI Bluetooth Configuration pane of MacOS programatically from Swift


I can open the Audio MIDI Setup app programatically like this:

NSWorkspace.shared.launchApplication("Audio MIDI Setup")

But how can I open the Bluetooth Configuration window inside the app?

Bluetooth Configuration window

I've seen other apps having a menu item which opens up this dialog directly.


Solution

  • Apple provides a window controller for developers to use called CABTLEMIDIWindowController. The documentation is pretty sparse, but there is a bit more information in the code comments:

    /**
    @class CABTLEMIDIWindowController
    
    @abstract  A window controller object that can present a window that displays nearby
     Bluetooth-based MIDI peripherals. The user can select one of those peripherals and 
     pair it with their mac. Additionally, the user can advertise the mac as a 
     Bluetooth-based MIDI peripheral.
     
    @discussion To use this class, create an instance of the CABTLEMIDIWindowController,
     initialize it, and call showWindow: to display the UI.
    */
    

    Usage is surprisingly straightforward:

    let windowController = CABTLEMIDIWindowController()
    windowController.showWindow(self)
    

    NOTE:

    Your app must have bluetooth configured and approved otherwise the window controller will appear like this:

    Error

    You must select Bluetooth from the App Sandbox settings and add the NSBluetoothAlwaysUsageDescription key to your Info.plist:

    setup

    FULL EXAMPLE:

    import Cocoa
    import CoreBluetooth
    import CoreAudioKit
    
    class ViewController: NSViewController, CBCentralManagerDelegate {
        fileprivate var centralManager: CBCentralManager!
        
        override func viewDidLoad() {
            super.viewDidLoad()
            centralManager = CBCentralManager(delegate: self, queue: nil)
        }
        
        func centralManagerDidUpdateState(_ central: CBCentralManager) {
            if (central.state == .poweredOn) {
                let windowController = CABTLEMIDIWindowController()
                windowController.showWindow(self)
            }
        }
    }
    

    Success

    BONUS:

    Found this while snooping around. Saves users a lot of clicks by opening System Preferences -> Security & Privacy -> Privacy -> Bluetooth:

    NSWorkspace.shared.open(URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_Bluetooth")!)