1

我正在开发一个需要蓝牙 2.1 的项目,并且我正在尝试制作一个测试客户端来连接到硬件。

因此,我一直在翻阅 IOBluetooth 的“文档”,并设法广播了 SDP 服务记录。

在设备(android)上打开一个连接并将数据写入我的计算机工作(根据远程设备),但我的客户端工具实际上并没有调用通知的选择器......

直到我停止客户端程序并重新启动它,在这种情况下它会立即触发。

关于通知如何触发的文档也很少,无论它们是否是异步的。

我已经绞尽脑汁一个星期了,你怎么看?

虚拟客户端代码:

BTSocketSession.swift

class BTSocketSession {

    var lock : DispatchSemaphore = DispatchSemaphore(value: 0);
    var serviceRecord : IOBluetoothSDPServiceRecord? = nil;
    var channel : IOBluetoothRFCOMMChannel? = nil;
    var notification : IOBluetoothUserNotification? = nil;
    var serverID : BluetoothRFCOMMChannelID = 255;
    var done = false;

    init(serviceRecordPListPath: String) {
        print("Loading Service Dictionary...");
        let serviceDict : NSMutableDictionary = NSMutableDictionary(contentsOfFile: serviceRecordPListPath)!;
        print("Done.");
        print("Publishing service...");
        self.serviceRecord = IOBluetoothSDPServiceRecord.publishedServiceRecord(with: serviceDict as! [AnyHashable : Any]);
        print("Done.");
    }

    func listen() {
        var id = BluetoothRFCOMMChannelID();
        self.serviceRecord?.getRFCOMMChannelID(&id);
        self.serverID = id;
        print(serviceRecord ?? "Derp");
        print(id);
        self.notification = IOBluetoothRFCOMMChannel.register(forChannelOpenNotifications: self, selector: #selector(self.rfcommChannelOpen(notification:channel:)), withChannelID: id, direction: kIOBluetoothUserNotificationChannelDirectionIncoming);
        self.lock.wait();
    }

    func cancel() {
        print("Cancelling service advertisement...");
        if (self.serviceRecord == nil) {
            self.removeServiceRecord();
            self.lock.signal();
            print("Done.");
        } else {
            print("Error: No service broadcasting.");
        }
    }

    private func removeServiceRecord() {
        self.serviceRecord?.remove();
        self.serviceRecord = nil;
        self.notification?.unregister();
        self.notification = nil;
    }

    @objc func rfcommChannelOpen(notification: IOBluetoothUserNotification, channel: IOBluetoothRFCOMMChannel) {
        if (self.serverID != channel.getID()) {
            return;
        }
        print("Notification Recieved!!!");
        print(channel);
        print(notification);
        self.done = true;
        notification.unregister();
        self.removeServiceRecord();
        self.channel = channel;
        self.lock.signal();
    }

}

main.swift

func main() {
    let q = DispatchQueue(label: "Demo");
    let s = DispatchSemaphore(value: 0);
    let c = BTSocketSession(serviceRecordPListPath: "/path/to/plist");

    q.async {
        print("Waiting for connection event...");
        c.listen();
        print("Done.");
        print("Releasing main thread...");
        s.signal()
        print("Done.");
    }

    s.wait();
    print("Closing channel...");
    c.channel?.close();
    c.cancel();
    print("Done.");
    print("Exiting...");

}

main();
print("Wellp");
4

1 回答 1

1

解决了:

事实证明,在 OSX 中制作命令行/无头应用程序时,您必须使用该RunLoop界面正确注册系统通知,例如蓝牙通道打开通知。

解决方案在这里找到。

变化:

以下允许程序按预期工作。

func main() {
    let q = DispatchQueue(label: "Demo");
    let c = BTSocketSession(serviceRecordPListPath: "/path/to/plist");

    q.async {
        print("Waiting for connection event...");
        c.listen();
        print("Done.");
        print("Releasing main thread...");
        c.channel.close();
        CFRunLoopStop(RunLoop.main.getCFRunLoop());
        print("Done.");
    }
    RunLoop.main.run();
    print("Exiting...");
}

main();
print("Wellp");

生活又精彩了=)希望你有美好的一天!

于 2017-05-18T19:16:22.097 回答