问题描述
我想检测到我的应用程序中已插入/移除了特定的USB.现在,我可以通过本教程获取deviceName 使用USB设备接口.但是,如何在Swift中执行(deviceAdded) IOServiceMatchingCallBack 的回调函数.
I would like to detect a specific USB is plugged in/removed in my application. For now, I can get the deviceName with this tutorial Working With USB Device Interfaces. But, how can I do the callback function of (deviceAdded)IOServiceMatchingCallBack in Swift.
我尝试如下,但出现错误:无法将类型'((UnsafePointer,迭代器:io_iterator_t)->()'的值转换为预期的参数类型'IOServiceMatchingCallback!'.
I tried as follows, but I got an error: Cannot convert value of type '(UnsafePointer, iterator: io_iterator_t) -> ()' to expected argument type 'IOServiceMatchingCallback!'
func detectUSBEvent() {
var portIterator: io_iterator_t = 0
var kr: kern_return_t = KERN_FAILURE
let matchingDict = IOServiceMatching(kIOUSBDeviceClassName)
let vendorIDString = kUSBVendorID as CFStringRef!
let productIDString = kUSBProductID as CFStringRef!
CFDictionarySetValue(matchingDict, unsafeAddressOf(vendorIDString), unsafeAddressOf(VendorID))
CFDictionarySetValue(matchingDict, unsafeAddressOf(productIDString), unsafeAddressOf(ProductID))
// To set up asynchronous notifications, create a notification port and add its run loop event source to the program’s run loop
let gNotifyPort: IONotificationPortRef = IONotificationPortCreate(kIOMasterPortDefault)
let runLoopSource: Unmanaged<CFRunLoopSource>! = IONotificationPortGetRunLoopSource(gNotifyPort)
let gRunLoop: CFRunLoop! = CFRunLoopGetCurrent()
CFRunLoopAddSource(gRunLoop, runLoopSource.takeUnretainedValue(), kCFRunLoopDefaultMode)
// Notification of first match:
kr = IOServiceAddMatchingNotification(gNotifyPort, kIOFirstMatchNotification, matchingDict, deviceAdded, nil, &portIterator)
deviceAdded(nil, iterator: portIterator)
}
func deviceAdded(refCon: UnsafePointer<Void>, iterator: io_iterator_t) {
if let usbDevice: io_service_t = IOIteratorNext(iterator)
{
let name = String()
let cs = (name as NSString).UTF8String
let deviceName: UnsafeMutablePointer<Int8> = UnsafeMutablePointer<Int8>(cs)
let kr: kern_return_t = IORegistryEntryGetName(usbDevice, deviceName)
if kr == KERN_SUCCESS {
let deviceNameAsCFString = CFStringCreateWithCString(kCFAllocatorDefault, deviceName,
kCFStringEncodingASCII)
print(deviceNameAsCFString)
// if deviceNameAsCFString == XXX
// Do Something
}
}
}
推荐答案
这是Swift 3版本,使用闭包代替全局函数(闭包w/oa上下文可以桥接到C函数指针),使用GCD代替Runloops(更好的API),使用回调和分派来通知事件,并使用真实对象而不是静态对象或单例:
Here's a Swift 3 version, using closures instead of global functions (a closure w/o a context can be bridged to a C function pointer), using GCD instead of Runloops (much nicer API), using callbacks and dispatches to inform about events and using real objects instead of static objects or singletons:
import Darwin
import IOKit
import IOKit.usb
import Foundation
class IOUSBDetector {
enum Event {
case Matched
case Terminated
}
let vendorID: Int
let productID: Int
var callbackQueue: DispatchQueue?
var callback: (
( _ detector: IOUSBDetector, _ event: Event,
_ service: io_service_t
) -> Void
)?
private
let internalQueue: DispatchQueue
private
let notifyPort: IONotificationPortRef
private
var matchedIterator: io_iterator_t = 0
private
var terminatedIterator: io_iterator_t = 0
private
func dispatchEvent (
event: Event, iterator: io_iterator_t
) {
repeat {
let nextService = IOIteratorNext(iterator)
guard nextService != 0 else { break }
if let cb = self.callback, let q = self.callbackQueue {
q.async {
cb(self, event, nextService)
IOObjectRelease(nextService)
}
} else {
IOObjectRelease(nextService)
}
} while (true)
}
init? ( vendorID: Int, productID: Int ) {
self.vendorID = vendorID
self.productID = productID
self.internalQueue = DispatchQueue(label: "IODetector")
guard let notifyPort = IONotificationPortCreate(kIOMasterPortDefault) else {
return nil
}
self.notifyPort = notifyPort
IONotificationPortSetDispatchQueue(notifyPort, self.internalQueue)
}
deinit {
self.stopDetection()
}
func startDetection ( ) -> Bool {
guard matchedIterator == 0 else { return true }
let matchingDict = IOServiceMatching(kIOUSBDeviceClassName)
as NSMutableDictionary
matchingDict[kUSBVendorID] = NSNumber(value: vendorID)
matchingDict[kUSBProductID] = NSNumber(value: productID)
let matchCallback: IOServiceMatchingCallback = {
(userData, iterator) in
let detector = Unmanaged<IOUSBDetector>
.fromOpaque(userData!).takeUnretainedValue()
detector.dispatchEvent(
event: .Matched, iterator: iterator
)
};
let termCallback: IOServiceMatchingCallback = {
(userData, iterator) in
let detector = Unmanaged<IOUSBDetector>
.fromOpaque(userData!).takeUnretainedValue()
detector.dispatchEvent(
event: .Terminated, iterator: iterator
)
};
let selfPtr = Unmanaged.passUnretained(self).toOpaque()
let addMatchError = IOServiceAddMatchingNotification(
self.notifyPort, kIOFirstMatchNotification,
matchingDict, matchCallback, selfPtr, &self.matchedIterator
)
let addTermError = IOServiceAddMatchingNotification(
self.notifyPort, kIOTerminatedNotification,
matchingDict, termCallback, selfPtr, &self.terminatedIterator
)
guard addMatchError == 0 && addTermError == 0 else {
if self.matchedIterator != 0 {
IOObjectRelease(self.matchedIterator)
self.matchedIterator = 0
}
if self.terminatedIterator != 0 {
IOObjectRelease(self.terminatedIterator)
self.terminatedIterator = 0
}
return false
}
// This is required even if nothing was found to "arm" the callback
self.dispatchEvent(event: .Matched, iterator: self.matchedIterator)
self.dispatchEvent(event: .Terminated, iterator: self.terminatedIterator)
return true
}
func stopDetection ( ) {
guard self.matchedIterator != 0 else { return }
IOObjectRelease(self.matchedIterator)
IOObjectRelease(self.terminatedIterator)
self.matchedIterator = 0
self.terminatedIterator = 0
}
}
这是一些用于测试该类的简单测试代码(将产品和供应商ID设置为适合您的USB设备):
And here is some simple test code to test that class (set product and vendor ID as appropriate for your USB device):
let test = IOUSBDetector(vendorID: 0x4e8, productID: 0x1a23)
test?.callbackQueue = DispatchQueue.global()
test?.callback = {
(detector, event, service) in
print("Event \(event)")
};
_ = test?.startDetection()
while true { sleep(1) }
这篇关于如何在Swift中实现IOServiceMatchingCallBack的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!