iOS BLE(藍(lán)牙4.0) 讀取埃微i5智能手環(huán)步數(shù)的簡(jiǎn)單實(shí)現(xiàn)

  • 開發(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)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末限寞,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子仰坦,更是在濱河造成了極大的恐慌履植,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件悄晃,死亡現(xiàn)場(chǎng)離奇詭異玫霎,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)妈橄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門庶近,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人眷蚓,你說(shuō)我怎么就攤上這事鼻种。” “怎么了溪椎?”我有些...
    開封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵普舆,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我校读,道長(zhǎng)沼侣,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任歉秫,我火速辦了婚禮蛾洛,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘雁芙。我一直安慰自己轧膘,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開白布兔甘。 她就那樣靜靜地躺著谎碍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪洞焙。 梳的紋絲不亂的頭發(fā)上蟆淀,一...
    開封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天拯啦,我揣著相機(jī)與錄音,去河邊找鬼熔任。 笑死褒链,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的疑苔。 我是一名探鬼主播甫匹,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼惦费!你這毒婦竟也來(lái)了兵迅?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤趁餐,失蹤者是張志新(化名)和其女友劉穎喷兼,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體后雷,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡季惯,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了臀突。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片勉抓。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖候学,靈堂內(nèi)的尸體忽然破棺而出藕筋,到底是詐尸還是另有隱情,我是刑警寧澤梳码,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布隐圾,位于F島的核電站,受9級(jí)特大地震影響掰茶,放射性物質(zhì)發(fā)生泄漏暇藏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一濒蒋、第九天 我趴在偏房一處隱蔽的房頂上張望盐碱。 院中可真熱鬧,春花似錦沪伙、人聲如沸瓮顽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)暖混。三九已至,卻和暖如春翁授,著一層夾襖步出監(jiān)牢的瞬間儒恋,已是汗流浹背善绎。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工黔漂, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留诫尽,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓炬守,卻偏偏與公主長(zhǎng)得像牧嫉,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子减途,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

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

  • 這里我們具體說(shuō)明一下中心模式的應(yīng)用場(chǎng)景酣藻。主設(shè)備(手機(jī)去掃描連接外設(shè),發(fā)現(xiàn)外設(shè)服務(wù)和屬性鳍置,操作服務(wù)和屬性的應(yīng)用辽剧。一般...
    丶逝水流年閱讀 2,238評(píng)論 3 4
  • 藍(lán)牙 藍(lán)牙的波段為2400-2483.5MHz(包括防護(hù)頻帶)。這是全球范圍內(nèi)無(wú)需取得執(zhí)照(但定不是無(wú)管制的)的工...
    蘇永茂閱讀 6,114評(píng)論 0 11
  • (一) iOS藍(lán)牙開發(fā)藍(lán)牙相關(guān)基礎(chǔ)知識(shí) 藍(lán)牙常見名稱和縮寫 MFI ======= make for ipad ...
    雷鳴1010閱讀 4,996評(píng)論 2 12
  • 由于最近工作的東家是一家物聯(lián)網(wǎng)公司,網(wǎng)上BLE相關(guān)的資料確實(shí)比較少,尤其我還做了一些調(diào)試和加密相關(guān)的工作.由于調(diào)試...
    陳長(zhǎng)見閱讀 2,015評(píng)論 5 11
  • 一直以來(lái),總是對(duì)別人的態(tài)度特別敏感辟拷,像一只容易受傷的小動(dòng)物喜歡把自己包裹起來(lái)撞羽。多少次,微笑著面對(duì)迎面走來(lái)的人衫冻,卻換...
    淞淞媽媽閱讀 349評(píng)論 0 0