iOS 蓝牙开发

前言:此篇文章只针对第一次接触蓝牙的小白,文章中仅仅描述了如何连接蓝牙、如何发送数据 、可能遇到的问题 等。对于其他专业性的名词没有做相应的描述。

一、准备工作
1、iOS使用蓝牙 必须先允许定位,所以需要开启定位。使用蓝牙需要用户同意才可使用 所以 工程info.plist 文件中需要添加 定位请求和蓝牙请求的权限

定位权限
Privacy - Location When In Use Usage Description 

蓝牙权限
Privacy - Bluetooth Peripheral Usage Description

2、使用蓝牙首先要准备几个UUID

服务UUID
#define BLE_SERVICE_UUID   @"0000XXXX-0000-1000-8000-00805f9b34fb"

读UUID
#define BLE_INDICATE_CHARACTERISTIC_UUID   @"0000XXXX-0000-1000-8000-00805f9b34fb"

写UUID
#define BLE_WRITE_CHARACTERISTIC_UUID   @"0000XXXX-0000-1000-8000-00805f9b34fb"

这几个UUID开发硬件的工程师会直接给你。作用后面会有所体验

二、设置相关代码

1、首先引入蓝牙和定位所需框架

#import <SystemConfiguration/CaptiveNetwork.h>
#import <CoreLocation/CoreLocation.h>
#import <CoreBluetooth/CoreBluetooth.h>

2、其次引入代理

CBCentralManagerDelegate
CBPeripheralDelegate

3、然后声明属性

@property (nonatomic, strong) CBCentralManager  * bluetoothManager;
@property (nonatomic, strong) CLLocationManager * locationManager;
@property (nonatomic, strong) CBPeripheral      * currentPer;

4、设置定位

- (void)location {
    NSString* phoneVersion = [[UIDevice currentDevice] systemVersion];
    CGFloat version = [phoneVersion floatValue];
    // 如果是iOS13 未开启地理位置权限 需要提示一下
    if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined && version >= 13) {
      self.locationManager = [[CLLocationManager alloc] init];
      [self.locationManager requestWhenInUseAuthorization];
    }
}

重点来了,以下代码是蓝牙相关的代码

1、初始化 CBCentralManager

#pragma mark--  CBCentralManager的实例对象
- (void)initCBCentralManager{
    NSDictionary *options = @{CBCentralManagerOptionShowPowerAlertKey: @YES};
    CBCentralManager* cBCentralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:options];
    self.bluetoothManager = cBCentralManager;
}

2、 CBCentralManagerDelegate回调:返回蓝牙的状态 在此函数中可以提醒用户打开蓝牙等操作

#pragma mark--  CBCentralManagerDelegate回调:(开启/关闭蓝牙,也就是蓝牙的状态)
- (void)centralManagerDidUpdateState:(CBCentralManager*)central{
    if (central.state == CBCentralManagerStatePoweredOn) {
        NSLog(@"蓝牙已经打开");
    } else if (central.state == CBManagerStatePoweredOff) {
        NSLog(@"蓝牙已经关闭");
    }
}

3、开始扫描蓝牙设备

#pragma  mark-- 开始扫描设备(也就是开始扫描蓝牙)
- (void)scanDevice{
    [self.bluetoothManager scanForPeripheralsWithServices:nil options:nil];
}

4、蓝牙设备扫描结果回调:在此方法中找到你想要连接的蓝牙设备然后去连接设备

#pragma mark--  CBCentralManagerDelegate回调:蓝牙搜索结果回调
- (void)centralManager:(CBCentralManager*)central didDiscoverPeripheral:(CBPeripheral*)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber*)RSSI{
    NSString *scanedName=advertisementData[@"kCBAdvDataLocalName"];
    if (scanedName.length>0) {
        NSLog(@"扫描到设备scanedName=:%@",scanedName);
    }
    if ([scanedName hasPrefix:@"aux-5802"]) {
        self.currentPer = peripheral;
        // 发现设备后,请求连接设备
        [self connectedDevices];
    }
}


#pragma mark-- 开始连接设备:
- (void)connectedDevices{
    [self.bluetoothManager connectPeripheral:self.currentPer options:nil];
}

5、连接状态回调

