iOS藍(lán)牙開發(fā)--對(duì)接體溫槍

最近做的育兒項(xiàng)目,需要iOS設(shè)備對(duì)接藍(lán)牙體溫槍,以前沒有做過,現(xiàn)在已經(jīng)完成了基本功能,現(xiàn)在記錄下過程,以備以后查看.

說明:

參考文章:
【譯】iOS藍(lán)牙編程指南 -- 核心藍(lán)牙概述 - 簡(jiǎn)書
【iOS官方文檔翻譯】iOS的藍(lán)牙連接、數(shù)據(jù)接收及發(fā)送 - dolacmeng的專欄 - 博客頻道 - CSDN.NET
文檔中涉及一些名詞:Central(中心設(shè)備)季希、Peripheral(外圍設(shè)備)褪那、advertising(廣告)幽纷、Services(服務(wù))、Characteristic(特征)等.具體下面解釋.

開發(fā)步驟:

步驟1.建立一個(gè)Central Manager實(shí)例進(jìn)行藍(lán)牙管理
步驟2.搜索外圍設(shè)備
步驟3.連接外圍設(shè)備
步驟4.獲得外圍設(shè)備的服務(wù)
步驟5.獲得服務(wù)的特征
步驟6.從外圍設(shè)備讀數(shù)據(jù)(直接讀取和訂閱兩種方法)
步驟7.給外圍設(shè)備發(fā)送數(shù)據(jù)

具體流程:

步驟一.開啟Central Manager

CBCentralManager 是Core Bluetooth的一個(gè)對(duì)象博敬,代表一個(gè)本地中心設(shè)備霹崎,在使用任何藍(lán)牙傳輸前,你必須給CBCentralManager實(shí)例分配內(nèi)存和初始化冶忱。可以通過CBCentralManager類的initWithDelegate:queue:options:方法:

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

在這個(gè)例子中境析,self會(huì)被設(shè)置為接收所有中心設(shè)備角色的事件的代理囚枪,設(shè)置dispatch queue為nil后,central manager會(huì)通過主線程來處理這些事件劳淆。ViewController需要實(shí)現(xiàn)CBCentralManagerDelegate,CBPeripheralDelegate這兩個(gè)代理
當(dāng)創(chuàng)建了一個(gè)central manager链沼,會(huì)回調(diào)代理的centralManagerDidUpdateState:方法,你必須實(shí)現(xiàn)這個(gè)代理方法來確定中心設(shè)備是否支持BLE以及是否可用沛鸵。

步驟二.搜索正在廣告的外圍設(shè)備

中心設(shè)備的第一個(gè)任務(wù)是搜索你的APP可以連接的外圍設(shè)備括勺,正如上一篇文章中提到的,廣告(advertising)是外圍設(shè)備使其被周圍設(shè)備發(fā)現(xiàn)的主要方法曲掰,你可以通過CBCentralManager類的scanForPeripheralsWithServices:options:方法疾捍,搜索任何正在廣告的外圍設(shè)備:

[myCentralManager scanForPeripheralsWithServices:nil options:nil];

你調(diào)用了scanForPeripheralsWithServices:options:方法來搜索可連接的外圍設(shè)備后,central manager 在每次搜索到一個(gè)外圍設(shè)備都會(huì)回調(diào)其代理的centralManager:didDiscoverPeripheral:advertisementData:RSSI:方法栏妖。任何被搜索到的外圍設(shè)備都以CBPeripheral類的方式返回乱豆。像下面的代碼,你可以實(shí)現(xiàn)這個(gè)代理方法來羅列出所有被搜索到的藍(lán)牙設(shè)備:

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

當(dāng)你已經(jīng)找到了一個(gè)你需要連接的外圍設(shè)備吊趾,停止搜索其它設(shè)備來節(jié)省電量宛裕。

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

步驟三.連接一個(gè)你搜索到并希望連接的外圍設(shè)備

