- 開發(fā)前:
1梢夯、profile
profile可以理解為一種規(guī)范,一個(gè)標(biāo)準(zhǔn)的通信協(xié)議寝受,它存在于從機(jī)中。藍(lán)牙組織規(guī)定了一些標(biāo)準(zhǔn)的profile零如,例如 HID OVER GATT ,防丟器 锄弱,心率計(jì)等考蕾。每個(gè)profile中會(huì)包含多個(gè)service,每個(gè)service代表從機(jī)的一種能力会宪。2肖卧、service
service可以理解為一個(gè)服務(wù),在ble從機(jī)中掸鹅,通過(guò)有多個(gè)服務(wù)塞帐,例如電量信息服務(wù)、系統(tǒng)信息服務(wù)等巍沙,每個(gè)service中又包含多個(gè)characteristic特征值葵姥。每個(gè)具體的characteristic特征值才是ble通信的主題。比如當(dāng)前的電量是80%句携,所以會(huì)通過(guò)電量的characteristic特征值存在從機(jī)的profile里榔幸,這樣主機(jī)就可以通過(guò)這個(gè)characteristic來(lái)讀取80%這個(gè)數(shù)據(jù)3、characteristic
characteristic特征值务甥,ble主從機(jī)的通信均是通過(guò)characteristic來(lái)實(shí)現(xiàn)牡辽,可以理解為一個(gè)標(biāo)簽,通過(guò)這個(gè)標(biāo)簽可以獲取或者寫入想要的內(nèi)容敞临。4、UUID
UUID麸澜,統(tǒng)一識(shí)別碼挺尿,我們剛才提到的service和characteristic,都需要一個(gè)唯一的uuid來(lái)標(biāo)識(shí)整理一下,每個(gè)從機(jī)都會(huì)有一個(gè)叫做profile的東西存在编矾,不管是上面的自定義的simpleprofile熟史,還是標(biāo)準(zhǔn)的防丟器profile,他們都是由一些列service組成窄俏,然后每個(gè)service又包含了多個(gè)characteristic蹂匹,主機(jī)和從機(jī)之間的通信,均是通過(guò)characteristic來(lái)實(shí)現(xiàn)凹蜈。
- 1 懶加載創(chuàng)建中心設(shè)備 (中心設(shè)備一般是手機(jī)本身))
/**
* 懶加載 初始化中心設(shè)備 CBCentralManager
*
* @return 中心設(shè)備
*/
- (CBCentralManager *)centralManager {
if (!_centralManager) {
_centralManager = [[CBCentralManager alloc]initWithDelegate:self queue:nil options:nil];
}
return _centralManager;
}
- 2 掃描外設(shè)并判斷藍(lán)牙開啟狀態(tài)及設(shè)備是否支持BLE(在需要掃描的地方調(diào)用該方法, 比如點(diǎn)擊掃描按鈕)
- (void)scanPeripheral {
// 2.掃描外設(shè)
if(self.centralManager.state == CBCentralManagerStatePoweredOff) { // 藍(lán)牙關(guān)閉狀態(tài)
[[[UIAlertView alloc] initWithTitle:@"藍(lán)牙是關(guān)閉狀態(tài)"
message:@"請(qǐng)打開藍(lán)牙"
delegate:self
cancelButtonTitle:@"dismiss"
otherButtonTitles: nil] show];
} else if(self.centralManager.state == CBCentralManagerStateUnsupported) { // 設(shè)備藍(lán)牙不支持
[[[UIAlertView alloc] initWithTitle:@"設(shè)備藍(lán)牙不支持"
message:@"必須 iPhone4S 以上的設(shè)備才支持藍(lán)牙4.0"
delegate:self
cancelButtonTitle:@"dismiss"
otherButtonTitles: nil] show];
} else if(self.centralManager.state == CBCentralManagerStatePoweredOn) { // 藍(lán)牙打開狀態(tài)
if (self.peripherals.count) {
// 連接外設(shè)
[self.centralManager connectPeripheral:[self.peripherals firstObject] options:nil];
return;
}
NSLog(@"藍(lán)牙已經(jīng)打開, 正在搜索中...");
self.connectStateLabel.text = @"正在搜索外設(shè)中...";
// 如果第一個(gè)參數(shù)為nil, 那么將會(huì)掃描所有可用的外圍設(shè)備, 不過(guò)這樣會(huì)很慢
[self.centralManager scanForPeripheralsWithServices:nil
options:nil];
}
}
- 3 必須實(shí)現(xiàn)CBCentralManager的一個(gè)代理方法, 在里邊調(diào)用步驟2的方法
/**
* 如果藍(lán)牙狀態(tài)改變, 會(huì)在這個(gè)方法回調(diào)
*
* @param central 中心設(shè)備(一般為你的iPhone)
*/
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
[self scanPeripheral];
}
- 4 實(shí)現(xiàn)CBCentralManager一個(gè)代理方法, 如果掃描到外設(shè)會(huì)在這個(gè)方法中獲取外設(shè)的信息, 并且連接外設(shè)
/**
* 這個(gè)代理方法中可以獲取外設(shè)的信息
* 4. 可以這里連接外設(shè)
* @param central 中心設(shè)備
* @param peripheral 外設(shè)
* @param advertisementData
* @param RSSI
*/
-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
NSLog(@"已經(jīng)搜索到設(shè)備, 正在連接中...");
self.connectStateLabel.text = @"正在連接設(shè)備...";
// 這里可以停止掃描外圍設(shè)備
[self.centralManager stopScan];
if (![self.peripherals containsObject:peripheral]) {
NSLog(@"外設(shè)名稱: %@", peripheral.name);
// 顯示設(shè)備名稱
[self setUpName:peripheral.name];
peripheral.delegate = self;
// 應(yīng)該保留外設(shè), 否則會(huì)被釋放
[self.peripherals addObject:peripheral];
}
// 連接外設(shè)
[self.centralManager connectPeripheral:peripheral options:nil];
}
- 5 實(shí)現(xiàn)CBCentralManager的一個(gè)代理方法, 如果連接外設(shè)成功會(huì)回調(diào)這個(gè)方法, 在這個(gè)方法中掃描外設(shè)中的服務(wù)
/**
* 如果連接成功的話會(huì)回調(diào)這個(gè)方法
* 5. 掃描外設(shè)中的服務(wù)
* @param central 中心設(shè)備
* @param peripheral 外設(shè)
*/
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
self.connectStateLabel.text = @"連接成功, 同步數(shù)據(jù)中...";
// 查找服務(wù)
[peripheral discoverServices:nil];
}
- 6 實(shí)現(xiàn)CBCentralManager的一個(gè)代理方法, 如果連接失敗會(huì)回調(diào)這個(gè)方法
/**
* 連接失敗
*
*/
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
self.connectStateLabel.text = @"連接失敗...";
self.deviceNameKeyLabel.hidden = YES;
self.deviceNameValueLabel.hidden = YES;
[self scanPeripheral];
}
- 7 實(shí)現(xiàn)CBPeripheral的一個(gè)代理方法, 從外設(shè)的services屬性中獲取服務(wù)列表, 從而獲取到想要的服務(wù), 并從中調(diào)用查找特征的方法
/**
* 7. 從外設(shè)的services屬性中獲取服務(wù)列表
*
* @param peripheral 外設(shè)
* @param error 錯(cuò)誤信息
*/
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
NSLog(@"已經(jīng)獲取到服務(wù)列表, 正在匹配服務(wù)中...");
if (error) {
NSLog(@"Discovered services for %@ with error: %@", peripheral.name, [error localizedDescription]);
// if ([self.delegate respondsToSelector:@selector(DidNotifyFailConnectService:withPeripheral:error:)])
// [self.delegate DidNotifyFailConnectService:nil withPeripheral:nil error:nil];
return;
}
// 遍歷服務(wù)
for (CBService *service in peripheral.services) {
NSLog(@"%@", service.UUID);
// [peripheral discoverCharacteristics:nil forService:service];
// 找到對(duì)應(yīng)的服務(wù)
if ([service.UUID isEqual:[CBUUID UUIDWithString:@"FF20"]]) {
// NSLog(@"Service found with UUID: %@", service.UUID);
// 查找特征
[peripheral discoverCharacteristics:nil forService:service];
break;
}
}
}
- 8 實(shí)現(xiàn)CBPeripheral的一個(gè)代理方法, 如果找到服務(wù)中的特征則會(huì)回調(diào)這個(gè)方法
/**
* 返回已經(jīng)發(fā)現(xiàn)的特性的代理方法
* 8. 發(fā)現(xiàn)服務(wù)中的特征
* @param peripheral 外設(shè)
* @param service 服務(wù)
* @param error 錯(cuò)誤信息
*/
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
if (error) {
NSLog(@"Discovered characteristics for %@ with error: %@", service.UUID, [error localizedDescription]);
return;
}
// NSLog(@"\n服務(wù): %@", service.UUID);
// 從服務(wù)中遍歷特征
for (CBCharacteristic *characteristic in service.characteristics) {
// [peripheral setNotifyValue:YES forCharacteristic:characteristic];
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"FF22"]]) {
// 這里要注意有些特征可讀, 有些特征可寫, 有些可以發(fā)通知, 而不是隨便調(diào)用讀寫或者發(fā)通知的方法的
// [peripheral readValueForCharacteristic:characteristic];
// [peripheral discoverDescriptorsForCharacteristic:characteristic];
// 發(fā)送通知
[peripheral setNotifyValue:YES forCharacteristic:characteristic];
}
}
}
- 9 與外設(shè)進(jìn)行數(shù)據(jù)交互(對(duì)于埃微智能手環(huán), 這個(gè)特征中返回的字節(jié)數(shù)肯可能小于20, 那些情況沒有分析, 所以暫且過(guò)濾掉, 如果返回20個(gè)字節(jié)的話, 那么第8, 9位存儲(chǔ)步數(shù); 注意, 這里僅僅針對(duì)埃微智能手環(huán)進(jìn)行的數(shù)據(jù)分析)
/**
* 9.與外設(shè)進(jìn)行數(shù)據(jù)交互
*
* @param peripheral 外設(shè)
* @param characteristic 特征
* @param error 錯(cuò)誤信息
*/
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
if (error) {
NSLog(@"Error updating value for characteristic %@ error: %@", characteristic.UUID, [error localizedDescription]);
return;
}
NSData *data = characteristic.value;
char scartchVal[data.length];
int16_t dataTemp;
[data getBytes:&scartchVal length:data.length];
long len = sizeof(scartchVal) / sizeof(scartchVal[0]);
// 可能返回的字節(jié)數(shù)小于20, 那些情況沒有分析, 所以暫且過(guò)濾掉
if ((sizeof(scartchVal) / sizeof(scartchVal[0])) == 20) {
// 對(duì)于埃微智能手環(huán), 如果返回20個(gè)字節(jié)的話, 那么第8, 9位存儲(chǔ)步數(shù)
dataTemp = ((scartchVal[8] & 0xff) + ((scartchVal[9] << 8) & 0xff00));
self.connectStateLabel.text = @"數(shù)據(jù)同步成功";
self.stepLabel.text = [NSString stringWithFormat:@"%d", dataTemp];
}
```
- 最后這里附上一篇不錯(cuò)的BLE的文章http://www.reibang.com/p/84b5b834b942 (http://www.reibang.com/p/84b5b834b942)