iOS【藍牙開發(fā)】實踐一 數(shù)據(jù)接發(fā)

說明:這次實踐的主要目的是簡單掌握藍牙的一些基本信息救崔,實現(xiàn)數(shù)據(jù)的接發(fā),中心與外設(shè)互相發(fā)送數(shù)據(jù)暂论,大數(shù)據(jù)分塊發(fā)送。最后為項目鏈接拌禾。

中心1.png
外設(shè)2.png
藍牙基礎(chǔ)(常見縮寫)
MFI: 專們?yōu)樘O果設(shè)備制作的設(shè)備取胎,詳見:關(guān)于MFi認證你所必須要知道的事情;
BLE:藍牙4.0設(shè)備因為低耗電湃窍,所以也叫做BLE闻蛀;
MFI:開發(fā)使用ExternalAccessory 框架;
4.0 BLE:開發(fā)使用CoreBluetooth 框架您市;

Peripheral:外設(shè)觉痛,被連接的設(shè)備為Peripheral;
Central:中心,發(fā)起連接的是Central茵休;
Service:服務(wù)薪棒,每個外設(shè)會有很多服務(wù),每個服務(wù)中包含很多字段榕莺,這些字段的權(quán)限一般分為 讀read俐芯,寫write,通知notiy幾種;
Characteristic:一個服務(wù)下面也可以存在多個特征钉鸯,特征可以理解成具體實現(xiàn)功能的窗口泼各,一般特征都會有value,也就是特征值亏拉,特征是與外界交互的最小單位扣蜻;
Description:每個特征可以對應(yīng)一個或多個Description用戶描述characteristic的信息或?qū)傩裕?UUID:可以理解成藍牙上的唯一標識符,為了區(qū)分不同的服務(wù)和特征及塘,或者給服務(wù)和特征取名字莽使,我們就用UUID來代表服務(wù)和特征;


快速生成UUID:
打開Mac OS X的Terminal.app笙僚,用uuidgen命令生成一個128bit的UUID

//服務(wù)id
#define TRANSFER_SERVICE_UUID  @"0FB51F75-C9D5-45DC-BA61-065BD4A5E3E8"
//特征id
#define TRANSFER_CHARACTERISTIC_UP_UUID @"B678C8E2-9B1A-4952-A320-EF6D42F0831A"

-------------------------------
藍牙中心模式流程:
1. 建立中心角色
2. 掃描外設(shè)(discover)
3. 連接外設(shè)(connect)
4. 掃描外設(shè)中的服務(wù)和特征(discover)
5. 與外設(shè)做數(shù)據(jù)交互(explore and interact)
6. 訂閱Characteristic的通知
7. 斷開連接(disconnect)

中心:首先要導(dǎo)入藍牙庫
#import <CoreBluetooth/CoreBluetooth.h>

遵守協(xié)議
<CBCentralManagerDelegate,CBPeripheralDelegate>

1. 建立中心角色 創(chuàng)建CBCentralManager對象
_centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];

2. 掃描外設(shè)(discover)
//查看設(shè)備是否支持 芳肌,若支持則掃描
-(void)centralManagerDidUpdateState:(CBCentralManager *)central{
    NSArray *uuidArray = [NSArray arrayWithObjects:[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID],nil];
    NSDictionary *optionsDic = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithBool:NO],CBCentralManagerScanOptionAllowDuplicatesKey, nil];
    [_centralManager scanForPeripheralsWithServices:uuidArray options:optionsDic];
}

3. 連接外設(shè)(connect)
-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {

    if (_discoveredPeripheral != peripheral) {
        _discoveredPeripheral = peripheral;
        [_centralManager connectPeripheral:peripheral options:nil];
    }
}

4. 掃描外設(shè)中的服務(wù)和特征(discover)
//當連接成功后,系統(tǒng)會通過回調(diào)函數(shù)告訴我們肋层,然后我們就在這個回調(diào)里去掃描設(shè)備下所有的服務(wù)和特征
-(void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {

    peripheral.delegate = self;
    //指定服務(wù) 
    [peripheral discoverServices:[[NSArray alloc] initWithObjects:[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID], nil]];
    //[peripheral discoverServices:nil];
}

-4.1 獲取外設(shè)的services  6. 訂閱Characteristic的通知
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{

    //處理我們需要的特征
    for (int i=0; i<peripheral.services.count; i++) {
        CBService *service = peripheral.services[i];       
    
        //指定需要查找的特征(對應(yīng)外設(shè)中訂閱特征)
        [peripheral discoverCharacteristics:[[NSArray alloc] initWithObjects:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_Up_UUID],[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_Image_UUID], nil] forService:service];
        //[peripheral discoverCharacteristics:nil forService:service];
    }
}

