iOS CoreBluetooth開發(fā)

本文主要參考如下鏈接:
http://blog.csdn.net/pony_maggie/article/details/26740237
http://blog.csdn.net/VictorMoKai/article/details/42395669
http://blog.csdn.net/m372897500/article/details/50662976

iOS 藍牙介紹

藍牙協(xié)議本身經(jīng)歷了從1.0到4.0的升級演變, 最新的4.0以其低功耗著稱壳坪,所以一般也叫BLE(Bluetoothlow energy)。

iOS 有兩個框架支持藍牙與外設(shè)連接桶蝎。一個是 ExternalAccessory薯嗤。從iOS3.0就開始支持,也是在iPhone4S出來之前用的比較多的一種模式,但是它有個不好的地方用狱,External Accessory需要拿到蘋果公司的MFI認證。

另一個框架則是本文要介紹的CoreBluetooth,在iphone4s開始支持,專門用于與BLE設(shè)備通訊(因為它的API都是基于BLE的)霜医。這個不需要MFI齿拂,并且現(xiàn)在很多藍牙設(shè)備都支持4.0,所以也是在IOS比較推薦的一種開發(fā)方法驳规。

CoreBluetooth介紹

CoreBluetooth框架的核心其實是兩個東西肴敛,Peripheral和Central, 可以理解成外設(shè)和中心。其中Peripheral外設(shè)相當于Socket編程中的Server服務(wù)端吗购,Central中心相當于Client客戶端医男。


你可以理解外設(shè)是一個廣播數(shù)據(jù)的設(shè)備,它開始告訴外面的世界說它這兒有一些數(shù)據(jù)捻勉,并且能提供一些服務(wù)镀梭。另一邊中心開始掃描周邊有沒有合適的設(shè)備,如果發(fā)現(xiàn)后踱启,會和外設(shè)做連接請求报账,一旦連接確定后,兩個設(shè)備就可以傳輸數(shù)據(jù)了埠偿。

在iOS6之后透罢,iOS 設(shè)備可以是外設(shè),也可以是中心冠蒋,就像Socket編程中一樣羽圃,你可以是服務(wù)端也可以是客戶端,但與Socket不同的是不能在同時間扮演兩個角色抖剿。

服務(wù)(service)和特征(characteristic)

每個藍牙4.0的設(shè)備都是通過服務(wù)和特征來展示自己的朽寞,一個設(shè)備必然包含一個或多個服務(wù)识窿,每個服務(wù)下面又包含若干個特征。特征是與外界交互的最小單位脑融。比如說喻频,智能音響設(shè)備,用服務(wù)A標識播放模塊肘迎,特征A1來表示播放上一首半抱,特征A2來表示播放下一首;服務(wù)B標識設(shè)置模塊膜宋,特征B1設(shè)置彩燈顏色窿侈。這樣做的目的主要為了模塊化。

服務(wù)和特征都是用UUID來唯一標識的秋茫,UUID的概念如果不清楚請自行g(shù)oogle,國際藍牙組織為一些很典型的設(shè)備(比如測量心跳和血壓的設(shè)備)規(guī)定了標準的service UUID史简。

CoreBluetooth框架的核心其實是兩個東西,peripheral和central, 可以理解成外設(shè)和中心肛著。對應(yīng)他們分別有一組相關(guān)的API和類圆兵,如下圖所示:


上面說了設(shè)備可以是外設(shè),也可以是中心枢贿,也就是 本地中心->遠程外設(shè) 殉农、本地外設(shè)->遠程中心,
不過在智能家居開發(fā)中局荚,大部分硬件藍牙都是擔任外設(shè)的角色超凳,也就是說我們應(yīng)用只要扮演中心即可了。

本地中心與遠程外設(shè)

在中心這邊耀态,由CBCentralManager對象管理本地中心轮傍,來發(fā)現(xiàn)或連接遠程外設(shè)。此時
正在連接的外設(shè)用CBPeripheral 對象表示首装。

遠程外設(shè)的數(shù)據(jù)由CBService和CBCharacteristic對象表示
當你與遠程外設(shè)CBPeripheral對象進行數(shù)據(jù)交互時创夜,是由一個服務(wù)與特征操作的。


實現(xiàn)細節(jié)

