iOS蓝牙开发--对接体温枪

最近做的育儿项目,需要iOS设备对接蓝牙体温枪,以前没有做过,现在已经完成了基本功能,现在记录下过程,以备以后查看.

说明:

参考文章:
【译】iOS蓝牙编程指南 -- 核心蓝牙概述 - 简书
【iOS官方文档翻译】iOS的蓝牙连接、数据接收及发送 - dolacmeng的专栏 - 博客频道 - CSDN.NET
文档中涉及一些名词:Central(中心设备)、Peripheral(外围设备)、advertising(广告)、Services(服务)、Characteristic(特征)等.具体下面解释.

开发步骤:

步骤1.建立一个Central Manager实例进行蓝牙管理
步骤2.搜索外围设备
步骤3.连接外围设备
步骤4.获得外围设备的服务
步骤5.获得服务的特征
步骤6.从外围设备读数据(直接读取和订阅两种方法)
步骤7.给外围设备发送数据

具体流程:

步骤一.开启Central Manager

CBCentralManager 是Core Bluetooth的一个对象,代表一个本地中心设备,在使用任何蓝牙传输前,你必须给CBCentralManager实例分配内存和初始化。可以通过CBCentralManager类的initWithDelegate:queue:options:方法:

myCentralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:nil];

在这个例子中,self会被设置为接收所有中心设备角色的事件的代理,设置dispatch queue为nil后,central manager会通过主线程来处理这些事件。ViewController需要实现CBCentralManagerDelegate,CBPeripheralDelegate这两个代理
当创建了一个central manager,会回调代理的centralManagerDidUpdateState:方法,你必须实现这个代理方法来确定中心设备是否支持BLE以及是否可用。

步骤二.搜索正在广告的外围设备

中心设备的第一个任务是搜索你的APP可以连接的外围设备,正如上一篇文章中提到的,广告(advertising)是外围设备使其被周围设备发现的主要方法,你可以通过CBCentralManager类的scanForPeripheralsWithServices:options:方法,搜索任何正在广告的外围设备:

[myCentralManager scanForPeripheralsWithServices:nil options:nil];