在你搜索到一個(gè)外圍設(shè)備,并且它廣告了你需要的服務(wù)论泛,你可以請(qǐng)求和這個(gè)外圍設(shè)備連接揩尸,通過調(diào)用CBCentralManager類的connectPeripheral:options:方法,簡(jiǎn)而言之屁奏,調(diào)用這個(gè)方法并且說明你需要連接的外圍設(shè)備:

[myCentralManager connectPeripheral:peripheral options:nil];

假設(shè)連接成功了岩榆,central manager 會(huì)回調(diào)其代理方法[centralManager:
didConnectPeripheral:],你可以實(shí)現(xiàn)這個(gè)方法來打印“外圍設(shè)備連接”:

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

在你開始和外圍設(shè)備交互之前,你應(yīng)該設(shè)置外圍設(shè)備的代理以確保它能接收合適的回調(diào)了袁,像這樣

peripheral.delegate = self;

步驟四.搜索你已經(jīng)連接的外圍設(shè)備的服務(wù)

在你與外圍設(shè)備建立連接之后朗恳,你可以開始勘察它的數(shù)據(jù)。第一步是勘察外圍設(shè)備提供了什么服務(wù)载绿,因?yàn)橥鈬O(shè)備廣告的數(shù)據(jù)有大小限制粥诫,你或許會(huì)發(fā)現(xiàn)外圍設(shè)備提供比它廣告的還有更多服務(wù)。你可以通過CBPeripheral類的discoverServices:方法來發(fā)現(xiàn)一個(gè)外圍設(shè)備提供的所有服務(wù):

[peripheral discoverServices:nil];

當(dāng)發(fā)現(xiàn)了具體的服務(wù)崭庸,外圍設(shè)備(已經(jīng)連接的CBPeripheral類)會(huì)回調(diào)其代理的peripheral:didDiscoverServices:方法怀浆。Core Bluetooth 建立CBService類的array數(shù)組——存儲(chǔ)外圍設(shè)備的每一個(gè)服務(wù)谊囚。像下面的代碼,你可以實(shí)現(xiàn)這個(gè)代理方法來獲得發(fā)現(xiàn)的服務(wù)列表:

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

步驟五.搜索服務(wù)的特征

假定你已經(jīng)找到了你需要的服務(wù)执赡,下一步就是探索服務(wù)的所有“特征”(characteristics)镰踏,搜索一個(gè)服務(wù)的所有特征只要調(diào)用CBPeripheral類的discoverCharacteristics:forService:方法,參數(shù)為具體的服務(wù):

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

當(dāng)發(fā)現(xiàn)了指定服務(wù)的特征沙合,外圍設(shè)備會(huì)回調(diào)peripheral:didDiscoverCharact
eristicsForService:error:
代理方法奠伪。Core Bluetooth建立存儲(chǔ)CBCharacteristic實(shí)例的array數(shù)組———每一個(gè)都代表一個(gè)發(fā)現(xiàn)了的特征。下面的示例就是實(shí)現(xiàn)這個(gè)代理方法來簡(jiǎn)單地打印每個(gè)發(fā)現(xiàn)了的特征:

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

步驟六.取得特征的值(就是從外圍設(shè)備取數(shù)據(jù))

一個(gè)特征包含一個(gè)代表外圍設(shè)備服務(wù)的簡(jiǎn)單值首懈,例如绊率,有一個(gè)健康溫度計(jì)服務(wù)甲脏,這個(gè)服務(wù)有一個(gè)溫度測(cè)量特征干毅,而這個(gè)特征有一個(gè)攝氏溫度的值,你可以直接讀取或者訂閱這個(gè)特征來取得這個(gè)特征對(duì)應(yīng)的值钳枕。
6.1直接讀取特征的值
你得到你希望得到的服務(wù)的某個(gè)特征后最仑,你可以通過調(diào)用CBPeripheral類的readValueForCharacteristic:方法來讀取這個(gè)特征對(duì)應(yīng)的值藐俺,參數(shù)為需要讀取的特征:

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

