Created
January 24, 2019 05:35
-
-
Save banjun/ad0289760f7fd6dac49bacac4e13ff4b to your computer and use it in GitHub Desktop.
Capture iBeacon packets and show them in Touch Bar
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/swift | |
import CoreBluetooth | |
import AppKit | |
class AppDelegate: NSResponder, CBCentralManagerDelegate, NSTouchBarDelegate, NSApplicationDelegate { | |
let manager: CBCentralManager | |
var advertises: [Advertise] = [] | |
override init() { | |
manager = CBCentralManager(delegate: nil, queue: DispatchQueue.main) | |
super.init() | |
manager.delegate = self | |
} | |
required init?(coder: NSCoder) { | |
fatalError("init(coder:) has not been implemented") | |
} | |
struct Advertise: CustomStringConvertible { | |
enum ManufacturerData { | |
case iBeacon(UUID, UInt16, UInt16) // uuid, major, minor | |
case apple(UInt8, UInt8, Data) // Type, Subtype, remainder | |
case other(Data) | |
} | |
var manufacturerData: ManufacturerData | |
var name: String? | |
var time: Date | |
var description: String { | |
let df = DateFormatter() | |
df.locale = Locale.current | |
df.dateStyle = .short | |
df.timeStyle = .medium | |
let timeString = df.string(from: time) | |
switch manufacturerData { | |
case let .iBeacon(uuid, major, minor): | |
return "\(timeString) iBeacon(\(name ?? "unknown")) (\(uuid.uuidString), \(major), \(minor))" | |
case let .apple(type, subtype, data): | |
return "\(timeString) apple(type=\((type, subtype)))(\(name ?? "unknown")) (\((data as NSData).description))" | |
case let .other(data): | |
return "\(timeString) other(\(name ?? "unknown")) (\((data as NSData).description))" | |
} | |
} | |
} | |
public func centralManagerDidUpdateState(_ central: CBCentralManager) { | |
NSLog("%@", "\(#function): \(central.state.rawValue)") | |
guard central.state == .poweredOn else { return } | |
manager.scanForPeripherals(withServices: nil, options: [CBCentralManagerScanOptionAllowDuplicatesKey: true]) | |
} | |
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) { | |
guard let manufacturerData = advertisementData["kCBAdvDataManufacturerData"] as? Data else { return } // ignore non iBeacon | |
let adData: Advertise.ManufacturerData | |
if manufacturerData.starts(with: [0x4c, 0x00, 0x02, 0x15]) && manufacturerData.count == 4 + 16 + 2 + 2 + 1 { | |
let (uuid, major, minor) = manufacturerData.withUnsafeBytes { p in | |
(NSUUID(uuidBytes: p + 4) as UUID, | |
CFSwapInt16BigToHost((p + 20).withMemoryRebound(to: UInt16.self, capacity: 1) {$0.pointee}), | |
CFSwapInt16BigToHost((p + 22).withMemoryRebound(to: UInt16.self, capacity: 1) {$0.pointee})) | |
} | |
adData = .iBeacon(uuid, major, minor) | |
} else if manufacturerData.starts(with: [0x4c, 0x00]) { | |
let (type, subtype) = manufacturerData.withUnsafeBytes { (p: UnsafePointer<UInt8>) in | |
((p + 2).pointee, (p + 3).pointee) | |
} | |
adData = .apple(type, subtype, Data(manufacturerData.dropFirst(4))) | |
} else { | |
adData = .other(manufacturerData) | |
} | |
let advertise = Advertise(manufacturerData: adData, name: peripheral.name, time: Date()) | |
print("\(advertise)") | |
fflush(__stdoutp) | |
if #available(OSX 10.12, *), case .iBeacon = advertise.manufacturerData { | |
touchbarLabel.stringValue = advertise.description | |
} | |
} | |
@available(OSX 10.12.2, *) | |
lazy var touchbar: NSTouchBar = { | |
let tb = NSTouchBar() | |
tb.delegate = self | |
tb.defaultItemIdentifiers = [NSTouchBarItem.Identifier(rawValue: "hoge")] | |
return tb | |
}() | |
@available(OSX 10.12.2, *) | |
override func makeTouchBar() -> NSTouchBar? { | |
return touchbar | |
} | |
@available(OSX 10.12, *) | |
lazy var touchbarLabel: NSTextField = NSTextField(labelWithString: "") | |
@available(OSX 10.12.2, *) | |
func touchBar(_ touchBar: NSTouchBar, makeItemForIdentifier identifier: NSTouchBarItem.Identifier) -> NSTouchBarItem? { | |
let item = NSCustomTouchBarItem(identifier: identifier) | |
item.view = touchbarLabel | |
return item | |
} | |
} | |
let appDelegate = AppDelegate() | |
let app = NSApplication.shared | |
app.setActivationPolicy(.regular) | |
app.delegate = appDelegate | |
app.run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment