#import "FlutterBluetoothBasicPlugin.h" #import "ConnecterManager.h" @interface FlutterBluetoothBasicPlugin () @property(nonatomic, retain) NSObject *registrar; @property(nonatomic, retain) FlutterMethodChannel *channel; @property(nonatomic, retain) BluetoothPrintStreamHandler *stateStreamHandler; @property(nonatomic) NSMutableDictionary *scannedPeripherals; @end @implementation FlutterBluetoothBasicPlugin + (void)registerWithRegistrar:(NSObject*)registrar { FlutterMethodChannel* channel = [FlutterMethodChannel methodChannelWithName:NAMESPACE @"/methods" binaryMessenger:[registrar messenger]]; FlutterEventChannel* stateChannel = [FlutterEventChannel eventChannelWithName:NAMESPACE @"/state" binaryMessenger:[registrar messenger]]; FlutterBluetoothBasicPlugin* instance = [[FlutterBluetoothBasicPlugin alloc] init]; instance.channel = channel; instance.scannedPeripherals = [NSMutableDictionary new]; // STATE BluetoothPrintStreamHandler* stateStreamHandler = [[BluetoothPrintStreamHandler alloc] init]; [stateChannel setStreamHandler:stateStreamHandler]; instance.stateStreamHandler = stateStreamHandler; [registrar addMethodCallDelegate:instance channel:channel]; } - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { NSLog(@"call method -> %@", call.method); if ([@"state" isEqualToString:call.method]) { result(nil); } else if([@"isAvailable" isEqualToString:call.method]) { result(@(YES)); } else if([@"isConnected" isEqualToString:call.method]) { result(@(NO)); } else if([@"isOn" isEqualToString:call.method]) { result(@(YES)); }else if([@"startScan" isEqualToString:call.method]) { NSLog(@"getDevices method -> %@", call.method); [self.scannedPeripherals removeAllObjects]; if (Manager.bleConnecter == nil) { [Manager didUpdateState:^(NSInteger state) { switch (state) { case CBCentralManagerStateUnsupported: NSLog(@"The platform/hardware doesn't support Bluetooth Low Energy."); break; case CBCentralManagerStateUnauthorized: NSLog(@"The app is not authorized to use Bluetooth Low Energy."); break; case CBCentralManagerStatePoweredOff: NSLog(@"Bluetooth is currently powered off."); break; case CBCentralManagerStatePoweredOn: [self startScan]; NSLog(@"Bluetooth power on"); break; case CBCentralManagerStateUnknown: default: break; } }]; } else { [self startScan]; } result(nil); } else if([@"stopScan" isEqualToString:call.method]) { [Manager stopScan]; result(nil); } else if([@"connect" isEqualToString:call.method]) { NSDictionary *device = [call arguments]; @try { NSLog(@"connect device begin -> %@", [device objectForKey:@"name"]); CBPeripheral *peripheral = [_scannedPeripherals objectForKey:[device objectForKey:@"address"]]; self.state = ^(ConnectState state) { [self updateConnectState:state]; }; [Manager connectPeripheral:peripheral options:nil timeout:2 connectBlack: self.state]; result(nil); } @catch(FlutterError *e) { result(e); } } else if([@"disconnect" isEqualToString:call.method]) { @try { [Manager close]; result(nil); } @catch(FlutterError *e) { result(e); } } else if([@"writeData" isEqualToString:call.method]) { @try { NSDictionary *args = [call arguments]; NSMutableArray *bytes = [args objectForKey:@"bytes"]; NSNumber* lenBuf = [args objectForKey:@"length"]; int len = [lenBuf intValue]; char cArray[len]; for (int i = 0; i < len; ++i) { // NSLog(@"** ind_%d (d): %@, %d", i, bytes[i], [bytes[i] charValue]); cArray[i] = [bytes[i] charValue]; } NSData *data2 = [NSData dataWithBytes:cArray length:sizeof(cArray)]; // NSLog(@"bytes in hex: %@", [data2 description]); [Manager write:data2]; result(nil); } @catch(FlutterError *e) { result(e); } } } -(void)startScan { [Manager scanForPeripheralsWithServices:nil options:nil discover:^(CBPeripheral * _Nullable peripheral, NSDictionary * _Nullable advertisementData, NSNumber * _Nullable RSSI) { if (peripheral.name != nil) { NSLog(@"find device -> %@", peripheral.name); [self.scannedPeripherals setObject:peripheral forKey:[[peripheral identifier] UUIDString]]; NSDictionary *device = [NSDictionary dictionaryWithObjectsAndKeys:peripheral.identifier.UUIDString,@"address",peripheral.name,@"name",nil,@"type",nil]; [_channel invokeMethod:@"ScanResult" arguments:device]; } }]; } -(void)updateConnectState:(ConnectState)state { dispatch_async(dispatch_get_main_queue(), ^{ NSNumber *ret = @0; switch (state) { case CONNECT_STATE_CONNECTING: NSLog(@"status -> %@", @"Connecting ..."); ret = @0; break; case CONNECT_STATE_CONNECTED: NSLog(@"status -> %@", @"Connection success"); ret = @1; break; case CONNECT_STATE_FAILT: NSLog(@"status -> %@", @"Connection failed"); ret = @0; break; case CONNECT_STATE_DISCONNECT: NSLog(@"status -> %@", @"Disconnected"); ret = @0; break; default: NSLog(@"status -> %@", @"Connection timed out"); ret = @0; break; } NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:ret,@"id",nil]; if(_stateStreamHandler.sink != nil) { self.stateStreamHandler.sink([dict objectForKey:@"id"]); } }); } @end @implementation BluetoothPrintStreamHandler - (FlutterError*)onListenWithArguments:(id)arguments eventSink:(FlutterEventSink)eventSink { self.sink = eventSink; return nil; } - (FlutterError*)onCancelWithArguments:(id)arguments { self.sink = nil; return nil; } @end