Github.com/djlovettt/B…

.h

#import <Foundation/Foundation.h>
#import <CoreBluetooth/CoreBluetooth.h>NS_ASSUME_NONNULL_BEGIN typedef void(^ScanDevicesBlock)(NSArray <CBPeripheral *> *devices); typedef void(^ConnectResultBlock)(CBPeripheral * _Nullable peripheral); typedef void(^ReceiveDataBlock)(NSDictionary *data); typedef void(^ErrorMsgBlock)(NSString *errorMsg); @property (copy, nonatomic) ScanDevicesBlock ScanDevicesBlock; @property (copy, nonatomic) ConnectResultBlock ConnectResultBlock; @Property (copy, nonatomic) ReceiveDataBlock ReceiveDataBlock; /// error callback @property (copy, nonatomic) ErrorMsgBlock ErrorMsgBlock; @property (assign, nonatomic) NSTimeInterval connectionDuration; // initialize + (instanceType)sharedInstance; - (instancetype)init __attribute__((unavailable("Use BleManager.sharedInstance")));
+ (instancetype)new  __attribute__((unavailable("Use BleManager.sharedInstance"))); // retrieve device - (void)scanPeripherals; // stop search - (void)stopScan; /// @param peripheral bluetooth device - (void)connectPeripheral:(CBPeripheral *)peripheral; Disconnected / / / / / / @ param peripheral bluetooth device - (void) cancelPeripheralConnection (CBPeripheral *) peripheral; /// @param data data to be written - (void)writeValue:(NSData *)data; @end NS_ASSUME_NONNULL_ENDCopy the code

.m

#import "BleManager.h"@interface BleManager() <CBCentralManagerDelegate,CBPeripheralDelegate> @property (strong, nonatomic) CBCentralManager *centralManager; @property (strong, nonatomic) CBPeripheral *connectingPeripheral; @property (strong, nonatomic) CBCharacteristic *writeValueCharacteristic; @property (strong, nonatomic) NSTimer *connectionTimer; @property (strong, nonatomic) NSArray <CBUUID *> *targetPeripheralUUIDs; @property (strong, nonatomic) NSMutableArray <NSData *> *waitingToAppendDatas; @property (strong, nonatomic) NSMutableArray <CBPeripheral *> *discoverdDevices; @implementation BleManager static BleManager *manager = nil; + (instancetype)sharedInstance { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ manager = [[BleManager alloc] init]; [manager initObjects]; });returnmanager; } /// retrieve the device - (void)scanPeripherals {if(self.centralManager.state ! = CBManagerStatePoweredOn) { [self errorMsgCallBack:@"Bluetooth is not available"];
        return;
    }
    [self.discoverdDevices removeAllObjects];
    if(self.scanDevicesBlock) { self.scanDevicesBlock(self.discoverdDevices); } [self.centralManager scanForPeripheralsWithServices:self.targetPeripheralUUIDs options:nil]; } /// stop search - (void)stopScan {[self.centralManager stopScan]; } /// @param peripheral bluetooth device - (void)connectPeripheral:(CBPeripheral *)peripheral {if(! peripheral) { [self errorMsgCallBack:@"Please check connection status with Bluetooth device"];
        return;
    }
    NSLog(@"BleManager --> About to establish connection with %@", peripheral); [self.centralManager connectPeripheral:peripheral options:nil]; // start the connection timerif(! self.connectionTimer) { __weak typeof(self) weakSelf = self; self.connectionTimer = [NSTimer scheduledTimerWithTimeInterval:self.connectionDuration repeats:NO block:^(NSTimer * _Nonnull timer) {if(! weakSelf.connectingPeripheral) { [weakSelf cancelPeripheralConnection:peripheral]; [weakSelf errorMsgCallBack:@"Connection failed. Please try again."];
            }
            [weakSelf invalidateConnectionTimer];
        }];
        [[NSRunLoop mainRunLoop] addTimer:self.connectionTimer forMode:NSRunLoopCommonModes]; Disconnected}} / / / / / / @ param peripheral bluetooth device - (void) cancelPeripheralConnection: (peripheral CBPeripheral *) {if(! peripheral) { [self errorMsgCallBack:@"No connected device"];
        return;
    }
    NSLog(@"BleManager --> About to disconnect from %@", peripheral); [self.centralManager cancelPeripheralConnection:peripheral]; } /// write data /// @param data data to be written - (void)writeValue:(NSData *)data {NSLog(@"BleManager --> Ready to send data %@", [self dataToDictionary:data]);
    
    if(! data.length) { NSLog(@"BleManager --> Failed to send data, pending data cannot be empty");
        [self errorMsgCallBack:@"Data to be sent is empty"];
        return;
    }
    if(! self.connectingPeripheral) { NSLog(@"BleManager --> Failed to send data, no connecting device");
        [self errorMsgCallBack:@"No connected device"];
        return;
    }
    if(! self.writeValueCharacteristic) { NSLog(@"BleManager --> Failed to send data, no writable eigenvalues");
        [self errorMsgCallBack:@"Unable to write data to Bluetooth device"];
        return;
    }
    [self.connectingPeripheral writeValue:data forCharacteristic:self.writeValueCharacteristic type:CBCharacteristicWriteWithResponse];
}