作為一個中心要實現(xiàn)完整的通訊仙逻,一般要經(jīng)過這樣幾個步驟:

  1. 建立中心角色
  1. 掃描外設(shè)(discover)
  2. 連接外設(shè)(connect)
  3. 掃描外設(shè)中的服務(wù)和特征(discover)
    -獲取外設(shè)的services
    -獲取外設(shè)的Characteristics,獲取Characteristics的值驰吓,獲取Characteristics的Descriptor和Descriptor的值
  4. 與外設(shè)做數(shù)據(jù)交互(explore and interact)
  5. 訂閱Characteristic的通知
  6. 斷開連接(disconnect)
1.導入CoreBluetooth頭文件,建立主設(shè)備管理類系奉,設(shè)置主設(shè)備委托

首先在我自己類的頭文件中要包含CoreBluetooth的頭文件檬贰,并繼承兩個協(xié)議<CBCentralManagerDelegate,CBPeripheralDelegate>,代碼如下:

#import <CoreBluetooth/CoreBluetooth.h>  
@interface ViewController (){  
        //系統(tǒng)藍牙設(shè)備管理對象喜最,可以把他理解為主設(shè)備偎蘸,通過他,可以去掃描和鏈接外設(shè)  
        CBCentralManager *manager;  
}  
  
- (void)viewDidLoad {  
        [super viewDidLoad];  
        /* 
         設(shè)置主設(shè)備的委托,CBCentralManagerDelegate 
            必須實現(xiàn)的: 
            - (void)centralManagerDidUpdateState:(CBCentralManager *)central;//主設(shè)備狀態(tài)改變的委托,在初始化CBCentralManager的適合會打開設(shè)備迷雪,只有當設(shè)備正確打開后才能使用 
            其他選擇實現(xiàn)的委托中比較重要的: 
            - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI; //找到外設(shè)的委托 
            - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral;//連接外設(shè)成功的委托 
            - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;//外設(shè)連接失敗的委托 
            - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;//斷開外設(shè)的委托 
        */  
         //初始化并設(shè)置委托和線程隊列限书,最好一個線程的參數(shù)可以為nil,默認會就main線程  
         manager = [[CBCentralManager alloc]initWithDelegate:self queue:dispatch_get_main_queue()];  
}
2. 掃描外設(shè)(discover)章咧,掃描外設(shè)的方法我們放在centralManager成功打開的委托中倦西,因為只有設(shè)備成功打開,才能開始掃描赁严,否則會報錯扰柠。

-(void)centralManagerDidUpdateState:(CBCentralManager *)central{
    switch (central.state){
        case CBCentralManagerStateUnknown:
            NSLog(@">>>CBCentralManagerStateUnknown");
            _statusLabel.text = @"CBCentralManagerStateUnknown";
            break;
        case CBCentralManagerStateResetting:
            NSLog(@">>>CBCentralManagerStateResetting");
            _statusLabel.text = @"CBCentralManagerStateResetting";
            break;
        case CBCentralManagerStateUnsupported:
            NSLog(@">>>CBCentralManagerStateUnsupported");
            _statusLabel.text = @"CBCentralManagerStateUnsupported";
            break;
        case CBCentralManagerStateUnauthorized:
            NSLog(@">>>CBCentralManagerStateUnauthorized");
            _statusLabel.text = @"CBCentralManagerStateUnauthorized";
            break;
        case CBCentralManagerStatePoweredOff:
            NSLog(@">>>CBCentralManagerStatePoweredOff");
            _statusLabel.text = @"CBCentralManagerStatePoweredOff";
            break;
        case CBCentralManagerStatePoweredOn:
        {
            NSLog(@">>>CBCentralManagerStatePoweredOn");
            _statusLabel.text = @"CBCentralManagerStatePoweredOn";
            //開始掃描周圍的外設(shè)
            /*第一個參數(shù)nil就是掃描周圍所有的外設(shè),掃描到外設(shè)后會進入
             - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI;
          */
            NSDictionary * dic = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:false],CBCentralManagerScanOptionAllowDuplicatesKey, nil];
            [manager scanForPeripheralsWithServices:nil options:dic];
        }
            break;
        default:
            break;
    }
    
}

- (BOOL)addBtPeripheralToArray:(CBPeripheral*)peripheral{
    if (![_btPeripheralsArray containsObject:peripheral] && peripheral.name.length > 0) {
        for (CBPeripheral* existPeripheral in _btPeripheralsArray) {
            if ([existPeripheral.identifier.UUIDString isEqualToString:peripheral.identifier.UUIDString]) {
                return NO;
            }
        }
        
        [_btPeripheralsArray addObject:peripheral];
        return YES;
    }
    return NO;
}