你调用了scanForPeripheralsWithServices:options:方法来搜索可连接的外围设备后,central manager 在每次搜索到一个外围设备都会回调其代理的centralManager:didDiscoverPeripheral:advertisementData:RSSI:方法。任何被搜索到的外围设备都以CBPeripheral类的方式返回。像下面的代码,你可以实现这个代理方法来罗列出所有被搜索到的蓝牙设备:

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData
RSSI:(NSNumber *)RSSI {
   NSLog(@"Discovered %@", peripheral.name);
...

当你已经找到了一个你需要连接的外围设备,停止搜索其它设备来节省电量。

[myCentralManager stopScan];
NSLog(@"Scanning stopped”);

步骤三.连接一个你搜索到并希望连接的外围设备

在你搜索到一个外围设备,并且它广告了你需要的服务,你可以请求和这个外围设备连接,通过调用CBCentralManager类的connectPeripheral:options:方法,简而言之,调用这个方法并且说明你需要连接的外围设备:

[myCentralManager connectPeripheral:peripheral options:nil];

假设连接成功了,central manager 会回调其代理方法[centralManager:
didConnectPeripheral:],你可以实现这个方法来打印“外围设备连接”:

- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
    NSLog(@"Peripheral connected");
...

在你开始和外围设备交互之前,你应该设置外围设备的代理以确保它能接收合适的回调,像这样

peripheral.delegate = self;

步骤四.搜索你已经连接的外围设备的服务

在你与外围设备建立连接之后,你可以开始勘察它的数据。第一步是勘察外围设备提供了什么服务,因为外围设备广告的数据有大小限制,你或许会发现外围设备提供比它广告的还有更多服务。你可以通过CBPeripheral类的discoverServices:方法来发现一个外围设备提供的所有服务:

[peripheral discoverServices:nil];

当发现了具体的服务,外围设备(已经连接的CBPeripheral类)会回调其代理的peripheral:didDiscoverServices:方法。Core Bluetooth 建立CBService类的array数组——存储外围设备的每一个服务。像下面的代码,你可以实现这个代理方法来获得发现的服务列表:

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
     for (CBService *service in peripheral.services) {
          NSLog(@"Discovered service %@", service);
...
}
…

步骤五.搜索服务的特征

假定你已经找到了你需要的服务,下一步就是探索服务的所有“特征”(characteristics),搜索一个服务的所有特征只要调用CBPeripheral类的discoverCharacteristics:forService:方法,参数为具体的服务:

NSLog(@"Discovering characteristics for service %@", interestingService);
[peripheral discoverCharacteristics:nil forService:interestingService];

当发现了指定服务的特征,外围设备会回调peripheral:didDiscoverCharact
eristicsForService:error:
代理方法。Core Bluetooth建立存储CBCharacteristic实例的array数组———每一个都代表一个发现了的特征。下面的示例就是实现这个代理方法来简单地打印每个发现了的特征:

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service
error:(NSError *)error {
      for (CBCharacteristic *characteristic in service.characteristics) {
      NSLog(@"Discovered characteristic %@", characteristic);
...
}
...

步骤六.取得特征的值(就是从外围设备取数据)

一个特征包含一个代表外围设备服务的简单值,例如,有一个健康温度计服务,这个服务有一个温度测量特征,而这个特征有一个摄氏温度的值,你可以直接读取或者订阅这个特征来取得这个特征对应的值。
6.1直接读取特征的值
你得到你希望得到的服务的某个特征后,你可以通过调用CBPeripheral类的readValueForCharacteristic:方法来读取这个特征对应的值,参数为需要读取的特征:

NSLog(@"Reading value for characteristic %@", interestingCharacteristic);
[peripheral readValueForCharacteristic:interestingCharacteristic];

当你试图去读一个特征对应的值,外围设备会回调它的代理方法peripheral:didUpdateValueForCharacteristic:error:去取值,如果值成功返回,你可以通过特征的value属性来获得它:

- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic
error:(NSError *)error {
      NSData *data = characteristic.value;
      // parse the data as needed
...

6.2订阅一个特征的值
在某些使用情况下,通过readValueForCharacteristic:读取一个特征的值会很有效率,但是这不是获得值改变的最有效率方法,对于大部分特征值的改变——例如,你在给定时间的心率,你应该通过订阅来获得它。当你订阅了一个特征的值,你可以在值改变的时候接收到通知。你可以通过CBPeripheral类的setNotifyValue:forCharacteristic:方法来订阅你需要的特征,参数为YES,以及需要订阅的特征:

[peripheral setNotifyValue:YES forCharacteristic:interestingCharacteristic];

当你试图去订阅(或取消订阅)一个特征时,外围设备会调用 它的代理的peripheral:didUpdateNotificationStateForCharacteristic:error:方法,如果订阅请求失败,你可以通过实现这个方法来获得错误原因:

- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic
error:(NSError *)error {
    if (error) {
       NSLog(@"Error changing notification state: %@",
       [error localizedDescription]);
}
...

当你成功订阅了某个特征,在特征的值改变时,外围设备会通知你的app,每次值改变,外围设备会调用 其代理的peripheral:didUpdateValueForCharacteristic
:error:
方法。你可以通过实现这个方法来获得改变的值,这个方法和上面直接读取时回调的方法一样。

步骤七.写值到特征中(就是发数据给外围设备)

在某些使用情况下,需要写数据到特征中,这是可行的。例如,你的app与一个BLE电子温度调节器交互,你或许需要提供给调节器一个值来设定房间的温度,如果特征的值可以被写,你可以通过CBPeripheral类的writeValue:forCharacteristi
c:type:
方法把数据(NSData的实例)写到特征的值里:

NSLog(@"Writing value for characteristic %@", interestingCharacteristic);
[peripheral writeValue:dataToWrite forCharacteristic:interestingCharacteristictype:CBCharacteristicWriteWithResponse];

当你试图去写特征的值时,你需要说明你需要用哪种类型的写的方法。上面的例子中,写的方法为CBCharacteristicWriteWithResponse,用这个方法,外围设备会让你的app知道写操作是否成功(就是)。更多写的方法请看CBPeripheral
Class Reference里面的CBCharacteristicWriteType枚举。
使用CBCharacteristicWriteWithResponse方法给外围设备写数据时,会回调 其代理的peripheral:didWriteValueForCharacteristic:error:方法。如果写数据失败,可以通过这个方法找到失败的原因。像这样:

- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic
error:(NSError *)error {
    if (error) {
        NSLog(@"Error writing characteristic value: %@",
        [error localizedDescription]);
}
...

说明:由于我开发的项目,对于蓝牙操作这一块,不在一个界面进行操作,倘若每一个界面都进行编写,逻辑太过混乱,代码也不清晰,所以实现了一个单例蓝牙管理类BLEManager.
BLEManager的代码如下:

//  BLEmanager.h

#import <Foundation/Foundation.h>
#import <CoreBluetooth/CoreBluetooth.h>
@protocol BLEMangerDelegate
-(void)bleManagerBlueToothState:(CBCentralManager *)central;
-(void)bleMangerConnectedPeripheral:(CBPeripheral *)peripheral;
-(void)bleMangerDisConnectedPeripheral :(CBPeripheral *)peripheral;
-(void)bleMangerReceiveDataPeripheralData :(NSData *)data fromCharacteristic :(CBCharacteristic *)curCharacteristic;

@end

@interface BLEmanager : NSObject<CBCentralManagerDelegate,CBPeripheralDelegate>
{
    CBCentralManager *_m_manger;
    CBPeripheral     *_m_peripheral;
    
    NSMutableArray *m_array_peripheral;
}
+(BLEmanager *)shareInstance;
@property(nonatomic,copy)     NSMutableArray   *m_array_peripheral;
@property(nonatomic,strong)   CBCentralManager *m_manger;
@property(nonatomic,strong)   CBPeripheral     *m_peripheral;
@property(weak,nonatomic) id<BLEMangerDelegate> mange_delegate;
@property (nonatomic,assign) BOOL BLEOpen;
-(void)initCentralManger;

@end

//  BLEmanager.m

#import "BLEmanager.h"
#import "BlePeripheral.h"
@implementation BLEmanager
@synthesize m_manger;
@synthesize m_peripheral;
@synthesize m_array_peripheral;
//@synthesize mange_delegate;

//单例
#undef  AS_SINGLETON
#define AS_SINGLETON( __class ) \
+ (__class *)sharedInstance;

#undef  DEF_SINGLETON
#define DEF_SINGLETON( __class ) \
+ (__class *)sharedInstance \
{ \
static dispatch_once_t once; \
static __class * __singleton__; \
dispatch_once( &once, ^{ __singleton__ = [[__class alloc] init]; } ); \
return __singleton__; \
}

static BLEmanager *sharedBLEmanger=nil;
-(instancetype)init
{
    self = [super init];
    if (self) {
        if (!m_array_peripheral) {
            
            m_manger = [[CBCentralManager alloc]initWithDelegate:self queue:nil];
            m_array_peripheral = [[NSMutableArray alloc]init];
        }
    }
    return self;
}


+(BLEmanager *)shareInstance;
{
    @synchronized(self){
        if (sharedBLEmanger == nil) {
            sharedBLEmanger = [[self alloc] init];
        }
    }
    return sharedBLEmanger;
}

-(void)initCentralManger;
{
    m_manger = [[CBCentralManager alloc]initWithDelegate:self queue:nil];
}

- (void)centralManagerDidUpdateState:(CBCentralManager *)central;
{
    if (central.state == CBCentralManagerStatePoweredOn) {
        self.BLEOpen = YES;
    }else{
        self.BLEOpen = NO;
        //可以自己判断其他的类型
        /*
         CBCentralManagerStateUnknown = 0,
         CBCentralManagerStateResetting,
         CBCentralManagerStateUnsupported,
         CBCentralManagerStateUnauthorized,
         CBCentralManagerStatePoweredOff,
         CBCentralManagerStatePoweredOn,
         */
    }

    
    if ([self.mange_delegate respondsToSelector:@selector(bleManagerBlueToothState:)]) {
        [self.mange_delegate bleManagerBlueToothState:central];
    }
    
}

/*!
 *  @method centralManager:didDiscoverPeripheral:advertisementData:RSSI:
 *
 *  @param central              The central manager providing this update.
 *  @param peripheral           A <code>CBPeripheral</code> object.
 *  @param advertisementData    A dictionary containing any advertisement and scan response data.
 *  @param RSSI                 The current RSSI of <i>peripheral</i>, in dBm. A value of <code>127</code> is reserved and indicates the RSSI
 *                              was not available.
 *
 *  @discussion                 This method is invoked while scanning, upon the discovery of <i>peripheral</i> by <i>central</i>. A discovered peripheral must
 *                              be retained in order to use it; otherwise, it is assumed to not be of interest and will be cleaned up by the central manager. For
 *                              a list of <i>advertisementData</i> keys, see {@link CBAdvertisementDataLocalNameKey} and other similar constants.
 *
 *  @seealso                    CBAdvertisementData.h
 *
 */
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI;
{
    
    //这个方法是一旦扫描到外设就会调用的方法,注意此时并没有连接上外设,这个方法里面,你可以解析出当前扫描到的外设的广播包信息,当前RSSI等,现在很多的做法是,会根据广播包带出来的设备名,初步判断是不是自己公司的设备,才去连接这个设备,就是在这里面进行判断的
    
    NSString *localName = [advertisementData valueForKey:@"kCBAdvDataLocalName"];
   // NSLog(@"localName = %@ RSSI = %@",localName,RSSI);
    
    
    NSArray *services = [advertisementData objectForKey:@"kCBAdvDataServiceUUIDs"];
    
    
    LFLog(@"advertisementData = %@",advertisementData);
    
    BOOL isExist = [self comparePeripheralisEqual:peripheral RSSI:RSSI localName:localName];
    if (!isExist) {
        BlePeripheral *l_per = [[BlePeripheral alloc]init];
        l_per.m_peripheral = peripheral;
        l_per.m_peripheralIdentifier = [peripheral.identifier UUIDString];
        l_per.m_peripheralLocaName = localName;
        l_per.m_peripheralRSSI = RSSI;
        
//        l_per.m_peripheralUUID       =  (__bridge NSString *)(CFUUIDCreateString(NULL, peripheral.identifier)); //IOS 7.0 之后弃用了,功能和 identifier 一样
        
        //[NSTemporaryDirectory()stringByAppendingPathComponent:[NSStringstringWithFormat:@"%@-%@", prefix, uuidStr]]
        l_per.m_peripheralServices   = [services count];
        
    
        [m_array_peripheral addObject:l_per];
    }
    
 
}
/*!
 *  @method centralManager:didConnectPeripheral:
 *
 *  @param central      The central manager providing this information.
 *  @param peripheral   The <code>CBPeripheral</code> that has connected.
 *
 *  @discussion         This method is invoked when a connection initiated by {@link connectPeripheral:options:} has succeeded.
 *
 */
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral;
{
    
    [m_manger stopScan];
    
    m_peripheral = peripheral;
    m_peripheral.delegate = self;
    
    LFLog(@"已经连接上了: %@",peripheral.name);
    
    if ([self.mange_delegate respondsToSelector:@selector(bleMangerConnectedPeripheral:)]) {
        [self.mange_delegate bleMangerConnectedPeripheral:peripheral]; //delegate 给出去外面一个通知什么的,表明已经连接上了
    }

    [m_peripheral discoverServices:nil]; //我们直接一次读取外设的所有的: Services ,如果只想找某个服务,直接传数组进去就行,比如你只想扫描服务UUID为 FFF1和FFE2 的这两项服务
    /*
    NSArray *array_service = [NSArray arrayWithObjects:[CBUUID UUIDWithString:@"FFF1"], [CBUUID UUIDWithString:@"FFE2"],nil];
    [m_peripheral discoverServices:array_service];
    */
    
}
/*!
 *  @method centralManager:didFailToConnectPeripheral:error:
 *
 *  @param central      The central manager providing this information.
 *  @param peripheral   The <code>CBPeripheral</code> that has failed to connect.
 *  @param error        The cause of the failure.
 *
 *  @discussion         This method is invoked when a connection initiated by {@link connectPeripheral:options:} has failed to complete. As connection attempts do not
 *                      timeout, the failure of a connection is atypical and usually indicative of a transient issue.
 *
 */
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;
{
    //看苹果的官方解释 {@link connectPeripheral:options:} ,也就是说链接外设失败了
    LFLog(@"链接外设失败");
}
/*!
 *  @method centralManager:didDisconnectPeripheral:error:
 *
 *  @param central      The central manager providing this information.
 *  @param peripheral   The <code>CBPeripheral</code> that has disconnected.
 *  @param error        If an error occurred, the cause of the failure.
 *
 *  @discussion         This method is invoked upon the disconnection of a peripheral that was connected by {@link connectPeripheral:options:}. If the disconnection
 *                      was not initiated by {@link cancelPeripheralConnection}, the cause will be detailed in the <i>error</i> parameter. Once this method has been
 *                      called, no more methods will be invoked on <i>peripheral</i>'s <code>CBPeripheralDelegate</code>.
 *
 */
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;
{
    //自己看看官方的说明,这个函数被调用是有前提条件的,首先你的要先调用过了 connectPeripheral:options:这个方法,其次是如果这个函数被回调的原因不是因为你主动调用了 cancelPeripheralConnection 这个方法,那么说明,整个蓝牙连接已经结束了,不会再有回连的可能,得要重来了
    LFLog(@"didDisconnectPeripheral");
    
    //如果你想要尝试回连外设,可以在这里调用一下链接函数
    /*
    [central connectPeripheral:peripheral options:@{CBCentralManagerScanOptionSolicitedServiceUUIDsKey : @YES,CBConnectPeripheralOptionNotifyOnDisconnectionKey:@YES}];
     */
    if ([self.mange_delegate respondsToSelector:@selector(bleMangerDisConnectedPeripheral:)]) {
          [self.mange_delegate bleMangerDisConnectedPeripheral:peripheral];
    }
}


- (void)peripheralDidUpdateName:(CBPeripheral *)peripheral NS_AVAILABLE(NA, 6_0);
{
    //这个函数一般不会被调用,他被调用是因为 peripheral.name 被修改了,才会被调用
    
}
/*!
 *  @method peripheralDidInvalidateServices:
 *
 *  @param peripheral   The peripheral providing this update.
 *
 *  @discussion         This method is invoked when the @link services @/link of <i>peripheral</i> have been changed. At this point,
 *                      all existing <code>CBService</code> objects are invalidated. Services can be re-discovered via @link discoverServices: @/link.
 *
 *  @deprecated         Use {@link peripheral:didModifyServices:} instead.
 */
- (void)peripheralDidInvalidateServices:(CBPeripheral *)peripheral NS_DEPRECATED(NA, NA, 6_0, 7_0);
{
    //这个函数一般也不会被调用,它是在你已经读取过一次外设的 services 之后,没有断开,这个时候外设突然来个我的某个服务不让用了,这个时候才会被调用,你得要再一次读取外设的 services 即可
}
/*!
 *  @method peripheral:didModifyServices:
 *
 *  @param peripheral           The peripheral providing this update.
 *  @param invalidatedServices  The services that have been invalidated
 *
 *  @discussion         This method is invoked when the @link services @/link of <i>peripheral</i> have been changed.
 *                      At this point, the designated <code>CBService</code> objects have been invalidated.
 *                      Services can be re-discovered via @link discoverServices: @/link.
 */
- (void)peripheral:(CBPeripheral *)peripheral didModifyServices:(NSArray *)invalidatedServices NS_AVAILABLE(NA, 7_0);
{
    //类似上面
    
}
/*!
 *  @method peripheralDidUpdateRSSI:error:
 *
 *  @param peripheral   The peripheral providing this update.
 *  @param error        If an error occurred, the cause of the failure.
 *
 *  @discussion         This method returns the result of a @link readRSSI: @/link call.
 *
 *  @deprecated         Use {@link peripheral:didReadRSSI:error:} instead.
 */
- (void)peripheralDidUpdateRSSI:(CBPeripheral *)peripheral error:(NSError *)error NS_DEPRECATED(NA, NA, 5_0, 8_0);
{
    //这个函数一看就知道了,当外设更新了RSSI的时候被调用,当然,外设不会无故给你老是发RSSI,听硬件那边工程师说,蓝牙协议栈里面的心跳包是可以把RSSI带过来的,但是不知道什么情况,被封杀了,你的要主动调用 [peripheral readRSSI];方法,人家外设才给你回RSSI,不过这个方法现在被弃用了。用下面的方法来接收
    //已经弃用
    
}
/*!
 *  @method peripheral:didReadRSSI:error:
 *
 *  @param peripheral   The peripheral providing this update.
 *  @param RSSI         The current RSSI of the link.
 *  @param error        If an error occurred, the cause of the failure.
 *
 *  @discussion         This method returns the result of a @link readRSSI: @/link call.
 */
- (void)peripheral:(CBPeripheral *)peripheral didReadRSSI:(NSNumber *)RSSI error:(NSError *)error NS_AVAILABLE(NA, 8_0);
{
    
    //同上,这个就是你主动调用了 [peripheral readRSSI];方法回调的RSSI,你可以根据这个RSSI估算一下距离什么的
    LFLog(@" peripheral Current RSSI:%@",RSSI);
    
}
/*!
 *  @method peripheral:didDiscoverServices:
 *
 *  @param peripheral   The peripheral providing this information.
 *  @param error        If an error occurred, the cause of the failure.
 *
 *  @discussion         This method returns the result of a @link discoverServices: @/link call. If the service(s) were read successfully, they can be retrieved via
 *                      <i>peripheral</i>'s @link services @/link property.
 *
 */
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error;
{
    //到这里,说明你上面调用的  [m_peripheral discoverServices:nil]; 方法起效果了,我们接着来找找特征值UUID
    for (CBService *s in [peripheral services]) {
        
        if ([[s UUID] isEqual:[CBUUID UUIDWithString:@"18F0"]]) {
            LFLog(@"%@",s);
            //搜索服务的特征
            [peripheral discoverCharacteristics:nil forService:s];  //同上,如果只想找某个特征值,传参数进去
            
        }

    }
    
}
/*!
 *  @method peripheral:didDiscoverIncludedServicesForService:error:
 *
 *  @param peripheral   The peripheral providing this information.
 *  @param service      The <code>CBService</code> object containing the included services.
 *  @param error        If an error occurred, the cause of the failure.
 *
 *  @discussion         This method returns the result of a @link discoverIncludedServices:forService: @/link call. If the included service(s) were read successfully,
 *                      they can be retrieved via <i>service</i>'s <code>includedServices</code> property.
 */
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverIncludedServicesForService:(CBService *)service error:(NSError *)error;
{
    //基本用不上
}
/*!
 *  @method peripheral:didDiscoverCharacteristicsForService:error:
 *
 *  @param peripheral   The peripheral providing this information.
 *  @param service      The <code>CBService</code> object containing the characteristic(s).
 *  @param error        If an error occurred, the cause of the failure.
 *
 *  @discussion         This method returns the result of a @link discoverCharacteristics:forService: @/link call. If the characteristic(s) were read successfully,
 *                      they can be retrieved via <i>service</i>'s <code>characteristics</code> property.
 */
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error;
{
    //发现了(指定)的特征值了,如果你想要有所动作,你可以直接在这里做,比如有些属性为 notify 的 Characteristics ,你想要监听他们的值,可以这样写
    
    for (CBCharacteristic *c in service.characteristics) {
        if ([[c.UUID UUIDString] isEqualToString:@"2AF0"]) {
            [peripheral setNotifyValue:YES forCharacteristic:c]; //不想监听的时候,设置为:NO 就行了
            [peripheral readValueForCharacteristic:c];
        }
    }
    
    
}
/*!
 *  @method peripheral:didUpdateValueForCharacteristic:error:
 *
 *  @param peripheral       The peripheral providing this information.
 *  @param characteristic   A <code>CBCharacteristic</code> object.
 *  @param error            If an error occurred, the cause of the failure.
 *
 *  @discussion             This method is invoked after a @link readValueForCharacteristic: @/link call, or upon receipt of a notification/indication.
 */
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error;
{
    //这个可是重点了,你收的一切数据,基本都从这里得到,你只要判断一下 [characteristic.UUID UUIDString] 符合你们定义的哪个,然后进行处理就行,值为:characteristic.value 一切数据都是这个,至于怎么解析,得看你们自己的了
   //[characteristic.UUID UUIDString]  注意: UUIDString 这个方法是IOS 7.1之后才支持的,要是之前的版本,得要自己写一个转换方法
    LFLog(@"receiveData = %@,fromCharacteristic.UUID = %@",characteristic.value,characteristic.UUID);
    if ([self.mange_delegate respondsToSelector:@selector(bleMangerReceiveDataPeripheralData:fromCharacteristic:)]) {
        [self.mange_delegate bleMangerReceiveDataPeripheralData:characteristic.value fromCharacteristic:characteristic];
    }
    
    
}
/*!
 *  @method peripheral:didWriteValueForCharacteristic:error:
 *
 *  @param peripheral       The peripheral providing this information.
 *  @param characteristic   A <code>CBCharacteristic</code> object.
 *  @param error            If an error occurred, the cause of the failure.
 *
 *  @discussion             This method returns the result of a {@link writeValue:forCharacteristic:type:} call, when the <code>CBCharacteristicWriteWithResponse</code> type is used.
 */
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error;
{
    //这个方法比较好,这个是你发数据到外设的某一个特征值上面,并且响应的类型是 CBCharacteristicWriteWithResponse ,上面的官方文档也有,如果确定发送到外设了,就会给你一个回应,当然,这个也是要看外设那边的特征值UUID的属性是怎么设置的,看官方文档,人家已经说了,条件是,特征值UUID的属性:CBCharacteristicWriteWithResponse
    if (!error) {
        LFLog(@"说明发送成功,characteristic.uuid为:%@",[characteristic.UUID UUIDString]);
    }else{
        LFLog(@"发送失败了啊!characteristic.uuid为:%@",[characteristic.UUID UUIDString]);
    }
        
}
/*!
 *  @method peripheral:didUpdateNotificationStateForCharacteristic:error:
 *
 *  @param peripheral       The peripheral providing this information.
 *  @param characteristic   A <code>CBCharacteristic</code> object.
 *  @param error            If an error occurred, the cause of the failure.
 *
 *  @discussion             This method returns the result of a @link setNotifyValue:forCharacteristic: @/link call.
 */
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error;

{
    //这个方法被调用是因为你主动调用方法: setNotifyValue:forCharacteristic 给你的反馈
    LFLog(@"你更新了对特征值:%@ 的通知",[characteristic.UUID UUIDString]);
    
    [peripheral readValueForCharacteristic:characteristic];
}

-(BOOL) comparePeripheralisEqual :(CBPeripheral *)disCoverPeripheral RSSI:(NSNumber *)RSSI localName:(NSString *)localName
{
    if ([m_array_peripheral count]>0) {
        for (int i=0;i<[m_array_peripheral count];i++) {
            BlePeripheral *l_per = [m_array_peripheral objectAtIndex:i];
            if ([disCoverPeripheral isEqual:l_per.m_peripheral]) {
                l_per.m_peripheralRSSI = RSSI;
                l_per.m_peripheralLocaName = localName;
                return YES;
            }
        }
    }
    return NO;
}

@end

在需要使用蓝牙的界面,初始化BLEManager,设置delegate,在回调方法中就可以执行相关操作.

    self.bleManager = [BLEmanager shareInstance];
    self.bleManager.mange_delegate = self;
    [self.bleManager.m_array_peripheral removeAllObjects];

m_array_peripheral为搜到的所有的蓝牙设备数组

BLEManager的代理方法:

#pragma mark - BLEMangerDelegate
//蓝牙是否打开
-(void)bleManagerBlueToothState:(CBCentralManager *)central {
    switch (central.state) {
        case CBManagerStatePoweredOff:
        {
            //蓝牙打开状态关
            //处理自己的逻辑
        }
            break;
        case CBManagerStatePoweredOn:
        {
            //蓝牙打开状态开
            //处理自己的逻辑
        }
            break;  
        default:
            break;
    }
}
//连接上蓝牙
-(void)bleMangerConnectedPeripheral:(CBPeripheral *)peripheral {
    [MBProgressHUD hideHUDForView:self.view];
   //处理自己的业务逻辑
    [self.bleManager.m_manger stopScan];
}
//蓝牙断开连接
-(void)bleMangerDisConnectedPeripheral:(CBPeripheral *)peripheral {
   //处理自己的业务逻辑
}
//接收到订阅的数据
-(void)bleMangerReceiveDataPeripheralData :(NSData *)data fromCharacteristic:(CBCharacteristic *)curCharacteristic {
      LFLog(@"接收到外设特征值为:%@ 发送的数据:%@",[curCharacteristic.UUID  UUIDString],data);
}

有什么错误地方请大家交流指正,就写到这里了

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • 备注:下面说到的内容都基于蓝牙4.0标准以上,主要以实践为主。 ~ CoreBluetooth.framework...
    未_漆小七阅读 1,597评论 1 8
  • 蓝牙简介 蓝牙( Bluetooth® ):是一种无线技术标准,可实现固定设备、移动设备和楼宇个人域网之间的短距离...
    Chefil阅读 2,027评论 2 19
  • 第一本手帐记录完毕,感觉心里被填得满满的。回头可以看见半年来的各种小小的进步,各种心绪,各种感想,或是看了电影的观...
    谒书人阅读 777评论 0 3
  • 首先我觉得午夜嚎叫这个非常害怕,真的非常害怕。它其实就是一种有点紫又有点红的花,这种花把它用一个机器弄成一滴滴的东...
    新余宝贝阅读 214评论 1 0
  • 蚁语 花开的喜悦 生命与生命相依 一边花开 一边结果 红是冬日热烈的枝干 瑞是花开花落不知倦 木是生命可贵难能久远...
    医尘阅读 307评论 4 2