iOS蓝牙开发

iOS蓝牙开发有三个框架

1.GameKit.framework:iOS7之前的蓝牙通讯框架,从iOS7开始过期。
2.MultipeerConnectivity.framework:iOS7开始引入的新的蓝牙通讯开发框架,用于取代GameKit。
3.CoreBluetooth.framework:功能强大的蓝牙开发框架,要求设备必须支持蓝牙4.0。目前蓝牙开发多半基于此框架,此笔记也是写基于此框架。

蓝牙开发有两种模式:
1.手机作为中心设备,获取外设的数据
2.手机作为外设,对外提供数据(这里不做讨论)

本文记录的是利用tableView展示所有扫描到的外设,点击某行时连接对应的外设进行数据交互
实现流程如下:

1.导入蓝牙库,宏定义服务UUID、读数据UUID、写数据UUID
#import <CoreBluetooth/CoreBluetooth.h>

#define     kServiceUUID        @"1234"//服务UUID
#define     kReadUUID           @"1236"//读数据UUID
#define     kWriteUUID          @"1235"//写数据UUID

@property (nonatomic, strong) CBPeripheral   *peripheral;               //外设
@property (nonatomic, strong) CBCentralManager *myCentralManager;       //管理中心
@property (nonatomic, strong) CBCharacteristic *readCharacteristic;     //读取数据特性
@property (nonatomic, strong) CBCharacteristic *writeCharacteristic;    //写数据特性

2.创建蓝牙管理中心
 _myCentralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];//如果设置为nil,默认在主线程中跑。设置了代理为self,记得遵守协议

3.监测蓝牙状态,如果蓝牙开启则扫描外设
- (void)centralManagerDidUpdateState:(CBCentralManager *)central{
    switch (central.state){
        case CBCentralManagerStateUnknown:
            break;
        case CBCentralManagerStateUnsupported:
            JCLog(@"模拟器不支持蓝牙调试");
            break;
        case CBCentralManagerStateUnauthorized:
            break;
        case CBCentralManagerStatePoweredOff:{
            JCLog(@"蓝牙处于关闭状态");
        }
            break;
        case CBCentralManagerStateResetting:
            break;
        case CBCentralManagerStatePoweredOn:{
            JCLog(@"蓝牙已开启");
            //开始扫描外设
            [_myCentralManager scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey:[NSNumber numberWithBool:NO]}];
        }
            break;
    }
}

4.实现代理方法。当扫描到外部设备时会进入         发现外设        的代理方法
- (void)centralManager:(CBCentralManager *)central //管理中心
 didDiscoverPeripheral:(CBPeripheral *)peripheral //发现的外设
     advertisementData:(NSDictionary *)advertisementData //外设中的广播数据
                  RSSI:(NSNumber *)RSSI //外设信号强度
{
    
//    JCLog(@"蓝牙广播数据------>>%@",advertisementData);
//每次扫描出一个外设都会进入此代理方法,在此方法中可以将外设添加到外设数组中,在添加进数组之前,判断一下数组中是否已经添加过这个外设,如果添加过,则不再添加。
if(![_allperipherals containsObject:peripheral]){
        [_allperipherals addObject:peripheral];
//添加了新的外设进去,刷新tableview
       [_tableView reloadData];
    }

5.连接外设
//在选中某行cell的代理方法中,调用连接蓝牙外设的方法
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//需要连接的外设必须强引用,否则出了此方法作用域后会被释放掉,导致蓝牙断开连接,控制台输出错误信息
    _peripheral = _allperipherals[indexPath.row];
    JCLog(@"连接蓝牙:%@",_peripheral.name);
    [_myCentralManager connectPeripheral:_peripheral options:nil];//连接蓝牙
}

6.蓝牙连接成功,会调用代理方法
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
//    JCLog(@"成功连接%@",peripheral.name);
    _peripheral = peripheral;
    peripheral.delegate = self;
    //开始寻找外设服务
    [peripheral discoverServices:nil];
