ios蓝牙使用总结

来源:互联网 发布:域名解析端口号怎么办 编辑:程序博客网 时间:2024/05/05 08:09

       关于ios蓝牙的相关编程,网上又很多教程,在这里,我经过了一段时间的学习,总结出了一些自己理解的东西,纪录在这里,方便自己和其他人看。

           现在用到的蓝牙技术又3.0和4.0.两者之间在ios编程中的区别仅仅是4.0版本的蓝牙收发数据报时,传递数据的长度只有20个字节。因此在数据处理的时候,要根据具体情况来调整。首先,我们先以3.0为例。

           (本文中仅是一些我用到的方法,可以解决一般的数据收发,如有不足之处,欢迎提出,本文中就不再详细阐述蓝牙中心设备和外围设备的概念了)

           首先介绍蓝牙框架中的几个常用类:

1.CBCentralManager   中心设备管理类

这个是管理本机蓝牙的搜索外围设备,链接,首发数据的类,一个对象代表一个中心设备

2.CBPeripheral      外围设备类

           一个该类的对象代表一个外围设备,储存了该外围设备的所有信息

3.CBService         服务类

           一个该类对象代表一个服务,一个外围设备可以包含多个服务

4.CBCharacteristic   特征类

           一个该类对象代表一个特征,一般来说特征只有一个读和一个写,特征是用来收发数据的工具。一个服务包含多个特征。

 

下面我们开始学习如何使用这些类,控制蓝牙设备。

(在教程过程中我添加了一些自己想的小技巧)

1.    首先,我们在使用蓝牙时,最好只是用一个对象来控制整个App的蓝牙,因此,最好创建一个单独的类,并且设置为一个单例。如果不了解单例,请百度单例模式。

<span style="font-size:18px;">@interface BlueToothController : NSObject//单例+(BlueToothController*)Instance;@end</span>

<span style="font-size:18px;">+(BlueToothController*)Instance{    if (instance == nil) {        instance = [[BlueToothController alloc] init];    }    return instance;}</span>

<span style="font-size:18px;">static BlueToothController* instance;</span>

2.    我们还需要让自己写的蓝牙控制类,遵守CBCentralManagerDelegate和CBPeripheralDelegate协议,用来分别控制中心设备和外围设备。

<span style="font-size:18px;">@interface BlueToothController : NSObject <CBCentralManagerDelegate,CBPeripheralDelegate></span>


3.    然后我们需要建立一个中心设备的实例,用来控制本机(中心设备)

//中心设备管理对象@property (nonatomic, strong) CBCentralManager *centralMgr;


4.    第三步,我们就开始进行蓝牙设备的控制了,首先是检查中心设备也就是本机的蓝牙状态,使用用CBCentralManagerDelegate协议中的centralManagerDidUpdateState方法。在以下例子中,检测蓝牙状态正常的时候,就直接使用scanForPeripheralsWithServices函数进行搜索。
了。

<span style="font-size:18px;">//查询到状态时调用的函数-(void)centralManagerDidUpdateState:(CBCentralManager *)central{    NSDictionary* dic = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:false],CBCentralManagerScanOptionAllowDuplicatesKey, nil];    switch (central.state)    {        case CBCentralManagerStatePoweredOn:            [self.centralMgr scanForPeripheralsWithServices:nil options:dic];            NSLog(@"开始搜索蓝牙~~~");                        break;                    default:            NSLog(@"设备存在问题,无法搜索蓝牙~");            break;    }}</span>
5.  在搜索函数启动后,设备开始启动搜索外围设备,如果搜索到了一个外围设备,就会调用一次协议中的didDiscoverPeripheral方法获取该设备,此项步骤中,我们需要保存外围设备的信息,因此,要创建一个成员变量,用来保存所有的外围设备。

<span style="font-size:18px;">//蓝牙设备列表@property (nonatomic, strong) NSMutableArray *arrayBLE;</span>

然后写代理方法,将搜索到的外围设备储存到数组中,代码中的BLUENAME 为之前定下的需要连接的设备名字。在保存蓝牙设备信息的时候如果设备名符合,那么调用一个自定义方法ConnectBlueTooth方法来连接蓝牙。自定义方法在下面写出

