通过JNI从Java使用CoreBluetooth时,didDiscoverCharacteristics没有被调用

时间:2019-06-14 16:04:10

标签: java c++ swift java-native-interface core-bluetooth

我正在为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端进行任何更改。

2 个答案:

答案 0 :(得分:0)

当您无法保留对相关对象的引用时,CoreBluetooth倾向于采用这种方式。确保在BLE对话的整个生命周期中始终保留对您感兴趣的外围设备,服务和特性的持久引用。

答案 1 :(得分:0)

Java 8的JNI可能与CoreBluetooth处理线程的方式不兼容。您可以使用JDK 9而不是8来解决此问题。