/*
关于外设服务是什么的理解:
每个蓝牙4.0的设备都是通过服务和特征来展示自己的,一个设备必然包含一个或多个服务,每个服务下面又包含若干个特征。
特征是与外界交互的最小单位。比如说,一台蓝牙4.0设备,用特征A来描述自己的出厂信息,用特征B来与收发数据等。
此处应用时可以借助一个叫:LightBlue的App来理解蓝牙外设的服务及特征值。
最近做的一个蓝牙项目中,硬件工程师选择的蓝牙模块有提供开发文档,文档中有提供 服务值 及 读取数据 和 写数据 的特征值。按照文档中提供的对应的值填写即可。借助LightBlue也可以看到服务值和读写数据特征值。具体值,参考步骤1中的三个宏定义。
理解不是很到位,请见谅。
*/
}

连接外部蓝牙设备失败调用此方法,可在此再次连接外设
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
//如何实现自动断线重连,就是在断开的委托方法中,执行连接蓝牙的方法  可以在此处重新调用连接蓝牙方法
//    JCLog(@"连接%@失败--error:%@",peripheral.name,error);
    [_myCentralManager connectPeripheral:_peripheral options:nil];//连接蓝牙
}

7.发现蓝牙外设服务,调用此方法
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
    
    if(error){
        JCLog(@"外围设备寻找服务过程中发生错误,错误信息:%@",error.localizedDescription);
    }
    //遍历查找到的服务
    CBUUID *serviceUUID=[CBUUID UUIDWithString:kServiceUUID];
    for (CBService *service in peripheral.services) {
        if([service.UUID isEqual:serviceUUID]){
            //外围设备查找指定服务中的特征
            [peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:kReadUUID],[CBUUID UUIDWithString:kWriteUUID]] forService:service];
        }
    }
}

8.寻找蓝牙服务中的特性
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
    if (error) {//报错直接返回退出
        JCLog(@"didDiscoverCharacteristicsForService error : %@", [error localizedDescription]);
        return;
    }
    
    for (CBCharacteristic *characteristic in service.characteristics)//遍历服务中的所有特性
    {
        if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:kReadUUID]]){//找到收数据特性
            [peripheral setNotifyValue:YES forCharacteristic:characteristic];//订阅其特性(这个特性只有订阅方式)
            _readCharacteristic = characteristic;
        }
        if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:kWriteUUID]]) {//找到发数据特性
            _writeCharacteristic = characteristic;
        }
    }
}

9.收到外设更新发送过来的数据
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    if (error) {
        JCLog(@"更新特征值时发生错误,错误信息:%@",error.localizedDescription);
        return;
    }
    NSString *value=[[NSString alloc]initWithData:characteristic.value encoding:NSUTF8StringEncoding];
    JCLog(@"读取到特征值:%@",value);//即收到的数据
}

10.发送数据到外设
-(void)sendString:(NSString *)string{
   NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
   [_eripheral writeValue:data
        forCharacteristic:_writeCharacteristic
                     type:CBCharacteristicWriteWithoutResponse];
}

/*======至此,蓝牙收发数据的流程基本结束======*/

/*
注意点:
1.发送到外设的数据最大为20字节
2.接收的数据也为20字节
3.MAC端蓝牙调试助手推荐使用CoolTerm,相当于windows中的串口调试助手
4.iPhone手机端调试,推荐LightBlue
*/


/*
关于服务UUID,特征值UUID的解释
1.此文介绍的蓝牙开发是固定的服务UUID、固定的特征值UUID。即已获知项目中使用的外设蓝牙模块的服务UUID、特征值UUID,这两个数据可以在硬件工程师那里拿到,蓝牙模块文档中一般会提及。如果没有,则使用上文中提到的调试工具LightBlue可以获取得到。
2.最近开发项目中的服务UUID、特征值UUID都是使用LightBlue获知。
*/

如有错误之处,望看到此文的大神批评指正,谢谢!

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

推荐阅读更多精彩内容