//处理搜索到的设备-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{            BELInfo *discoveredBLEInfo = [[BELInfo alloc] init];    discoveredBLEInfo.discoveredPeripheral = peripheral;    discoveredBLEInfo.rssi = RSSI;        //如果已经连接过了设备,就不再保存了    if (self.arrayBLE.count > 0) {        return;    }        // 储存连接搜索到的蓝牙设备    if (![self saveBLE:discoveredBLEInfo]) {        NSLog(@"蓝牙设备保存连接失败!~~");    };}//保存蓝牙设备-(BOOL)saveBLE:(BELInfo*)info{    NSLog(@"发现设备%@:%@",info.discoveredPeripheral.name,info.discoveredPeripheral.identifier.UUIDString);        //如果名字为我们需要连接的蓝牙的名字,则连接并且保存返回yes    if ([info.discoveredPeripheral.name isEqualToString:BLUENAME]) {        //连接蓝牙        if (![self ConnectBlueTooth:info.discoveredPeripheral]) {            NSLog(@"蓝牙连接失败!");            return NO;        }        else        {            [self.arrayBLE addObject:info];            NSLog(@"蓝牙连接成功!连接上设备名为:%@,UUID为%@的设备",info.discoveredPeripheral.name,info.discoveredPeripheral.identifier.UUIDString);        }    }            return YES;    }
//连接蓝牙函数-(BOOL)ConnectBlueTooth:(CBPeripheral*)pheral{    //连接蓝牙设备    [self.centralMgr connectPeripheral:pheral options:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:CBConnectPeripheralOptionNotifyOnDisconnectionKey]];        //记录连接的蓝牙,并且设置该外围设备协议    self.ConnectPeripheral = pheral;    [pheral setDelegate:self];    return YES;}

在上述的自定义的连接蓝牙函数中ConnectPerpheral函数是框架库函数给出的,但在连接之后,我们需要保存我们连接上的外围设备实例,因此,我们需要一个成员变量指针。

@property (nonatomic,strong) CBPeripheral* ConnectPeripheral;

以上函数中表示对这个指针的初始化的部分

//记录连接的蓝牙,并且设置该外围设备协议    self.ConnectPeripheral = pheral;    [pheral setDelegate:self];    return YES;
6.   在连接了外围设备之后,会自动回调协议中的didConnectPeripheral函数,可以在这个函数中调用搜索该设备的相关服务的操作

//连接蓝牙的时候触发的协议函数-(void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{    //获取T100的UUID    CBUUID* MyServerUUID = [CBUUID UUIDWithString:BLUE_SERVER];    //打包成数组    NSArray* uuida = [NSArray arrayWithObject:MyServerUUID];    //搜索该UUID服务    [peripheral discoverServices:uuida];    NSLog(@"开始搜索蓝牙的服务!!");}

BLUE_SERVER是需要搜索到的设备的服务

7.   如果没有连接到设备,或者设备断开连接,则会调用协议中的didDisconnectPeripheral函数,我在示例中,让在断开或者没有搜索到设备之后的操作是,继续搜索设备。

//没连上的时候的响应函数-(void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{    NSLog(@"蓝牙断开了链接!!开始重新搜索!!");    //清除之前保存的所有信息    [self.arrayBLE removeAllObjects];    SendCharacteristic = nil;    ReadCharacteristic = nil;    MyServer = nil;     NSDictionary* dic = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:false],CBCentralManagerScanOptionAllowDuplicatesKey, nil];    //重新搜索    [self.centralMgr scanForPeripheralsWithServices:nil options:dic];}

8.   在搜索到服务之后,会回调协议中的didDiscoverServices函数,然后我们将访问每一个服务,并且搜索这个服务的所有特征。
//搜索服务的时候触发的协议函数-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{    if (!error) {        for (CBService* server in peripheral.services) {            //搜索该服务的特征值            [peripheral discoverCharacteristics:nil forService:server];            NSLog(@"搜索到了一个服务:%@",server.UUID.UUIDString);        }    }    else    {        NSLog(@"搜索服务失败,失败提示:%@",error);    }}

