LoginSignup
5
3

More than 5 years have passed since last update.

Swift:macでUSBデバイスの接続/排出を検知する.

Posted at

背景

シリアル通信向けのライブラリを作っている際にUSBデバイスの接続/排出の検出が必要となった.

下準備

プロジェクトのCapabilitiesApp SandboxUSBにチェックを入れる

ソース

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

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3