背景
シリアル通信向けのライブラリを作っている際にUSBデバイスの接続/排出の検出が必要となった.
下準備
プロジェクトのCapabilities
のApp Sandbox
のUSB
にチェックを入れる
ソース
USBDetector.swift
import Foundation
import IOKit
import IOKit.usb
public protocol USBDetectorDelegate: NSObjectProtocol {
func deviceAdded(_ device: io_object_t)
func deviceRemoved(_ device: io_object_t)
}
public class USBDetector {
public weak var delegate: USBDetectorDelegate?
private let notificationPort = IONotificationPortCreate(kIOMasterPortDefault)
private var addedIterator: io_iterator_t = 0
private var removedIterator: io_iterator_t = 0
public func start() {
let matchingDict = IOServiceMatching(kIOUSBDeviceClassName)
let opaqueSelf = Unmanaged.passUnretained(self).toOpaque()
let runLoop = IONotificationPortGetRunLoopSource(notificationPort)!.takeRetainedValue()
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoop, CFRunLoopMode.defaultMode)
let addedCallback: IOServiceMatchingCallback = { (pointer, iterator) in
let detector = Unmanaged<USBDetector>.fromOpaque(pointer!).takeUnretainedValue()
detector.delegate?.deviceAdded(iterator)
while case let device = IOIteratorNext(iterator), device != IO_OBJECT_NULL {
IOObjectRelease(device)
}
}
IOServiceAddMatchingNotification(notificationPort,
kIOPublishNotification,
matchingDict,
addedCallback,
opaqueSelf,
&addedIterator)
while case let device = IOIteratorNext(addedIterator), device != IO_OBJECT_NULL {
IOObjectRelease(device)
}
let removedCallback: IOServiceMatchingCallback = { (pointer, iterator) in
let watcher = Unmanaged<USBDetector>.fromOpaque(pointer!).takeUnretainedValue()
watcher.delegate?.deviceRemoved(iterator)
while case let device = IOIteratorNext(iterator), device != IO_OBJECT_NULL {
IOObjectRelease(device)
}
}
IOServiceAddMatchingNotification(notificationPort,
kIOTerminatedNotification,
matchingDict,
removedCallback,
opaqueSelf,
&removedIterator)
while case let device = IOIteratorNext(removedIterator), device != IO_OBJECT_NULL {
IOObjectRelease(device)
}
}
deinit {
Swift.print("deinit")
IOObjectRelease(addedIterator)
IOObjectRelease(removedIterator)
IONotificationPortDestroy(notificationPort)
}
}
ViewController.swift
import Cocoa
class ViewController: NSViewController, USBDetectorDelegate {
let detector = USBDetector()
override func viewDidLoad() {
super.viewDidLoad()
detector.delegate = self
detector.start()
}
override var representedObject: Any? {
didSet {
}
}
func deviceAdded(_ device: io_object_t) {
Swift.print("Added")
}
func deviceRemoved(_ device: io_object_t) {
Swift.print("Removed")
}
}
参考
StackOverflow USB Connection Delegate on Swift