9.    在搜索到特征后,会回调协议中的didDiscoverCharacteristicsForService函数,我们将获取约定好的读特征和写特征存储在,再次创建的成员变量中。读特征直接绑定,写特征储存在发数据时使用。

//储存特征值    CBCharacteristic* SendCharacteristic;//读特征    CBCharacteristic* ReadCharacteristic;//写特征

//扫描完每一个特征值之后调用该函数-(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{    if (!error) {        //扫描每一个特征        for (CBCharacteristic* character in service.characteristics) {                        NSLog(@"搜索到一个特征:%@",character.UUID.UUIDString);                        //如果是写的特征,写入发送特征对象中            if ([character.UUID.UUIDString isEqualToString:BLUE_CHARACTERISTIC_WRITE]) {                SendCharacteristic = character;            }            //如果是读特征,写入读特征对象中            if ([character.UUID.UUIDString isEqualToString:BLUE_CHARACTERISTIC_READ]) {                ReadCharacteristic = character;                //绑定监听                [self.ConnectPeripheral setNotifyValue:YES forCharacteristic:character];            }        }    }    else    {        NSLog(@"搜索特征失败,失败提示:%@",error);    }    }


10.  到了这一步,蓝牙连接和准备工作已经全部结束,剩下的就是收发数据的阶段了。收发数据的方法有很多,本例中使用的是发一条数据等到这条数据处理完之后再发送另一条数据的方式。过程中会用到线程,信号灯相关知识。

首先是发数据:

11.  发数据时只需要调用writeValue函数,但是发送数据需要使用本类单例的对象自己调用,因此,我们自定义一个函数,这个函数会创建一个线程,在线程中发送数据报,发送结束后,将会用信号灯等待,如果再50秒内没有收到信号就自动继续,如果收到信号,就可以发送另一条数据。

<span style="font-size:18px;">//通过特征值发送数据-(void)SendData:(NSData*)data{    NSLog(@"开启了一个线程发送数据:%@",data);    NSThread* sendThread = [[NSThread alloc] initWithTarget:self selector:@selector(SenddataByOtherWay:) object:data];    [sendThread start];    }//发送数据线程//////////////////////////////////////////////////////-(void)SenddataByOtherWay:(NSData*)data{        NSLog(@"发出数据:%@",data);    //需要响应的发送数据    if (SendCharacteristic) {        [self.ConnectPeripheral writeValue:data forCharacteristic:SendCharacteristic type:CBCharacteristicWriteWithResponse];    }        //发送完之后,等待处理完成,如果五十秒后,无反馈,继续    [condition waitUntilDate:[[NSDate alloc] initWithTimeIntervalSinceReferenceDate:50]];    }//////////////////////////////////////////////////////</span>

在数据发送之后会回调didWriteValueForCharacteristic函数,我没有做处理,只是把数据显示了一下,在这里就不做说明了。


12.  其次是读数据,再设备收到外围设备反馈回来的数据时,会自动回调didUpdateValueForCharacteristic函数,这个是在第九步中监听了读特征才会调用的函数。

因为蓝牙收到的数据很多,考虑到可复用性,我们创建一个协议,用来让使用蓝牙的对象,自己定义数据的处理方法。

@protocol BlueToothControllerDelegate <NSObject>-(void)BlueToothEventWithReadData:(CBPeripheral*)peripheral Data:(NSData*)data;@end

@property (nonatomic , strong) id<BlueToothControllerDelegate> delegate;

13. 在didUpdateValueForCharacteristic函数中,我们直接从特征值中获取到数据,然后让代理方法去处理,在代理方法处理结束后,发送一个信号灯,让发数据的线程继续工作。

//监听读特征的协议函数-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{    NSData* data = characteristic.value;    NSLog(@"收到了一条数据:%@",data);    //调用协议的函数    if (self.delegate) {        [self.delegate BlueToothEventWithReadData:peripheral Data:data];    }    //处理完成数据后,开启信号灯    [condition signal];}

以上就是我总结的蓝牙的常用方法。不足之处,欢迎提出。大笑








0 0
原创粉丝点击