當(dāng)你試圖去讀一個(gè)特征對(duì)應(yīng)的值,外圍設(shè)備會(huì)回調(diào)它的代理方法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訂閱一個(gè)特征的值
在某些使用情況下,通過readValueForCharacteristic:讀取一個(gè)特征的值會(huì)很有效率全景,但是這不是獲得值改變的最有效率方法耀石,對(duì)于大部分特征值的改變——例如,你在給定時(shí)間的心率爸黄,你應(yīng)該通過訂閱來獲得它滞伟。當(dāng)你訂閱了一個(gè)特征的值,你可以在值改變的時(shí)候接收到通知炕贵。你可以通過CBPeripheral類的setNotifyValue:forCharacteristic:方法來訂閱你需要的特征梆奈,參數(shù)為YES,以及需要訂閱的特征:

[peripheral setNotifyValue:YES forCharacteristic:interestingCharacteristic];

當(dāng)你試圖去訂閱(或取消訂閱)一個(gè)特征時(shí)称开,外圍設(shè)備會(huì)調(diào)用 它的代理的peripheral:didUpdateNotificationStateForCharacteristic:error:方法亩钟,如果訂閱請(qǐng)求失敗,你可以通過實(shí)現(xiàn)這個(gè)方法來獲得錯(cuò)誤原因:

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

當(dāng)你成功訂閱了某個(gè)特征鳖轰,在特征的值改變時(shí)清酥,外圍設(shè)備會(huì)通知你的app,每次值改變蕴侣,外圍設(shè)備會(huì)調(diào)用 其代理的peripheral:didUpdateValueForCharacteristic
:error:
方法焰轻。你可以通過實(shí)現(xiàn)這個(gè)方法來獲得改變的值,這個(gè)方法和上面直接讀取時(shí)回調(diào)的方法一樣昆雀。

步驟七.寫值到特征中(就是發(fā)數(shù)據(jù)給外圍設(shè)備)

在某些使用情況下辱志,需要寫數(shù)據(jù)到特征中蝠筑,這是可行的。例如揩懒,你的app與一個(gè)BLE電子溫度調(diào)節(jié)器交互什乙,你或許需要提供給調(diào)節(jié)器一個(gè)值來設(shè)定房間的溫度,如果特征的值可以被寫已球,你可以通過CBPeripheral類的writeValue:forCharacteristi
c:type:
方法把數(shù)據(jù)(NSData的實(shí)例)寫到特征的值里:

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

當(dāng)你試圖去寫特征的值時(shí)臣镣,你需要說明你需要用哪種類型的寫的方法。上面的例子中智亮,寫的方法為CBCharacteristicWriteWithResponse退疫,用這個(gè)方法,外圍設(shè)備會(huì)讓你的app知道寫操作是否成功(就是)鸽素。更多寫的方法請(qǐng)看CBPeripheral
Class Reference里面的CBCharacteristicWriteType枚舉。
使用CBCharacteristicWriteWithResponse方法給外圍設(shè)備寫數(shù)據(jù)時(shí)亦鳞,會(huì)回調(diào) 其代理的peripheral:didWriteValueForCharacteristic:error:方法馍忽。如果寫數(shù)據(jù)失敗,可以通過這個(gè)方法找到失敗的原因燕差。像這樣:

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

