Skip to content

Commit

Permalink
OnValueChanged moved to method channel (#11),fixes #44. iOS discoverS…
Browse files Browse the repository at this point in the history
…ervices queue implemented, fixes #46.
  • Loading branch information
demarcoMac committed Mar 9, 2018
1 parent 69d9508 commit 09eb37c
Show file tree
Hide file tree
Showing 6 changed files with 29 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ public class FlutterBluePlugin implements MethodCallHandler {
private final EventChannel servicesDiscoveredChannel;
private final EventChannel characteristicReadChannel;
private final EventChannel descriptorReadChannel;
private final EventChannel characteristicNotifiedChannel;
private final BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private final Map<String, BluetoothGatt> mGattServers = new HashMap<>();
Expand All @@ -75,7 +74,6 @@ public static void registerWith(Registrar registrar) {
this.servicesDiscoveredChannel = new EventChannel(registrar.messenger(), NAMESPACE+"/servicesDiscovered");
this.characteristicReadChannel = new EventChannel(registrar.messenger(), NAMESPACE+"/characteristicRead");
this.descriptorReadChannel = new EventChannel(registrar.messenger(), NAMESPACE+"/descriptorRead");
this.characteristicNotifiedChannel = new EventChannel(registrar.messenger(), NAMESPACE+"/characteristicNotified");
this.mBluetoothManager = (BluetoothManager) r.activity().getSystemService(Context.BLUETOOTH_SERVICE);
this.mBluetoothAdapter = mBluetoothManager.getAdapter();
channel.setMethodCallHandler(this);
Expand All @@ -84,7 +82,6 @@ public static void registerWith(Registrar registrar) {
servicesDiscoveredChannel.setStreamHandler(servicesDiscoveredHandler);
characteristicReadChannel.setStreamHandler(characteristicReadHandler);
descriptorReadChannel.setStreamHandler(descriptorReadHandler);
characteristicNotifiedChannel.setStreamHandler(characteristicNotifiedHandler);
}

@Override
Expand Down Expand Up @@ -690,19 +687,6 @@ public void onCancel(Object o) {
}
};

private EventSink characteristicNotifiedSink;
private final StreamHandler characteristicNotifiedHandler = new StreamHandler() {
@Override
public void onListen(Object o, EventChannel.EventSink eventSink) {
characteristicNotifiedSink = eventSink;
}

@Override
public void onCancel(Object o) {
characteristicNotifiedSink = null;
}
};

private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
Expand Down Expand Up @@ -749,14 +733,11 @@ public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristi

@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
Log.d(TAG, "onCharacteristicChanged: " + characteristic.getValue());
if(characteristicNotifiedSink != null) {
// Rebuild the ReadAttributeRequest and send back along with response
Protos.OnNotificationResponse.Builder q = Protos.OnNotificationResponse.newBuilder();
q.setRemoteId(gatt.getDevice().getAddress());
q.setCharacteristic(ProtoMaker.from(characteristic, gatt));
characteristicNotifiedSink.success(q.build().toByteArray());
}
Log.d(TAG, "onCharacteristicChanged: " + characteristic.getUuid().toString());
Protos.OnNotificationResponse.Builder p = Protos.OnNotificationResponse.newBuilder();
p.setRemoteId(gatt.getDevice().getAddress());
p.setCharacteristic(ProtoMaker.from(characteristic, gatt));
channel.invokeMethod("OnValueChanged", p.build().toByteArray());
}

@Override
Expand Down
Binary file modified example/ios/Flutter/flutter_assets/snapshot_blob.bin
Binary file not shown.
2 changes: 1 addition & 1 deletion example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class _FlutterBlueAppState extends State<FlutterBlueApp> {
StreamSubscription deviceConnection;
StreamSubscription deviceStateSubscription;
List<BluetoothService> services = new List();
Map<Guid, StreamSubscription> valueChangedSubscriptions;
Map<Guid, StreamSubscription> valueChangedSubscriptions = {};
BluetoothDeviceState deviceState = BluetoothDeviceState.disconnected;

@override
Expand Down
34 changes: 20 additions & 14 deletions ios/Classes/FlutterBluePlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ @interface FlutterBluePlugin ()
@property(nonatomic, retain) FlutterBlueStreamHandler *servicesDiscoveredStreamHandler;
@property(nonatomic, retain) FlutterBlueStreamHandler *characteristicReadStreamHandler;
@property(nonatomic, retain) FlutterBlueStreamHandler *descriptorReadStreamHandler;
@property(nonatomic, retain) FlutterBlueStreamHandler *characteristicNotifiedStreamHandler;
@property(nonatomic, retain) CBCentralManager *centralManager;
@property(nonatomic) NSMutableDictionary *scannedPeripherals;
@property(nonatomic) NSMutableArray *servicesThatNeedDiscovered;
@property(nonatomic) NSMutableArray *characteristicsThatNeedDiscovered;
@end

@implementation FlutterBluePlugin
Expand All @@ -37,11 +38,12 @@ + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
FlutterEventChannel* servicesDiscoveredChannel = [FlutterEventChannel eventChannelWithName:NAMESPACE @"/servicesDiscovered" binaryMessenger:[registrar messenger]];
FlutterEventChannel* characteristicReadChannel = [FlutterEventChannel eventChannelWithName:NAMESPACE @"/characteristicRead" binaryMessenger:[registrar messenger]];
FlutterEventChannel* descriptorReadChannel = [FlutterEventChannel eventChannelWithName:NAMESPACE @"/descriptorRead" binaryMessenger:[registrar messenger]];
FlutterEventChannel* characteristicNotifiedChannel = [FlutterEventChannel eventChannelWithName:NAMESPACE @"/characteristicNotified" binaryMessenger:[registrar messenger]];
FlutterBluePlugin* instance = [[FlutterBluePlugin alloc] init];
instance.channel = channel;
instance.centralManager = [[CBCentralManager alloc] initWithDelegate:instance queue:nil];
instance.scannedPeripherals = [NSMutableDictionary new];
instance.servicesThatNeedDiscovered = [NSMutableArray new];
instance.characteristicsThatNeedDiscovered = [NSMutableArray new];

// STATE
FlutterBlueStreamHandler* stateStreamHandler = [[FlutterBlueStreamHandler alloc] init];
Expand All @@ -68,11 +70,6 @@ + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
[descriptorReadChannel setStreamHandler:descriptorReadStreamHandler];
instance.descriptorReadStreamHandler = descriptorReadStreamHandler;

// CHARACTERISTIC NOTIFIED
FlutterBlueStreamHandler* characteristicNotifiedStreamHandler = [[FlutterBlueStreamHandler alloc] init];
[characteristicNotifiedChannel setStreamHandler:characteristicNotifiedStreamHandler];
instance.characteristicNotifiedStreamHandler = characteristicNotifiedStreamHandler;

[registrar addMethodCallDelegate:instance channel:channel];
}

Expand Down Expand Up @@ -142,6 +139,9 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
NSString *remoteId = [call arguments];
@try {
CBPeripheral *peripheral = [self findPeripheral:remoteId];
// Clear helper arrays
[_servicesThatNeedDiscovered removeAllObjects];
[_characteristicsThatNeedDiscovered removeAllObjects ];
[peripheral discoverServices:nil];
result(nil);
} @catch(FlutterError *e) {
Expand Down Expand Up @@ -386,23 +386,31 @@ - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(C
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
NSLog(@"didDiscoverServices");
// Loop through and discover characteristics and secondary services
[_servicesThatNeedDiscovered addObjectsFromArray:peripheral.services];
for(CBService *s in [peripheral services]) {
NSLog(@"Found service: %@", [s.UUID UUIDString]);
[peripheral discoverCharacteristics:nil forService:s];
[peripheral discoverIncludedServices:nil forService:s];
// [peripheral discoverIncludedServices:nil forService:s]; // Secondary services in the future (#8)
}
}

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
NSLog(@"didDiscoverCharacteristicsForService");
// Loop through and discover descriptors for characteristics
[_servicesThatNeedDiscovered removeObject:service];
[_characteristicsThatNeedDiscovered addObjectsFromArray:service.characteristics];
for(CBCharacteristic *c in [service characteristics]) {
[peripheral discoverDescriptorsForCharacteristic:c];
}
}

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
NSLog(@"didDiscoverDescriptorsForCharacteristic");
[_characteristicsThatNeedDiscovered removeObject:characteristic];
if(_servicesThatNeedDiscovered.count > 0 || _characteristicsThatNeedDiscovered.count > 0) {
// Still discovering
return;
}
// Send updated tree
if(_servicesDiscoveredStreamHandler.sink != nil) {
ProtosDiscoverServicesResult *result = [self toServicesResultProto:peripheral];
Expand All @@ -427,12 +435,10 @@ - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(C
_characteristicReadStreamHandler.sink([self toFlutterData:result]);
}
// on iOS, this method also handle notification values
if(_characteristicNotifiedStreamHandler.sink != nil) {
ProtosOnNotificationResponse *result = [[ProtosOnNotificationResponse alloc] init];
[result setRemoteId:[peripheral.identifier UUIDString]];
[result setCharacteristic:[self toCharacteristicProto:characteristic]];
_characteristicNotifiedStreamHandler.sink([self toFlutterData:result]);
}
ProtosOnNotificationResponse *result = [[ProtosOnNotificationResponse alloc] init];
[result setRemoteId:[peripheral.identifier UUIDString]];
[result setCharacteristic:[self toCharacteristicProto:characteristic]];
[_channel invokeMethod:@"OnValueChanged" arguments:[self toFlutterData:result]];
}

- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
Expand Down
5 changes: 3 additions & 2 deletions lib/src/bluetooth_device.dart
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,9 @@ class BluetoothDevice {
/// Notifies when the characteristic's value has changed.
/// setNotification() should be run first to enable them on the peripheral
Stream<List<int>> onValueChanged(BluetoothCharacteristic characteristic) {
return FlutterBlue.instance._characteristicNotifiedChannel
.receiveBroadcastStream()
return FlutterBlue.instance._methodStream
.where((m) => m.method == "OnValueChanged")
.map((m) => m.arguments)
.map((buffer) => new protos.OnNotificationResponse.fromBuffer(buffer))
.where((p) => p.remoteId == id.toString())
.map((p) => new BluetoothCharacteristic.fromProto(p.characteristic))
Expand Down
2 changes: 0 additions & 2 deletions lib/src/flutter_blue.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ class FlutterBlue {
const EventChannel('$NAMESPACE/characteristicRead');
final EventChannel _descriptorReadChannel =
const EventChannel('$NAMESPACE/descriptorRead');
final EventChannel _characteristicNotifiedChannel =
const EventChannel('$NAMESPACE/characteristicNotified');
final StreamController<MethodCall> _methodStreamController =
new StreamController.broadcast(); // ignore: close_sinks
Stream<MethodCall> get _methodStream => _methodStreamController
Expand Down

0 comments on commit 09eb37c

Please sign in to comment.