頭文件:
主要修改的地方:
- (void)didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic;
- (void)didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error;
@property (strong,nonatomic) NSMutableDictionary *connectedCharacteristicsDic;
-(void)setNotification:(BOOL)enable forCharacteristicUUID:(CBUUID *)characteristicUUID;
-(void)writeValue:(NSData *)data forCharacteristicUUID:(CBUUID *)characteristicUUID;// Type:(CBCharacteristicWriteType)type;
//
// BluetoothManager.h
// LightBlue-Objective-C
//
// Created by Deepak Sharma on 15/12/18.
// Copyright ? 2018 Insanelydeepak. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <CoreBluetooth/CoreBluetooth.h>
#import "CBUUID+Additions.h"
#import "CBService+Additions.h"
#import "CBCharacteristic+Additions.h"
#define AUTO_CANCEL_CONNECT_TIMEOUT 2
#define PeripheralNotificationKeys_DisconnectNotif @"disconnectNotif"
#define PeripheralNotificationKeys_CharacteristicNotif @"characteristicNotif"
#ifdef DEBUG
#define NSLog(fmt,...) do { \
NSString *logString = [NSString stringWithFormat:(fmt), ##__VA_ARGS__]; \
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; \
[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss.SSS"]; \
NSString *dateString = [dateFormatter stringFromDate:[NSDate date]]; \
NSString *fileName = [[NSString stringWithUTF8String:__FILE__] lastPathComponent]; \
NSLog(@"%@ %@,[%d:%s],%@", dateString,fileName,__LINE__,_cmd, logString); \
} while (0)
#else
#define NSLog(...)
#endif
@protocol IDBluetoothDelegate <NSObject>
@optional
/**
The callback function when the bluetooth has updated.
- parameter state: The newest state
*/
-(void)didUpdateState:(CBCentralManager *)central;
/**
The callback function when peripheral has been found.
- parameter peripheral: The peripheral has been found.
- parameter advertisementData: The advertisement data.
- parameter RSSI: The signal strength.
*/
-(void)didDiscoverPeripheral:(CBPeripheral *)peripheral AdvertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)rssi;
/**
The callback function when central manager connected the peripheral successfully.
- parameter connectedPeripheral: The peripheral which connected successfully.
*/
-(void)didConnectedPeripheral:(CBPeripheral *)connectedPeripheral;
/**
The callback function when central manager failed to connect the peripheral.
- parameter connectedPeripheral: The peripheral which connected failure.
- parameter error: The connected failed error message.
*/
-(void)failToConnectPeripheral:(CBPeripheral *)peripheral Error:(NSError *)error;
/**
The callback function when the services has been discovered.
- parameter peripheral: Peripheral which provide this information and contain services information
*/
-(void)didDiscoverServices:(CBPeripheral *)peripheral;
/**
The callback function when the peripheral disconnected.
- parameter peripheral: The peripheral which provide this action
*/
-(void)didDisconnectPeripheral:(CBPeripheral *)peripheral;
/**
The callback function when interrogate the peripheral is timeout
- parameter peripheral: The peripheral which is failed to discover service
*/
-(void)didFailedToInterrogate:(CBPeripheral *)peripheral;
/**
The callback function when discover characteritics successfully.
- parameter service: The service information include characteritics.
*/
-(void)didDiscoverCharacteritics:(CBService *)service;
/**
The callback function when discover characteritics successfully.
- parameter service: The service information include characteritics.
*/
-(void)didFailToDiscoverCharacteritics:(NSError *)error;
/**
The callback function when discover descriptor for characteristic successfully
- parameter characteristic: The characteristic which has the descriptor
*/
-(void)didDiscoverDescriptors:(CBCharacteristic *)characteristic;
/**
The callback function when failed to discover descriptor for characteristic
- parameter error: The error message
*/
-(void)didFailToDiscoverDescriptors:(NSError *)error;
/**
The callback function invoked when peripheral read value for the characteristic successfully
- parameter characteristic: The characteristic withe the value
*/
-(void)didReadValueForCharacteristic:(CBCharacteristic *)characteristic;
- (void)didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic;
/**
The callback function invoked when failed to read value for the characteristic
- parameter error: The error message
*/
-(void)didFailToReadValueForCharacteristic:(NSError *)error;
- (void)didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error;
@end
@interface IDBluetoothManager : NSObject <CBCentralManagerDelegate, CBPeripheralDelegate>
+(IDBluetoothManager *)sharedInstance;
@property (strong,nonatomic) CBCentralManager *manager;
@property (strong, nonatomic) id<IDBluetoothDelegate> delegate;
@property (nonatomic) BOOL connected;
@property (strong,nonatomic) NSTimer *timeoutMonitor; /// Timeout monitor of connect to peripheral
@property (strong,nonatomic) NSTimer * interrogateMonitor ; /// Timeout monitor of interrogate the peripheral
@property (strong,nonatomic) NSNotificationCenter *notifCenter;
@property (nonatomic) BOOL isConnecting;
@property (strong,nonatomic) NSString *logs;
@property (strong,nonatomic) CBPeripheral *connectedPeripheral;
@property (strong,nonatomic) NSMutableArray *connectedServices;
@property (strong,nonatomic) NSMutableDictionary *connectedCharacteristicsDic;
-(void)startScanPeripheral;
-(void)stopScanPeripheral;
-(void)disconnectPeripheral;
-(void)discoverCharacteristics;
-(void)connectPeripheral:(CBPeripheral *)peripheral;
-(void)discoverDescriptor:(CBCharacteristic *)characteristic;
-(void)setNotification:(BOOL)enable forCharacteristic:(CBCharacteristic *)characteristic;
-(void)setNotification:(BOOL)enable forCharacteristicUUID:(CBUUID *)characteristicUUID;
-(void)readValueForCharacteristic:(CBCharacteristic *)characteristic;
-(void)writeValue:(NSData *)data forCharacteristic:(CBCharacteristic *)characteristic Type:(CBCharacteristicWriteType)type;
-(void)writeValue:(NSData *)data forCharacteristicUUID:(CBUUID *)characteristicUUID;// Type:(CBCharacteristicWriteType)type;
@end
實現部分:
#import "IDBluetoothManager.h"
/// Save the single instance
static IDBluetoothManager* sharedInstance = nil;
@implementation IDBluetoothManager
+ (IDBluetoothManager*)sharedInstance{
// lazy instantiation
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[IDBluetoothManager alloc] init];
});
return sharedInstance;
}
- (id)init{
self = [super init];
if (self) {
[self initCBCentralManager];
}
return self;
}
#pragma mark - Custom functions
/**
Initialize CBCentralManager instance
*/
-(void)initCBCentralManager{
_connected = false;
_isConnecting = false;
_connectedServices = [NSMutableArray array];
_notifCenter = [NSNotificationCenter defaultCenter];
NSDictionary *dic = @{CBCentralManagerOptionShowPowerAlertKey:[NSNumber numberWithBool:false]};
_manager = [[CBCentralManager alloc]
initWithDelegate:self
queue:nil
options:dic];
}
/**
Singleton pattern method
- returns: Bluetooth single instance
*/
/**
The method provides for starting scan near by peripheral
*/
-(void)startScanPeripheral{
[_manager scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey:[NSNumber numberWithBool:true]}];
// [_manager scanForPeripheralsWithServices:[NSArray arrayWithObject:[CBUUID UUIDWithString:@"1910"]] options:nil];
}
/**
The method provides for stopping scan near by peripheral
*/
-(void)stopScanPeripheral{
[_manager stopScan];
}
/**
The method provides for connecting the special peripheral
- parameter peripher: The peripheral you want to connect
*/
-(void)connectPeripheral:(CBPeripheral *)peripheral{
if (!_isConnecting) {
_isConnecting = true;
[_manager connectPeripheral:peripheral options:@{CBConnectPeripheralOptionNotifyOnDisconnectionKey:[NSNumber numberWithBool:true]}];
_timeoutMonitor = [NSTimer scheduledTimerWithTimeInterval:AUTO_CANCEL_CONNECT_TIMEOUT target:self selector:@selector(connectTimeout:) userInfo:peripheral repeats:false];
}
}
/**
The method provides for disconnecting with the peripheral which has connected
*/
-(void)disconnectPeripheral{
if (_connectedPeripheral != nil) {
[_manager cancelPeripheralConnection:_connectedPeripheral];
[self startScanPeripheral];
_connectedPeripheral = nil;
}
}
/**
The method provides for the user who want to obtain the descriptor
- parameter characteristic: The character which user want to obtain descriptor
*/
-(void)discoverDescriptor:(CBCharacteristic *)characteristic{
if (_connectedPeripheral != nil) {
[_connectedPeripheral discoverDescriptorsForCharacteristic:characteristic];
}
}
/**
The method is invoked when connect peripheral is timeout
- parameter timer: The timer touch off this selector
*/
-(void)connectTimeout:(NSTimer *)timer{
if (_isConnecting) {
_isConnecting = false;
CBPeripheral *peripheral = [timer userInfo];
[self connectPeripheral:peripheral];
_timeoutMonitor = nil;
}
}
/**
This method is invoked when interrogate peripheral is timeout
- parameter timer: The timer touch off this selector
*/
-(void)integrrogateTimeout:(NSTimer *)timer{
[self disconnectPeripheral];
CBPeripheral *peripheral = [timer userInfo];
if (_delegate && [(id)_delegate respondsToSelector:@selector(didFailedToInterrogate:)]) {
[_delegate didFailedToInterrogate:peripheral];
}
}
/**
This method provides for discovering the characteristics.
*/
-(void)discoverCharacteristics{
if (_connectedPeripheral == nil) {
return;
}
NSArray<CBService *> *services =_connectedPeripheral.services;
if (services == nil || services.count < 1 ){ // Validate service array
return;
}
for (CBService *service in services){
[_connectedPeripheral discoverCharacteristics:nil forService:service];
}
}
/**
Read characteristic value from the peripheral
- parameter characteristic: The characteristic which user should
*/
-(void)readValueForCharacteristic:(CBCharacteristic *)characteristic{
if (_connectedPeripheral == nil) {
return;
}
[_connectedPeripheral readValueForCharacteristic:characteristic];
}
/**
Start or stop listening for the value update action
- parameter enable: If you want to start listening, the value is true, others is false
- parameter characteristic: The characteristic which provides notifications
*/
-(void)setNotification:(BOOL)enable forCharacteristic:(CBCharacteristic *)characteristic{
if (_connectedPeripheral == nil) {
return;
}
NSLog(@"setNotification:>>value = %d",enable);
[_connectedPeripheral setNotifyValue:enable forCharacteristic:characteristic];
}
-(void)setNotification:(BOOL)enable forCharacteristicUUID:(CBUUID *)characteristicUUID {
if (_connectedCharacteristicsDic) {
CBCharacteristic *characteristic = [_connectedCharacteristicsDic objectForKey:characteristicUUID];
if (characteristic) {
[_connectedPeripheral setNotifyValue:enable forCharacteristic:characteristic];
} else {
}
} else {
}
}
/**
Write value to the peripheral which is connected
- parameter data: The data which will be written to peripheral
- parameter characteristic: The characteristic information
- parameter type: The write of the operation
*/
-(void)writeValue:(NSData *)data forCharacteristic:(CBCharacteristic *)characteristic Type:(CBCharacteristicWriteType)type{
if (_connectedPeripheral == nil) {
return;
}
NSLog(@"write data to ble:%@",data);
[_connectedPeripheral writeValue:data forCharacteristic:characteristic type:type];
}
-(void)writeValue:(NSData *)data forCharacteristicUUID:(CBUUID *)characteristicUUID {
CBCharacteristic *characteristic = [self.connectedCharacteristicsDic objectForKey:characteristicUUID];
CBCharacteristicProperties properties = characteristic.properties;
CBCharacteristicWriteType type = CBCharacteristicWriteWithResponse;
if (properties & CBCharacteristicPropertyWriteWithoutResponse > 0) {
type = CBCharacteristicWriteWithoutResponse;
} else {
type = CBCharacteristicWriteWithResponse;
}
[_connectedPeripheral writeValue:data forCharacteristic:characteristic type:type];
}
#pragma mark - Delegate
/**
Invoked whenever the central manager's state has been updated.
*/
- (void)centralManagerDidUpdateState:(nonnull CBCentralManager *)central {
// Determine the state of the peripheral
switch ([central state]) {
case CBCentralManagerStatePoweredOff:
NSLog(@"State : Powered Off");
break;
case CBCentralManagerStatePoweredOn:
NSLog(@"State : Powered On");
break;
case CBCentralManagerStateResetting:
NSLog(@"State : Resetting");
break;
case CBCentralManagerStateUnauthorized:
NSLog(@"State : Unauthorized");
break;
case CBCentralManagerStateUnknown:
NSLog(@"State : Unknown");
break;
case CBCentralManagerStateUnsupported:
NSLog(@"State : Unsupported");
break;
}
if (_delegate && [(id)_delegate respondsToSelector:@selector(didUpdateState:)]) {
[_delegate didUpdateState:central];
}
}
/**
This method is invoked while scanning, upon the discovery of peripheral by central
- parameter central: The central manager providing this update.
- parameter peripheral: The discovered peripheral.
- parameter advertisementData: A dictionary containing any advertisement and scan response data.
- parameter RSSI: The current RSSI of peripheral, in dBm. A value of 127 is reserved and indicates the RSSI
* was not available.
*/
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{
// NSLog(@"discover peripheral: %@; advertisementData: %@; RSSI: %@", peripheral, advertisementData, RSSI);
NSLog(@"Bluetooth Manager --> didDiscoverPeripheral:%@ RSSI:%@", peripheral.name, RSSI);
if (_delegate && [(id)_delegate respondsToSelector:@selector(didDiscoverPeripheral:AdvertisementData:RSSI:)]) {
[_delegate didDiscoverPeripheral:peripheral AdvertisementData:advertisementData RSSI:RSSI];
}
}
/**
This method is invoked when a connection succeeded
- parameter central: The central manager providing this information.
- parameter peripheral: The peripheral that has connected.
*/
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
NSLog(@"Bluetooth Manager --> didConnectPeripheral: %@",peripheral.name);
_isConnecting = false;
if (_timeoutMonitor != nil) {
[_timeoutMonitor invalidate];
_timeoutMonitor = nil;
}
_connected = true;
_connectedPeripheral = peripheral;
if (_delegate && [(id)_delegate respondsToSelector:@selector(didConnectedPeripheral:)]) {
[_delegate didConnectedPeripheral:peripheral];
}
[self stopScanPeripheral];
peripheral.delegate = self;
[peripheral discoverServices:nil];
_interrogateMonitor = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(integrrogateTimeout:) userInfo:peripheral repeats:false];
}
/**
This method is invoked where a connection failed.
- parameter central: The central manager providing this information.
- parameter peripheral: The peripheral that you tried to connect.
- parameter error: The error infomation about connecting failed.
*/
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
NSLog(@"Bluetooth Manager --> didFailToConnectPeripheral");
_isConnecting = false;
if (_timeoutMonitor != nil) {
[_timeoutMonitor invalidate];
_timeoutMonitor = nil;
}
_connected = false;
if (_delegate && [(id)_delegate respondsToSelector:@selector(failToConnectPeripheral:Error:)]) {
[_delegate failToConnectPeripheral:peripheral Error:error];
}
}
/**
The method is invoked where services were discovered.
- parameter peripheral: The peripheral with service informations.
- parameter error: Errot message when discovered services.
*/
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
NSLog(@"Bluetooth Manager --> didDiscoverServices");
_connectedPeripheral = peripheral;
if (error != nil) {
NSLog(@"Bluetooth Manager --> Discover Services Error, error:%@",error.localizedDescription);
return ;
}
// If discover services, then invalidate the timeout monitor
if (_interrogateMonitor != nil) {
[_interrogateMonitor invalidate];
_interrogateMonitor = nil;
}
if (_delegate && [(id)_delegate respondsToSelector:@selector(didDiscoverServices:)]) {
[_delegate didDiscoverServices:peripheral];
}
}
/**
The method is invoked where characteristics were discovered.
- parameter peripheral: The peripheral provide this information
- parameter service: The service included the characteristics.
- parameter error: If an error occurred, the cause of the failure.
*/
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
NSLog(@"Bluetooth Manager --> didDiscoverCharacteristicsForService");
_connectedPeripheral = peripheral;
if (error != nil) {
NSLog(@"Bluetooth Manager --> Fail to discover characteristics! Error:%@",error.localizedDescription);
if (_delegate && [(id)_delegate respondsToSelector:@selector(didFailToDiscoverCharacteritics:)]) {
[_delegate didFailToDiscoverCharacteritics:error];
}
return ;
}
if (_connectedCharacteristicsDic == nil) {
_connectedCharacteristicsDic = [NSMutableDictionary dictionary];
}
for (CBCharacteristic *cbchara in service.characteristics) {
[_connectedCharacteristicsDic setObject:cbchara forKey:cbchara.UUID];
}
if (_delegate && [(id)_delegate respondsToSelector:@selector(didDiscoverCharacteritics:)]) {
[_delegate didDiscoverCharacteritics:service];
}
}
/**
This method is invoked when the peripheral has found the descriptor for the characteristic
- parameter peripheral: The peripheral providing this information
- parameter characteristic: The characteristic which has the descriptor
- parameter error: The error message
*/
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
NSLog(@"Bluetooth Manager --> didDiscoverDescriptorsForCharacteristic");
if (error != nil) {
NSLog(@"Bluetooth Manager --> Fail to discover descriptor for characteristic Error:%@",error.localizedDescription);
if (_delegate && [(id)_delegate respondsToSelector:@selector(didFailToDiscoverDescriptors:)]) {
[_delegate didFailToDiscoverDescriptors:error];
}
return;
}
if (_delegate && [(id)_delegate respondsToSelector:@selector(didDiscoverDescriptors:)]) {
[_delegate didDiscoverDescriptors:characteristic];
}
}
/**
This method is invoked when the peripheral has been disconnected.
- parameter central: The central manager providing this information
- parameter peripheral: The disconnected peripheral
- parameter error: The error message
*/
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
NSLog(@"Bluetooth Manager --> didDisconnectPeripheral");
_connected = false;
if (_delegate && [(id)_delegate respondsToSelector:@selector(didDisconnectPeripheral:)]) {
[_delegate didDisconnectPeripheral:peripheral];
}
[_notifCenter postNotificationName:PeripheralNotificationKeys_DisconnectNotif object:self];
}
/**
Thie method is invoked when the user call the peripheral.readValueForCharacteristic
- parameter peripheral: The periphreal which call the method
- parameter characteristic: The characteristic with the new value
- parameter error: The error message
*/
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
NSLog(@"Bluetooth Manager --> didUpdateValueForCharacteristic, %@:>%@",characteristic.UUID.UUIDString, characteristic.value);
if (error){
NSLog(@"Bluetooth Manager --> Failed to read value for the characteristic. Error:%@",error.localizedDescription);
if (_delegate && [(id)_delegate respondsToSelector:@selector(didFailToReadValueForCharacteristic:)]) {
[_delegate didFailToReadValueForCharacteristic:error];
}
return;
}
NSLog(@"_delegate:>%@",_delegate);
if (_delegate && [_delegate respondsToSelector:@selector(didReadValueForCharacteristic:)]) {
[_delegate didReadValueForCharacteristic:characteristic];
}
}
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
NSLog(@">>>Bluetooth Manager --> didUpdateNotificationStateForCharacteristic, %@:>%@,isnotify:%d error:%@",characteristic.UUID.UUIDString, characteristic.value,characteristic.isNotifying, error);
if (_delegate && [_delegate respondsToSelector:@selector(didUpdateNotificationStateForCharacteristic:)]) {
[_delegate didUpdateNotificationStateForCharacteristic:characteristic];
}
}
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
NSLog(@">>>Bluetooth Manager --> didWriteValueForCharacteristic, %@:>%@, error:%@",characteristic.UUID.UUIDString, characteristic.value, error);
if (_delegate && [_delegate respondsToSelector:@selector(didWriteValueForCharacteristic:error:)]) {
[_delegate didWriteValueForCharacteristic:characteristic error:error];
}
}
@end
以下是應用場景:
image.png
代碼說明:
在添加藍牙設備后發送指令讓設備返回設備信息。
步驟:添加,使能notify,寫入指令,接收信息。