- 4.2 獲取外設(shè)的Characteristics,獲取Characteristics的值亿笤,獲取Characteristics的Descriptor和Descriptor的
// 5 已搜索到Characteristics
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {

    //屬于那個服務(wù) 根據(jù)不同的特征執(zhí)行不同的命令
    if ([service.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]]) {
    
        for (int i=0; i<service.characteristics.count; i++) {
            CBCharacteristic *characteristic = service.characteristics[i];

            if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_Up_UUID]]) {
                _upCharacteristic = characteristic;
                //監(jiān)聽設(shè)備
                [peripheral setNotifyValue:YES forCharacteristic:characteristic];
            }
        }
    }
}

5. 與外設(shè)做數(shù)據(jù)交互(explore and interact)
///獲取外設(shè)發(fā)來的數(shù)據(jù),不論是read和notify,獲取數(shù)據(jù)都是從這個方法中讀取栋猖。
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
    NSData *dataValue = characteristic.value;
}
//給外設(shè)發(fā)數(shù)據(jù)
- (void)wrietPeripheral:(CBPeripheral *)peripheral characteristic:(CBCharacteristic *)characteristic value:(NSData *)data {

    if(_imageCharacteristic.properties & CBCharacteristicPropertyWrite || _imageCharacteristic.properties & CBCharacteristicPropertyWriteWithoutResponse) {
       [self.discoveredPeripheral writeValue:data forCharacteristic:_imageCharacteristic type:CBCharacteristicWriteWithResponse];
    }
}
// 寫入數(shù)據(jù)后的回調(diào)方法
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
}
停止掃描
[_centralManager stopScan];
主動斷開設(shè)備
[_centralManager cancelPeripheralConnection:_discoveredPeripheral];

大數(shù)據(jù)净薛,分塊發(fā)包
- (void)actionSend:(UIButton *)btn {//發(fā)送大數(shù)據(jù) 分包處理
    NSInteger BLE_SEND_MAX_LEN = 512;
    imgName = [imgName isEqualToString:@"2.jpg"] ? @"3.jpg" : @"2.jpg";
    testImgView.image = [UIImage imageNamed:imgName];

    NSData *msgData = UIImageJPEGRepresentation([UIImage imageNamed:imgName], 1.0);

    for (int i = 0; i < [msgData length]; i += BLE_SEND_MAX_LEN) {
        // 預(yù)加 最大包長度,如果依然小于總數(shù)據(jù)長度蒲拉,可以取最大包數(shù)據(jù)大小
        if ((i + BLE_SEND_MAX_LEN) < [msgData length]) {
            NSString *rangeStr = [NSString stringWithFormat:@"%i,%li", i, (long)BLE_SEND_MAX_LEN];
            NSData *subData = [msgData subdataWithRange:NSRangeFromString(rangeStr)];
            [[HMBLECenterHandle sharedHMBLECenterHandle] wrietPeripheral:nil
                                                          characteristic:nil
                                                                   value:subData];
            //根據(jù)接收模塊的處理能力做相應(yīng)延時
            usleep(20 * 1000);
        }
        else {
            NSString *rangeStr = [NSString stringWithFormat:@"%i,%i", i, (int)([msgData length] - i)];
            NSData *subData = [msgData subdataWithRange:NSRangeFromString(rangeStr)];
       
            [[HMBLECenterHandle sharedHMBLECenterHandle] wrietPeripheral:nil
                                                          characteristic:nil
                                                                   value:subData];
            usleep(20 * 1000);
            
            //發(fā)送結(jié)束標識
            NSData *exoData = [@"exo" dataUsingEncoding:NSUTF8StringEncoding];
            [[HMBLECenterHandle sharedHMBLECenterHandle] wrietPeripheral:nil
                                                          characteristic:nil
                                                                   value:exoData];

        }
    }
}

外設(shè):首先要導(dǎo)入藍牙庫
#import <CoreBluetooth/CoreBluetooth.h>

遵守協(xié)議
<CBPeripheralManagerDelegate>

1. 建立外設(shè)角色 創(chuàng)建CBPeripheralManager對象
_peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil];

2. 本地Peripheral設(shè)置服務(wù),特性,描述肃拜,權(quán)限等等
//1 查看設(shè)備是否支持 ,若支持則創(chuàng)建 服務(wù)和特征
-(void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral{

    //一組特征值
    _upCharacteristic = [[CBMutableCharacteristic alloc] initWithType:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UP_UUID] properties:CBCharacteristicPropertyNotify | CBCharacteristicPropertyRead | CBCharacteristicPropertyWrite | CBCharacteristicPropertyWriteWithoutResponse value:nil permissions:CBAttributePermissionsReadable | CBAttributePermissionsWriteable];

    //一個服務(wù)中添加多個特征值
    transferService = [[CBMutableService alloc] initWithType:[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID] primary:YES];
    NSArray *characters = [[NSArray alloc] initWithObjects:_upCharacteristic, nil];
    [transferService setCharacteristics:characters];

    // 2 添加一個服務(wù)
    [self.peripheralManager addService:transferService];  
}

