Reputation: 11
Recently, I want to to add Bluetooth midi support to my app, and I use the audiokit’s BluetoothMIDIbutton, which code can be found here https://github.com/AudioKit/AudioKit/blob/main/Sources/AudioKit/MIDI/BluetoothMIDIButton.swift. Because my UI is based on SwiftUI, and I use the UIRepresentable to bridge the UIView to my swiftUI View, after I add NSBluetoothAlwaysUsageDescription
and NSBluetoothPeripheralUsageDescription
, I can run this app and connect to my mac, after a while, this app lose the connection with my Mac, the console will print API MISUSE: Cancelling connection for unused peripheral <CBPeripheral: , identifier = , name = My MacBook Pro, mtu = 23, state = connecting>, Did you forget to keep a reference to it? and XPC connection invalid
. I have searched for solutions, which recommend me to add a strong reference to my ViewController? I donnot know how to add it properly, and my code goes like this , you can run directly by copying it and add NSBluetoothAlwaysUsageDescription
and NSBluetoothPeripheralUsageDescription
in the info.plist, and run it in a physical device. How could I do to fix this problem and run it properly.
import SwiftUI
import CoreAudioKit
struct BTMIDIView: UIViewControllerRepresentable {
@Environment(\.presentationMode) var presentationMode
func makeUIViewController(context: Context) -> UINavigationController {
let controller = BTMIDICentralViewController()
let nav = UINavigationController(rootViewController: controller)
// nav.modalPresentationStyle = .none
return nav
}
func updateUIViewController(_ uiViewController: UINavigationController, context: Context) {}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject {
var parent: BTMIDIView
init(_ parent: BTMIDIView) {
self.parent = parent
}
}
}
class BTMIDICentralViewController: CABTMIDICentralViewController {
@objc func doneAction() {
dismiss(animated: true)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
navigationItem.rightBarButtonItem = UIBarButtonItem(
barButtonSystemItem: .done,
target: self,
action: #selector(doneAction)
)
}
}
struct BluetoothMIDIControlView: View {
@State private var showMIDISetup = false
@EnvironmentObject var mainViewModel: MainViewModel
var body: some View {
ZStack(alignment: .top) {
Color(.systemBackground)
.ignoresSafeArea()
VStack(spacing: 20) {
Toggle("BLE MIDI", isOn: $mainViewModel.isBluetoothMIDIEnabled)
.toggleStyle(SwitchToggleStyle(tint: .blue))
.padding(.horizontal)
.onChange(of: mainViewModel.isBluetoothMIDIEnabled) { newValue in
handleMIDIToggle(newValue: newValue)
}
if mainViewModel.isBluetoothMIDIEnabled {
BTMIDIView()
.frame(height: 400)
.background(Color(.systemBackground))
.cornerRadius(12)
.shadow(radius: 5)
.padding()
} else {
Color.clear.frame(height: 400)
}
}
}
}
private func handleMIDIToggle(newValue: Bool) {
if newValue {
showMIDISetup = true
} else {
print("BLE MIDI closed")
}
}
}
#Preview {
let mainVM = MainViewModel()
BluetoothMIDIControlView()
.environmentObject(mainVM)
}
Upvotes: 1
Views: 19