Я реализую интерфейс Java для Bluetooth Low Energy на MacOS. Мы хотим позвонить в CoreBluetooth API через JNI. Я могу сканировать устройства и заполнять службы, но не могу заставить работать характеристики, потому что 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];
}
Цель-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)
}
Я пытался установить массив CBServices в Macable только тогда, когда Swiftable обнаружил все службы и характеристики. Я попытался реализовать «посредника» между Macable и Swiftable, где каждый раз, когда PerifheralDelegate Swiftable обнаруживает службы или характеристики для службы, он обновляет список служб Middleman. И снова, все работает как исполняемый файл, но не при использовании .dylib в Java.
Мне интересно, как заставить любой из слоев C ++, Obj-C ++ или Swift ждать, пока Swift не вызовет функцию didDiscoverCharacteristics. Если я использую цикл while для ожидания признаков, основной поток блокируется, и моя программа работает вечно, ожидая обнаружения признаков, которое никогда не происходит. И если я вынуждаю мою программу спать, поток, по-видимому, будет прерван при использовании .dylib в Java.
Мне кажется, что логика обнаружения устройств и обслуживающего персонала такая же, как ожидание обнаружения характеристики, но только первые два работают правильно.
Основываясь на этой библиотеке JS , я знаю, что можно реализовать API для CoreBluetooth на неродном языке.
ОБНОВЛЕНИЕ: Это проблема с Java. Наше приложение использовало Java 8 для общения с JNI. Обновление до Java 9 полностью решило проблему без каких-либо изменений на стороне Swift.