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 

#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获知。
*/

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

你可能感兴趣的:(iOS蓝牙开发)