我正在为MacOS上的低功耗蓝牙实现Java接口。我们想通过JNI调用CoreBluetooth API。我可以扫描设备并填充服务,但是我无法使特征正常工作,因为didDiscoverCharacteristics似乎没有被调用。
以可执行文件身份运行时,可以使用C ++对设备进行扫描,连接以及将其服务/特性填充和打印。然后,该应用程序将构建为动态库,并可以用Java加载。在Java中,将扫描设备并成功连接到该设备,然后可以发现其服务。但是从Java调用时永远不会发现特征。
这里是服务人员的流动,为清楚起见,省略了一些多余的部分:
C ++:BluetoothCentralNative.cpp
// tell "macable bridge" to populate services/characteristics
macableBridge.populateServices(name, UUID);
// retreive the discovered services (with characteristics populated)
vector<vector<string>> serviceData = macableBridge.getDiscoveredServices();
Objective-C ++:MacableBridge.mm
void MacableBridge::populateServices(string name, string UUID) {
NSString* nameString = [NSString stringWithCString:name.c_str() encoding:NSUTF8StringEncoding];
NSString* uuidString = [NSString stringWithCString:UUID.c_str() encoding:NSUTF8StringEncoding];
CBPeripheral* foundPeripheral = [macable findPeripheral:nameString deviceUUID:uuidString];
[macable connectToDevice:foundPeripheral];
[macable populateServices:foundPeripheral];
}
Objective-C:Macable.m
- (void) populateServices:(CBPeripheral *)device {
[_swift populateServicesWithDevice:device];
// sleep needs to be here to discover characteristics successfully as executable
// but when we sleep, thread seems to die when calling this library from java
sleep(1);
// more on retrieval of populated services later
}
Swiftable.swift
@objc public func populateServices(device: CBPeripheral) {
device.discoverServices(nil);
}
PeripheralDelegate.swift
// invoked when the peripheral's available services are discovered
public func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
print("\nServices discovered!\n")
//middleman.gotServices(peripheral.services) (more on this later)
for service in peripheral.services! {
peripheral.discoverCharacteristics(nil, for: service)
}
}
// invoked when characteristics of a specified service are discovered
public func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
print("Discovered characteristics for service: \(service)")
//middleman.gotCharacteristics(service)
}
仅当Swiftable发现了所有服务和特性时,我才尝试在Macable中设置CBServices数组。我尝试在Macable和Swiftable之间实现一个“中间人”,每当Swiftable的PeripheralDelegate发现服务或服务特征时,它都会更新中间人的服务列表。同样,一切都可以作为可执行文件运行,但在Java中使用.dylib时则不能。
我想知道如何强制任何C ++,Obj-C ++或Swift层等待,直到Swift调用“ didDiscoverCharacteristics”函数。如果我使用while循环来等待特征,主线程将被阻塞,并且我的程序将永远运行,以等待永远不会发生的特征发现。而且,如果我强迫程序进入睡眠状态,那么在Java中使用.dylib时,线程似乎已被放弃。
在我看来,发现设备和服务数量的逻辑与等待特征发现相同,但是只有前两个可以正常工作。
基于此JS library,我知道可以用非本机语言为CoreBluetooth实现API。
更新:这是Java的问题。我们的应用程序使用Java 8与JNI通信。升级到Java 9完全可以解决该问题,而无需在Swift端进行任何更改。
答案 0 :(得分:0)
当您无法保留对相关对象的引用时,CoreBluetooth倾向于采用这种方式。确保在BLE对话的整个生命周期中始终保留对您感兴趣的外围设备,服务和特性的持久引用。
答案 1 :(得分:0)
Java 8的JNI可能与CoreBluetooth处理线程的方式不兼容。您可以使用JDK 9而不是8来解决此问题。