最近做的育兒項(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)大家交流指正,就寫到這里了