//掃描到設(shè)備會進入方法
-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{
    
    NSLog(@"掃描到設(shè)備:%@",peripheral.name);
    if ([self addBtPeripheralToArray:peripheral]) {
        [_btListView reloadData];
    }

    
}
3. 連接外設(shè)(connect)

在剛剛存入數(shù)組的外設(shè)中選擇一個外設(shè)疼约,然后調(diào)用tryToConnectPeripheral方法

- (void)tryToConnectPeripheral:(CBPeripheral*)peripheral{
    //接下來可以連接設(shè)備
    //接下連接我們的測試設(shè)備卤档,如果你沒有設(shè)備,可以下載一個app叫l(wèi)ightbule的app去模擬一個設(shè)備

    /*
     一個主設(shè)備最多能連7個外設(shè)程剥,每個外設(shè)最多只能給一個主設(shè)備連接,連接成功劝枣,失敗,斷開會進入各自的委托
     - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral;//連接外設(shè)成功的委托
     - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;//外設(shè)連接失敗的委托
     - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;//斷開外設(shè)的委托
     */
    //連接設(shè)備
    _statusLabel.text = @"連接中织鲸。舔腾。。";
    [manager connectPeripheral:peripheral options:nil];

}

嘗試連接后搂擦,CoreBluetooth會把連接狀態(tài)通過代理發(fā)送給調(diào)用者

//連接到Peripherals-成功
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
    NSLog(@">>>連接到名稱為(%@)的設(shè)備-成功",peripheral.name);
    
    //設(shè)置的peripheral委托CBPeripheralDelegate
    //@interface ViewController : UIViewController
    [peripheral setDelegate:self];
    //掃描外設(shè)Services稳诚,成功后會進入方法:-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
    [peripheral discoverServices:nil];
    
}

//連接到Peripherals-失敗
-(void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
    NSLog(@">>>連接到名稱為(%@)的設(shè)備-失敗,原因:%@",[peripheral name],[error localizedDescription]);
}

//Peripherals斷開連接
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
    NSLog(@">>>外設(shè)連接斷開連接 %@: %@\n", [peripheral name], [error localizedDescription]);
    
}
4. 掃描外設(shè)中的服務(wù)和特征(discover)

設(shè)備連接成功后,就可以掃描設(shè)備的服務(wù)了瀑踢,同樣是通過委托形式扳还,掃描到結(jié)果后會進入委托方法。
但是這個委托已經(jīng)不再是主設(shè)備的委托(CBCentralManagerDelegate)丘损,而是外設(shè)的委托(CBPeripheralDelegate),這個委托包含了主設(shè)備與外設(shè)交互的許多回調(diào)方法普办,包括獲取services工扎,獲取characteristics徘钥,獲取characteristics的值,獲取characteristics的Descriptor肢娘,和Descriptor的值呈础,寫數(shù)據(jù),讀rssi橱健,用通知的方式訂閱數(shù)據(jù)等等而钞。

4.1 獲取外設(shè)的services
//掃描到Services
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
    NSLog(@">>>掃描到服務(wù):%@",peripheral.services);
    NSLog(@"***begin<%s>***",__func__);
    if (error)
    {
        NSLog(@">>>Discovered services for %@ with error: %@", peripheral.name, [error localizedDescription]);
        return;
    }
    
    for (CBService *service in peripheral.services) {
        NSLog(@"UUID: %@",service.UUID);
        //掃描每個service的Characteristics,掃描到后會進入方法: -(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
        [peripheral discoverCharacteristics:nil forService:service];
    }
    NSLog(@"***end***");
    
}
4.2 獲取外設(shè)的Characteristics,獲取Characteristics的值拘荡,獲取Characteristics的Descriptor和Descriptor的值
//掃描到Characteristics
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
    
    
    if (error)
    {
        NSLog(@"error Discovered characteristics for %@ with error: %@", service.UUID, [error localizedDescription]);
        return;
    }
    
    //獲取Characteristic的值臼节,讀到數(shù)據(jù)會進入方法:-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
    for (CBCharacteristic *characteristic in service.characteristics){
        {
            [peripheral readValueForCharacteristic:characteristic];
        }
    }
    
    //搜索Characteristic的Descriptors,讀到數(shù)據(jù)會進入方法:-(void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
    for (CBCharacteristic *characteristic in service.characteristics){
        [peripheral discoverDescriptorsForCharacteristic:characteristic];
    }

}