#pragma mark -

- (void)centralManagerDidUpdateState:(nonnull CBCentralManager *)central {
    
    switch (central.state) {
        case CBManagerStateResetting:
            [self errorMsgCallBack:@"Bluetooth reset"];
            [self stopScan];
            break;
        case CBManagerStateUnsupported:
            [self errorMsgCallBack:@"Device does not support Bluetooth"];
            break;
        case CBManagerStateUnauthorized:
            NSLog(@"BleManager --> Unauthorized...");
            [self errorMsgCallBack:@"Please enable Bluetooth access."];
            break;
        case CBManagerStatePoweredOff:
            NSLog(@"BleManager --> Bluetooth is not enabled...");
            [self errorMsgCallBack:@"Bluetooth enabled, please."];
            break;
        case CBManagerStatePoweredOn:
            NSLog(@"BleManager --> Bluetooth enabled...");
            break;
        default:
            // CBManagerStateUnknown
            NSLog(@"BleManager --> Unknown error...");
            [self errorMsgCallBack:@"Unknown error, please restart Bluetooth."];
            break; } } - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral AdvertisementData :(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI {// the device is retrievedif(peripheral.name.length && ! [self.discoverdDevices containsObject:peripheral]) { [self.discoverdDevices addObject:peripheral];if (self.scanDevicesBlock) {
            self.scanDevicesBlock(self.discoverdDevices);
        }
    }
}

- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
    
    NSLog(@"BleManager --> didConnectPeripheral -> %@", peripheral); / / connected self. ConnectingPeripheral = peripheral; // start to discover services self.connectingPeripheral.delegate = self; [self.connectingPeripheral discoverServices:nil]; } - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error { NSLog(@"BleManager --> didFailToConnectPeripheral -> %@", peripheral); / / connection failure self. ConnectingPeripheral = nil; self.writeValueCharacteristic = nil;if(self.connectResultBlock) { self.connectResultBlock(nil); [self invalidateConnectionTimer]; } } - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError  *)error { NSLog(@"BleManager --> didDisconnectPeripheral -> %@", peripheral); / / disconnected self. ConnectingPeripheral = nil; self.writeValueCharacteristic = nil; } - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {// discover the servicefor (CBService *service in peripheral.services) {
        // start to discover characteristics
        NSLog(@"BleManager --> didDiscoverServices -> %@", service);
        [self.connectingPeripheral discoverCharacteristics:nil forService:service]; } } - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service Error :(NSError *)error {// find eigenvaluesfor (CBCharacteristic *characteristic in service.characteristics) {
        NSLog(@"BleManager --> didDiscoverCharacteristicsForService -> %@", characteristic); // Write data eigenvaluesif ([characteristic.UUID.UUIDString isEqualToString:@"* * *"]) { self.writeValueCharacteristic = characteristic; // The device is successfully connected after the writable eigenvalue is detectedif (self.connectResultBlock) {
                [self invalidateConnectionTimer];
                self.connectResultBlock(peripheral);
            }
            NSLog(@"BleManager --> Writable eigenvalue %@ found", self.writeValueCharacteristic); } // Listen for data eigenvaluesif ([characteristic.UUID.UUIDString isEqualToString:@"* * *"]) {
            
            [self.connectingPeripheral setNotifyValue:YES forCharacteristic:characteristic];
            [self.connectingPeripheral readValueForCharacteristic:characteristic]; } } } - (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic Error :(NSError *)error {// write the instruction NSLog(@) to an eigenvalue"BleManager --> didWriteValueForCharacteristic -> %@ %@", characteristic, [self dataToDictionary:characteristic.value]);
    if (error) {
        [self errorMsgCallBack:@"Data write failure"];
    }
}

- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
    
    if(! characteristic.value.length) {return; } // The data returned by an eigenvalue is received NSLog(@"BleManager --> didUpdateValueForCharacteristic -> %@ %@", characteristic, [self dataToDictionary:characteristic.value]); // Data verification failedif(! [self checkData:characteristic.value]) { NSLog(@"BleManager --> Incomplete data received, waiting for stitching");
        [self.waitingToAppendDatas addObject:characteristic.value];
        return;
    }
    
    NSMutableData *fullData = [[NSMutableData alloc] init];
    if(self. WaitingToAppendDatas. Count) {/ / if any incomplete data, the data splicingfor (NSData *waitToAppendData in self.waitingToAppendDatas) {
            [fullData appendData:waitToAppendData];
        }
    }
    [fullData appendData:characteristic.value];
    
    if(self. ReceiveDataBlock) {/ / after complete data transfer, empty for splicing data [self. WaitingToAppendDatas removeAllObjects]; self.receiveDataBlock([self dataToDictionary:fullData]); }}#pragma mark -- (BOOL)checkData:(NSData *)data {NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"BleManager --> checkDataIntegrity %@", jsonString);
    
    return [jsonString hasSuffix:@"}}"]; // @param data - (NSDictionary *)dataToDictionary:(NSData *)data {// @param data - (NSDictionary *)dataToDictionary:(NSData *)data {if(! data.length) {return nil; }
    
    NSString *receiveString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"dataToDictionary --> %@", receiveString);
    if(! receiveString) {return nil;
    }
    NSData *encodingData = [receiveString dataUsingEncoding:NSUTF8StringEncoding];
    NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:encodingData options:NSJSONReadingMutableLeaves error:nil];
    return dictionary;
}

#pragma mark -// initialize - (void)initObjects {self.connectionDuration = 5.0; self.discoverdDevices = [[NSMutableArray alloc] init]; self.waitingToAppendDatas = [[NSMutableArray alloc] init]; self.targetPeripheralUUIDs = @[[CBUUID UUIDWithString:@"* * *"], [CBUUID UUIDWithString:@"* * *"]]. self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue() options:nil]; // @param connectionDuration Maximum connectionDuration - (void)setConnectionDuration:(NSTimeInterval)connectionDuration { _connectionDuration = connectionDuration; } / / / cancellation in the timer - (void) invalidateConnectionTimer {[self. ConnectionTimer invalidate]; self.connectionTimer = nil; } /// error callback // @param error error message - (void)errorMsgCallBack:(NSString *)error {if(! error.length) {return; }
    
    if (self.errorMsgBlock) {
        self.errorMsgBlock(error);
    }
}

@end
Copy the code