3. Peripheral發(fā)送廣告
// 3 會監(jiān)聽didAddService
-(void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error{
    NSLog(@"添加服務(wù)");
    if (error != nil) {
        NSLog(@"添加服務(wù)失敶仆拧: %@",error.localizedDescription);
    } else {        
        // 開始廣播
        [self.peripheralManager startAdvertising:@{ CBAdvertisementDataLocalNameKey : @"Service_name", CBAdvertisementDataServiceUUIDsKey :@[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]] }];
    }
}

4. 設(shè)置處理訂閱燃领、取消訂閱、
//當中央端連接上了此設(shè)備并訂閱了特征時會回調(diào) didSubscribeToCharacteristic
-(void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic {
NSLog(@"中心已經(jīng)預(yù)定了特征 --- %@",characteristic);
}

//當中央端取消訂閱時會調(diào)用didUnsubscribeFromCharacteristic
-(void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic {
NSLog(@"中心沒有從特征預(yù)定 -- %@",characteristic);
}

 4. 讀characteristic锦援、寫characteristic的委托方法
//當接收到中央端讀的請求時會調(diào)用didReceiveReadRequest
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveReadRequest:(CBATTRequest *)request {
    if (request.characteristic.properties & CBCharacteristicPropertyRead) {
        NSData *data = request.characteristic.value;        
        [request setValue:data];
        [self.peripheralManager respondToRequest:request withResult:CBATTErrorSuccess];
    } else {
        [self.peripheralManager respondToRequest:request withResult:CBATTErrorReadNotPermitted];
    }
}

//當接收到中央端寫的請求時會調(diào)用didReceiveWriteRequest
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray<CBATTRequest *> *)requests {
CBATTRequest *request = requests[0];
    if (request.characteristic.properties & CBCharacteristicPropertyWrite) {
        CBMutableCharacteristic *c = (CBMutableCharacteristic *)request.characteristic;
        c.value = request.value;
        NSData *data = c.value;
       [self.peripheralManager respondToRequest:request withResult:CBATTErrorSuccess];
    } else {
        [self.peripheralManager respondToRequest:request withResult:CBATTErrorWriteNotPermitted];
    }
}

4. 往中心發(fā)送數(shù)據(jù)
- (BOOL)updateValue:(NSData *)value characteristic:(CBMutableCharacteristic *)characteristic {

    if (value && characteristic) {
       return [self.peripheralManager updateValue:value forCharacteristic:characteristic onSubscribedCentrals:nil];
    }
    return NO;
}

項目Demo:藍牙外設(shè) 猛蔽、藍牙中心

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市灵寺,隨后出現(xiàn)的幾起案子曼库,更是在濱河造成了極大的恐慌,老刑警劉巖替久,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件凉泄,死亡現(xiàn)場離奇詭異,居然都是意外死亡蚯根,警方通過查閱死者的電腦和手機后众,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來颅拦,“玉大人蒂誉,你說我怎么就攤上這事【嗨В” “怎么了右锨?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長碌秸。 經(jīng)常有香客問我绍移,道長悄窃,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任蹂窖,我火速辦了婚禮轧抗,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘瞬测。我一直安慰自己横媚,他們只是感情好,可當我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布月趟。 她就那樣靜靜地躺著灯蝴,像睡著了一般。 火紅的嫁衣襯著肌膚如雪孝宗。 梳的紋絲不亂的頭發(fā)上穷躁,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天,我揣著相機與錄音碳褒,去河邊找鬼折砸。 笑死,一個胖子當著我的面吹牛沙峻,可吹牛的內(nèi)容都是我干的睦授。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼摔寨,長吁一口氣:“原來是場噩夢啊……” “哼去枷!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起是复,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤删顶,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后淑廊,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體逗余,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年季惩,在試婚紗的時候發(fā)現(xiàn)自己被綠了录粱。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡画拾,死狀恐怖啥繁,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情青抛,我是刑警寧澤旗闽,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響适室,放射性物質(zhì)發(fā)生泄漏嫡意。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一亭病、第九天 我趴在偏房一處隱蔽的房頂上張望鹅很。 院中可真熱鬧,春花似錦罪帖、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至佑吝,卻和暖如春坐昙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背芋忿。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工炸客, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人戈钢。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓痹仙,卻偏偏與公主長得像,于是被迫代替她去往敵國和親殉了。 傳聞我的和親對象是個殘疾皇子开仰,可洞房花燭夜當晚...
    茶點故事閱讀 44,779評論 2 354

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