#pragma mark-- 链接状态回调
///连接成功
- (void)centralManager:(CBCentralManager*)central didConnectPeripheral:(CBPeripheral*)peripheral{
    NSLog(@"连接成功");
    //连接成功停止搜索
    [self.bluetoothManager stopScan];

    self.currentPer = peripheral;

//连接成功后,扫描外围设备的服务CBService:
  [self scanDeviceCBService];
    
}

///连接失败
- (void)centralManager:(CBCentralManager*)central didFailToConnectPeripheral:(CBPeripheral*)peripheral error:(NSError*)error{
    NSLog(@"连接失败---%@",error);
}

///断开连接结果
- (void)centralManager:(CBCentralManager*)central didDisconnectPeripheral:(CBPeripheral*)peripheral error:(NSError*)error{
    NSLog(@"断开链接");
}


#pragma mark-- 连接成功后,扫描外围设备的服务CBService:
- (void)scanDeviceCBService{
    self.currentPer.delegate = self;
    [ self.currentPer discoverServices:@[[CBUUID UUIDWithString:BLE_SERVICE_UUID]]];
}

6、 扫描服务结果会通过CBPeripheralDelegate回调 返回

#pragma mark-- 扫描服务结果会通过CBPeripheralDelegate回调:
- (void)peripheral:(CBPeripheral*)peripheral didDiscoverServices:(NSError*)error{
    for (CBService *service in peripheral.services) {
        if ([service.UUID isEqual:[CBUUID UUIDWithString:BLE_SERVICE_UUID]]) {
            //查找特征
            [self.currentPer discoverCharacteristics:nil forService:service];
        }
    }
}

7、查询特征结果会通过CBPeripheralDelegate回调:返回

#pragma mark--查询特征结果会通过CBPeripheralDelegate回调:
-(void)peripheral:(CBPeripheral*)peripheral didDiscoverCharacteristicsForService:(CBService*)service error:(NSError*)error{
    for (CBCharacteristic *character in service.characteristics) {
        NSLog(@"%@",character);
      
        if ([character.UUID isEqual:[CBUUID UUIDWithString:BLE_WRITE_CHARACTERISTIC_UUID]]) { 
  // 写

//注意:1、这里的 writeValue: 传的是一个NSData类型的数据 这个数据硬件需要什么 你传什么就可以了。

//注意:2、这里的 type :你需要查看硬件给你返回的什么类型然后你填什么类型就可以了,这个类型可以打印 character 查看他的 properties属性  如果硬件返回的是 0x04(CBCharacteristicPropertyWriteWithoutResponse) 那你就需要填写对应的(CBCharacteristicWriteWithoutResponse)即可,切记这一点 否则会报 读或写没有权限的 问题
            [self.currentPer writeValue:   data forCharacteristic:character type:CBCharacteristicWriteWithoutResponse];
        }else if ([character.UUID isEqual:[CBUUID UUIDWithString:BLE_INDICATE_CHARACTERISTIC_UUID]]) {
  // 读
            [self.currentPer setNotifyValue:YES forCharacteristic:character];
        }
    }   
}

8、特征的数据也是通过CBPeripheralDelegate回调

#pragma mark-- 特征的数据也是通过CBPeripheralDelegate回调:
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
    NSLog(@"peripheral:%@ \n\n characteristic:%@ \n\n error:%@",peripheral, characteristic, error);
    [peripheral readValueForCharacteristic:characteristic];
}

9、蓝牙返回数据 代理方法 :这里可能会出现 Reading is not permitted 或则 Writing is not permitted 出现这个 问题不要着急 首先检查 硬件给你的 读写UUID是否正确 如果正确 再次检查 第七步 ( [self.currentPer writeValue: data forCharacteristic:character type:CBCharacteristicWriteWithoutResponse]; )中的 type是否与硬件返回的一致 确保这两点基本没有什么问题了

- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
    if (error) {
        NSLog(@"%@",error);
    } else {
        NSData *responseData = characteristic.value;
        NSLog(@"%@",responseData);

//注意:蓝牙返回的也是 NSData类型的数据 拿到数据解析数据就就可以了
        [self auxCmdParse:responseData];//这一步是解析数据
    }
}

补充:
向蓝牙发送数据包(数据包的格式跟硬件协商好)