說明:由于我開發(fā)的項(xiàng)目,對(duì)于藍(lán)牙操作這一塊,不在一個(gè)界面進(jìn)行操作,倘若每一個(gè)界面都進(jìn)行編寫,邏輯太過混亂,代碼也不清晰,所以實(shí)現(xiàn)了一個(gè)單例藍(lán)牙管理類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;
{
    
    //這個(gè)方法是一旦掃描到外設(shè)就會(huì)調(diào)用的方法遭笋,注意此時(shí)并沒有連接上外設(shè),這個(gè)方法里面徒探,你可以解析出當(dāng)前掃描到的外設(shè)的廣播包信息瓦呼,當(dāng)前RSSI等,現(xiàn)在很多的做法是测暗,會(huì)根據(jù)廣播包帶出來的設(shè)備名央串,初步判斷是不是自己公司的設(shè)備,才去連接這個(gè)設(shè)備碗啄,就是在這里面進(jìn)行判斷的
    
    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(@"已經(jīng)連接上了: %@",peripheral.name);
    
    if ([self.mange_delegate respondsToSelector:@selector(bleMangerConnectedPeripheral:)]) {
        [self.mange_delegate bleMangerConnectedPeripheral:peripheral]; //delegate 給出去外面一個(gè)通知什么的,表明已經(jīng)連接上了
    }

    [m_peripheral discoverServices:nil]; //我們直接一次讀取外設(shè)的所有的: Services ,如果只想找某個(gè)服務(wù)稚字,直接傳數(shù)組進(jìn)去就行饲宿,比如你只想掃描服務(wù)UUID為 FFF1和FFE2 的這兩項(xiàng)服務(wù)
    /*
    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:} ,也就是說鏈接外設(shè)失敗了
    LFLog(@"鏈接外設(shè)失敗");
}
/*!
 *  @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;
{
    //自己看看官方的說明,這個(gè)函數(shù)被調(diào)用是有前提條件的胆描,首先你的要先調(diào)用過了 connectPeripheral:options:這個(gè)方法瘫想,其次是如果這個(gè)函數(shù)被回調(diào)的原因不是因?yàn)槟阒鲃?dòng)調(diào)用了 cancelPeripheralConnection 這個(gè)方法,那么說明昌讲,整個(gè)藍(lán)牙連接已經(jīng)結(jié)束了国夜,不會(huì)再有回連的可能,得要重來了
    LFLog(@"didDisconnectPeripheral");
    
    //如果你想要嘗試回連外設(shè)剧蚣,可以在這里調(diào)用一下鏈接函數(shù)
    /*
    [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);
{
    //這個(gè)函數(shù)一般不會(huì)被調(diào)用支竹,他被調(diào)用是因?yàn)?peripheral.name 被修改了旋廷,才會(huì)被調(diào)用
    
}
/*!
 *  @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);
{
    //這個(gè)函數(shù)一般也不會(huì)被調(diào)用,它是在你已經(jīng)讀取過一次外設(shè)的 services 之后礼搁,沒有斷開饶碘,這個(gè)時(shí)候外設(shè)突然來個(gè)我的某個(gè)服務(wù)不讓用了,這個(gè)時(shí)候才會(huì)被調(diào)用馒吴,你得要再一次讀取外設(shè)的 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);
{
    //這個(gè)函數(shù)一看就知道了扎运,當(dāng)外設(shè)更新了RSSI的時(shí)候被調(diào)用,當(dāng)然饮戳,外設(shè)不會(huì)無故給你老是發(fā)RSSI豪治,聽硬件那邊工程師說,藍(lán)牙協(xié)議棧里面的心跳包是可以把RSSI帶過來的扯罐,但是不知道什么情況负拟,被封殺了,你的要主動(dòng)調(diào)用 [peripheral readRSSI];方法歹河,人家外設(shè)才給你回RSSI掩浙,不過這個(gè)方法現(xiàn)在被棄用了。用下面的方法來接收
    //已經(jīng)棄用
    
}
/*!
 *  @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);
{
    
    //同上秸歧,這個(gè)就是你主動(dòng)調(diào)用了 [peripheral readRSSI];方法回調(diào)的RSSI厨姚,你可以根據(jù)這個(gè)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;
{
    //到這里,說明你上面調(diào)用的  [m_peripheral discoverServices:nil]; 方法起效果了键菱,我們接著來找找特征值UUID
    for (CBService *s in [peripheral services]) {
        
        if ([[s UUID] isEqual:[CBUUID UUIDWithString:@"18F0"]]) {
            LFLog(@"%@",s);
            //搜索服務(wù)的特征
            [peripheral discoverCharacteristics:nil forService:s];  //同上谬墙,如果只想找某個(gè)特征值,傳參數(shù)進(jìn)去
            
        }

    }
    
}
/*!
 *  @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;
{
    //發(fā)現(xiàn)了(指定)的特征值了经备,如果你想要有所動(dòng)作拭抬,你可以直接在這里做,比如有些屬性為 notify 的 Characteristics ,你想要監(jiān)聽他們的值侵蒙,可以這樣寫
    
    for (CBCharacteristic *c in service.characteristics) {
        if ([[c.UUID UUIDString] isEqualToString:@"2AF0"]) {
            [peripheral setNotifyValue:YES forCharacteristic:c]; //不想監(jiān)聽的時(shí)候玖喘,設(shè)置為: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;
{
    //這個(gè)可是重點(diǎn)了,你收的一切數(shù)據(jù)蘑志,基本都從這里得到,你只要判斷一下 [characteristic.UUID UUIDString] 符合你們定義的哪個(gè)累奈,然后進(jìn)行處理就行,值為:characteristic.value 一切數(shù)據(jù)都是這個(gè)急但,至于怎么解析澎媒,得看你們自己的了
   //[characteristic.UUID UUIDString]  注意: UUIDString 這個(gè)方法是IOS 7.1之后才支持的,要是之前的版本,得要自己寫一個(gè)轉(zhuǎn)換方法
    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;
{
    //這個(gè)方法比較好波桩,這個(gè)是你發(fā)數(shù)據(jù)到外設(shè)的某一個(gè)特征值上面戒努,并且響應(yīng)的類型是 CBCharacteristicWriteWithResponse ,上面的官方文檔也有,如果確定發(fā)送到外設(shè)了储玫,就會(huì)給你一個(gè)回應(yīng)侍筛,當(dāng)然,這個(gè)也是要看外設(shè)那邊的特征值UUID的屬性是怎么設(shè)置的,看官方文檔撒穷,人家已經(jīng)說了匣椰,條件是,特征值UUID的屬性:CBCharacteristicWriteWithResponse
    if (!error) {
        LFLog(@"說明發(fā)送成功端礼,characteristic.uuid為:%@",[characteristic.UUID UUIDString]);
    }else{
        LFLog(@"發(fā)送失敗了扒菪Α!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;

{
    //這個(gè)方法被調(diào)用是因?yàn)槟阒鲃?dòng)調(diào)用方法: setNotifyValue:forCharacteristic 給你的反饋
    LFLog(@"你更新了對(duì)特征值:%@ 的通知",[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

在需要使用藍(lán)牙的界面,初始化BLEManager,設(shè)置delegate,在回調(diào)方法中就可以執(zhí)行相關(guān)操作.

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

m_array_peripheral為搜到的所有的藍(lán)牙設(shè)備數(shù)組

BLEManager的代理方法:

#pragma mark - BLEMangerDelegate
//藍(lán)牙是否打開
-(void)bleManagerBlueToothState:(CBCentralManager *)central {
    switch (central.state) {
        case CBManagerStatePoweredOff:
        {
            //藍(lán)牙打開狀態(tài)關(guān)
            //處理自己的邏輯
        }
            break;
        case CBManagerStatePoweredOn:
        {
            //藍(lán)牙打開狀態(tài)開
            //處理自己的邏輯
        }
            break;  
        default:
            break;
    }
}
//連接上藍(lán)牙
-(void)bleMangerConnectedPeripheral:(CBPeripheral *)peripheral {
    [MBProgressHUD hideHUDForView:self.view];
   //處理自己的業(yè)務(wù)邏輯
    [self.bleManager.m_manger stopScan];
}
//藍(lán)牙斷開連接
-(void)bleMangerDisConnectedPeripheral:(CBPeripheral *)peripheral {
   //處理自己的業(yè)務(wù)邏輯
}
//接收到訂閱的數(shù)據(jù)
-(void)bleMangerReceiveDataPeripheralData :(NSData *)data fromCharacteristic:(CBCharacteristic *)curCharacteristic {
      LFLog(@"接收到外設(shè)特征值為:%@ 發(fā)送的數(shù)據(jù):%@",[curCharacteristic.UUID  UUIDString],data);
}

有什么錯(cuò)誤地方請(qǐng)大家交流指正,就寫到這里了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蛤奥,一起剝皮案震驚了整個(gè)濱河市佳镜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌凡桥,老刑警劉巖蟀伸,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異缅刽,居然都是意外死亡望蜡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門拷恨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人谢肾,你說我怎么就攤上這事腕侄。” “怎么了芦疏?”我有些...
    開封第一講書人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵冕杠,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我酸茴,道長(zhǎng)分预,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任薪捍,我火速辦了婚禮笼痹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘酪穿。我一直安慰自己凳干,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開白布被济。 她就那樣靜靜地躺著救赐,像睡著了一般。 火紅的嫁衣襯著肌膚如雪只磷。 梳的紋絲不亂的頭發(fā)上经磅,一...
    開封第一講書人閱讀 51,692評(píng)論 1 305
  • 那天泌绣,我揣著相機(jī)與錄音,去河邊找鬼预厌。 笑死阿迈,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的配乓。 我是一名探鬼主播仿滔,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼犹芹!你這毒婦竟也來了崎页?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤腰埂,失蹤者是張志新(化名)和其女友劉穎飒焦,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體屿笼,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡牺荠,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了驴一。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片休雌。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖肝断,靈堂內(nèi)的尸體忽然破棺而出杈曲,到底是詐尸還是另有隱情,我是刑警寧澤胸懈,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布担扑,位于F島的核電站,受9級(jí)特大地震影響趣钱,放射性物質(zhì)發(fā)生泄漏涌献。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一首有、第九天 我趴在偏房一處隱蔽的房頂上張望燕垃。 院中可真熱鬧,春花似錦井联、人聲如沸利术。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)印叁。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間轮蜕,已是汗流浹背昨悼。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留跃洛,地道東北人率触。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像汇竭,于是被迫代替她去往敵國(guó)和親葱蝗。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 備注:下面說到的內(nèi)容都基于藍(lán)牙4.0標(biāo)準(zhǔn)以上细燎,主要以實(shí)踐為主两曼。 ~ CoreBluetooth.framework...
    未_漆小七閱讀 1,619評(píng)論 1 8
  • 藍(lán)牙簡(jiǎn)介 藍(lán)牙( Bluetooth? ):是一種無線技術(shù)標(biāo)準(zhǔn),可實(shí)現(xiàn)固定設(shè)備玻驻、移動(dòng)設(shè)備和樓宇個(gè)人域網(wǎng)之間的短距離...
    Chefil閱讀 2,044評(píng)論 2 19
  • 第一本手帳記錄完畢悼凑,感覺心里被填得滿滿的¤邓玻回頭可以看見半年來的各種小小的進(jìn)步户辫,各種心緒,各種感想嗤锉,或是看了電影的觀...
    謁書人閱讀 794評(píng)論 0 3
  • 首先我覺得午夜嚎叫這個(gè)非常害怕渔欢,真的非常害怕。它其實(shí)就是一種有點(diǎn)紫又有點(diǎn)紅的花瘟忱,這種花把它用一個(gè)機(jī)器弄成一滴滴的東...
    新余寶貝閱讀 220評(píng)論 1 0
  • 蟻語(yǔ) 花開的喜悅 生命與生命相依 一邊花開 一邊結(jié)果 紅是冬日熱烈的枝干 瑞是花開花落不知倦 木是生命可貴難能久遠(yuǎn)...
    醫(yī)塵閱讀 308評(píng)論 4 2