//獲取的charateristic的值
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    //打印出characteristic的UUID和值
    //!注意,value的類型是NSData网缝,具體開發(fā)時巨税,會根據(jù)外設(shè)協(xié)議制定的方式去解析數(shù)據(jù)

    NSLog(@"characteristic uuid:%@  value:%@",characteristic.UUID,characteristic.value);

}

//搜索到Characteristic的Descriptors
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    
    //打印出Characteristic和他的Descriptors

    NSLog(@"characteristic uuid:%@",characteristic.UUID);
    for (CBDescriptor *d in characteristic.descriptors) {
        NSLog(@"Descriptor uuid:%@",d.UUID);
    }

    
}
//獲取到Descriptors的值
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForDescriptor:(CBDescriptor *)descriptor error:(NSError *)error{
    //打印出DescriptorsUUID 和value
    //這個descriptor都是對于characteristic的描述,一般都是字符串粉臊,所以這里我們轉(zhuǎn)換成字符串去解析

    NSLog(@"characteristic uuid:%@  value:%@",[NSString stringWithFormat:@"%@",descriptor.UUID],descriptor.value);

}



5. 把數(shù)據(jù)寫到Characteristic中

//寫數(shù)據(jù)
-(void)writeCharacteristic:(CBPeripheral *)peripheral
            characteristic:(CBCharacteristic *)characteristic
                     value:(NSData *)value{
    
    //打印出 characteristic 的權(quán)限草添,可以看到有很多種,這是一個NS_OPTIONS扼仲,就是可以同時用于好幾個值远寸,常見的有read,write屠凶,notify驰后,indicate,知知道這幾個基本就夠用了矗愧,前連個是讀寫權(quán)限倡怎,后兩個都是通知,兩種不同的通知方式贱枣。
    /*
     typedef NS_OPTIONS(NSUInteger, CBCharacteristicProperties) {
     CBCharacteristicPropertyBroadcast                                              = 0x01,
     CBCharacteristicPropertyRead                                                   = 0x02,
     CBCharacteristicPropertyWriteWithoutResponse                                   = 0x04,
     CBCharacteristicPropertyWrite                                                  = 0x08,
     CBCharacteristicPropertyNotify                                                 = 0x10,
     CBCharacteristicPropertyIndicate                                               = 0x20,
     CBCharacteristicPropertyAuthenticatedSignedWrites                              = 0x40,
     CBCharacteristicPropertyExtendedProperties                                     = 0x80,
     CBCharacteristicPropertyNotifyEncryptionRequired NS_ENUM_AVAILABLE(NA, 6_0)        = 0x100,
     CBCharacteristicPropertyIndicateEncryptionRequired NS_ENUM_AVAILABLE(NA, 6_0)  = 0x200
     };
     
     */
    NSLog(@"%lu", (unsigned long)characteristic.properties);
    
    
    //只有 characteristic.properties 有write的權(quán)限才可以寫
    if(characteristic.properties & CBCharacteristicPropertyWrite){
        /*
         最好一個type參數(shù)可以為CBCharacteristicWriteWithResponse或type:CBCharacteristicWriteWithResponse,區(qū)別是是否會有反饋
         */
        [peripheral writeValue:value forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
    }else{
        NSLog(@"該字段不可寫监署!");
    }
    
    
}
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{

    NSLog(@"characteristic uuid:%@ error:%@",characteristic.UUID,error);
    
}
6 訂閱Characteristic的通知

通常,與藍牙設(shè)備的交互是這樣進行的:
監(jiān)聽A特性(訂閱Characteristic的通知)->寫B(tài)特性來請求數(shù)據(jù)->請求的數(shù)據(jù)從A特性返回纽哥。
這時钠乏,就需要我們訂閱通知,訂閱通知以后春塌,如果有數(shù)據(jù)更新晓避,didUpdateValueForCharacteristic就會被調(diào)用


//設(shè)置通知
-(void)notifyCharacteristic:(CBPeripheral *)peripheral
             characteristic:(CBCharacteristic *)characteristic{
    //設(shè)置通知,數(shù)據(jù)通知會進入:didUpdateValueForCharacteristic方法
    [peripheral setNotifyValue:YES forCharacteristic:characteristic];
    
}

//取消通知
-(void)cancelNotifyCharacteristic:(CBPeripheral *)peripheral
                   characteristic:(CBCharacteristic *)characteristic{
    
    [peripheral setNotifyValue:NO forCharacteristic:characteristic];
}
7 斷開連接(disconnect)
//停止掃描并斷開連接
-(void)disconnectPeripheral:(CBCentralManager *)centralManager
                 peripheral:(CBPeripheral *)peripheral{
    //停止掃描
    [centralManager stopScan];
    //斷開連接
    [centralManager cancelPeripheralConnection:peripheral];
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末只壳,一起剝皮案震驚了整個濱河市俏拱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌吼句,老刑警劉巖锅必,帶你破解...
    沈念sama閱讀 211,948評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異惕艳,居然都是意外死亡搞隐,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評論 3 385
  • 文/潘曉璐 我一進店門远搪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來劣纲,“玉大人,你說我怎么就攤上這事谁鳍●荆” “怎么了劫瞳?”我有些...
    開封第一講書人閱讀 157,490評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長绷柒。 經(jīng)常有香客問我柠新,道長,這世上最難降的妖魔是什么辉巡? 我笑而不...
    開封第一講書人閱讀 56,521評論 1 284
  • 正文 為了忘掉前任恨憎,我火速辦了婚禮,結(jié)果婚禮上郊楣,老公的妹妹穿的比我還像新娘憔恳。我一直安慰自己,他們只是感情好净蚤,可當我...
    茶點故事閱讀 65,627評論 6 386
  • 文/花漫 我一把揭開白布钥组。 她就那樣靜靜地躺著,像睡著了一般今瀑。 火紅的嫁衣襯著肌膚如雪程梦。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,842評論 1 290
  • 那天橘荠,我揣著相機與錄音屿附,去河邊找鬼。 笑死哥童,一個胖子當著我的面吹牛挺份,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播贮懈,決...
    沈念sama閱讀 38,997評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼匀泊,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了朵你?” 一聲冷哼從身側(cè)響起各聘,我...
    開封第一講書人閱讀 37,741評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎抡医,沒想到半個月后躲因,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,203評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡魂拦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,534評論 2 327
  • 正文 我和宋清朗相戀三年毛仪,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片芯勘。...
    茶點故事閱讀 38,673評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖腺逛,靈堂內(nèi)的尸體忽然破棺而出荷愕,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 34,339評論 4 330
  • 正文 年R本政府宣布安疗,位于F島的核電站抛杨,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏荐类。R本人自食惡果不足惜怖现,卻給世界環(huán)境...
    茶點故事閱讀 39,955評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望玉罐。 院中可真熱鬧屈嗤,春花似錦、人聲如沸吊输。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽季蚂。三九已至茫船,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間扭屁,已是汗流浹背算谈。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留料滥,地道東北人濒生。 一個月前我還...
    沈念sama閱讀 46,394評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像幔欧,于是被迫代替她去往敵國和親罪治。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,562評論 2 349

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

  • (一) iOS藍牙開發(fā)藍牙相關(guān)基礎(chǔ)知識 藍牙常見名稱和縮寫 MFI ======= make for ipad ...
    雷鳴1010閱讀 4,999評論 2 12
  • 最近音響項目要用到藍牙開發(fā)功能礁蔗,所以查找了一些藍牙的基本資料學習一下觉义,藍牙的應(yīng)用領(lǐng)域很廣,比如浴井,手環(huán)晒骇,車載設(shè)備,音...
    皮皮強閱讀 858評論 0 0
  • 這里我們具體說明一下中心模式的應(yīng)用場景磺浙。主設(shè)備(手機去掃描連接外設(shè)洪囤,發(fā)現(xiàn)外設(shè)服務(wù)和屬性,操作服務(wù)和屬性的應(yīng)用撕氧。一般...
    丶逝水流年閱讀 2,243評論 3 4
  • 本文主要以藍牙4.0做介紹,因為現(xiàn)在iOS能用的藍牙也就是只僅僅4.0的設(shè)備 用的庫就是core bluetoot...
    暮雨飛煙閱讀 832評論 0 2
  • 喜歡就要放肆瘤缩,愛就不要克制,當喜歡不在放肆伦泥,當愛變成克制剥啤,說明我們長大了锦溪,成熟了............
    那個女作家閱讀 76評論 1 1