- (NSData*)getData{
    NSString *ssid = self.ssid;
    NSString *key= self.password;
    NSString *paas_address= self.paas_address;
    NSString *m2m_address= self.m2m_address;
    NSString *apCode= self.apCode;;
    NSMutableData *allMData = [[NSMutableData alloc] init];
    NSData *ssidData = [ssid dataUsingEncoding: NSUTF8StringEncoding];
    NSData *keyData = [key dataUsingEncoding: NSUTF8StringEncoding];
    NSData *paas_addressData = [paas_address dataUsingEncoding:NSUTF8StringEncoding];
    NSData *m2m_addressData = [m2m_address dataUsingEncoding:NSUTF8StringEncoding];
    NSData *apcodeData = [apCode dataUsingEncoding:NSUTF8StringEncoding];
    unsigned long length = 8+(ssidData.length)+(keyData.length)+(apcodeData.length)+(m2m_addressData.length)+(paas_addressData.length)+7;
    
    Byte bhead[]= {0xa5, 0xa5, length & 0xFF, 0x00, 0x01, 0x00, 0x00,0x00};
    
    [allMData appendBytes:bhead length:8];
    Byte blen[]= {ssidData.length & 0xFF};
    [allMData appendBytes:blen length:1];
    if (blen[0]>0){
        [allMData appendBytes:[ssidData bytes] length:blen[0]];
    }
    //    //
    blen[0]= keyData.length & 0xFF;
    [allMData appendBytes:blen length:1];
    if (blen[0]>0){
        [allMData appendBytes:[keyData bytes] length:blen[0]];
    }
    
    
    blen[0]= apcodeData.length & 0xFF;
    [allMData appendBytes:blen length:1];
    if (blen[0]>0){
        [allMData appendBytes:[apcodeData bytes] length:blen[0]];
    }
    
    //    //
    blen[0]= paas_addressData.length & 0xFF;
    [allMData appendBytes:blen length:1];
    if (blen[0]>0){
        [allMData appendBytes:[paas_addressData bytes] length:blen[0]];
    }
    //
    //
    blen[0]= m2m_addressData.length & 0xFF;
    [allMData appendBytes:blen length:1];
    if (blen[0]>0){
        [allMData appendBytes:[m2m_addressData bytes] length:blen[0]];
    }
    
    
    
    int crc= [CRC crc16CCIT:allMData andLen:(int)allMData.length];
    Byte bcrc[]= {(crc>>8)&0x0ff, crc&0x0ff};
    [allMData appendBytes:bcrc length:2];
    
    return allMData;
}

接收蓝牙发来的数据包(按照规定的顺序解包)

- (Boolean)cmdParse:(NSData *)data{
    Byte *b= (Byte *)[data bytes];
    if (b[0]== 0xa5 && b[1]== 0xa5
        && b[4]== 0x01 && b[5]== 0x10
        && b[6]== 0x00 && b[7]== 0x00
        && b[8]== 0x00 && b[9]== 0x00){
        int crcCal= [CRC crc16CCIT:data andLen:(int)data.length-2];
        int crcRcv= ((b[data.length-2] & 0x0ff) << 8) | (b[data.length-1] & 0x0ff);
        if (crcCal == crcRcv){
            _auxRplMac= [NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X", b[11], b[12], b[13], b[14], b[15], b[16]];
            _auxRplPasscode= [self toHexString:b start:18 Len:b[17]];
            NSLog(@"%@",_auxRplMac);
            NSLog(@"%@",_auxRplPasscode);
            return true;
        }
    }
    return false;
}

- (NSString *)toHexString:(Byte *)b start:(int)start Len:(int)len{
    NSString *str= @"";
    for (int i=0; i<len; i++){
        str= [NSString stringWithFormat:@"%@%02X", str, b[start+i]];
    }
    return str;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容

  • 首先先明白几个名词:Central(中心设备)、Peripheral(外围设备)、advertising(广告)、...
    shuaikun阅读 403评论 0 0
  • iOS的蓝牙数据接收以及发送 名词:Central(中心设备)、Peripheral(外围设备)、advertis...
    TianBai阅读 22,574评论 54 304
  • iOS 中使用 Core Bluetooth 框架实现蓝牙通信。Core Bluetooth 是基于蓝牙 4.0 ...
    欧大帅Allen阅读 2,686评论 0 3
  • 相比于网络请求,蓝牙是一种低功耗(low-energy)的通信手段。目前iOS的开发都是针对CoreBluetoo...
    huxinwen阅读 10,426评论 0 11
  • 夜莺2517阅读 127,695评论 1 9