iOS蓝牙编程

来源:互联网 发布:淘宝已下架宝贝在哪里 编辑:程序博客网 时间:2024/05/17 14:29

蓝牙编程

最近公司新来了一部蓝牙小票机器,需要对其进行编程,所以阅读起了iOS蓝牙编程的官方文档,昨日测试成功,想写下点心得,方便以后查看。

言归正传。iOS的蓝牙框架是支持蓝牙4.0协议的。

理解iOS CoreBluetooth两个很重要的概念,Central 和 Periperal Devices

这两个概念可以用传统的模式client-server来理解,central意思是中心,其作用类似server,periperal就是外设,一般携带有数据,我们需要去其中获取数据,下图是苹果官网的例子,peripheral是心跳仪,按期作用,我们去这个外设中取心跳数据,则心跳仪的作用就类似server了,我们的手机去心跳仪中获取数据,类似client。



Peripheral如何让central知道它的存在呢?
peripheral.比如上图的心跳仪,通过不断广播自己的存在,并且在广播过程中附带广告包(advertising packet),不知道这样翻译是否正确,不对请指正一下。如同好像有个设备在喊,Here~我是心跳仪器,我是心跳仪器,这是我提供的服务(广告包)。Central发现有个设备在呐喊,就说:“那我看看需不需要你提供服务,拿来我看看”。这样你就发现了这个设备,并且获取到它提供的服务。



Peripheral介绍
Peripheral,每个Peripheral都有一个唯一标识符(UUID),来标明Peripheral的唯一性。
Peripheral携带着两个非常重要的数据.这个对象的呈现由Service和
1.Service 服务,Service是一组数据的集合,并且代表一种服务或者功能。Peripheral含多一个或多个Services.每个Service都具有一个UUID
2.Characteristic 特征,代表着由Service提供详细信息或者功能。Service含有一个或多个Characteristics.每个Characteristic都具有一个UUID

这里可能就有点晕。通俗的来解释,就用心跳仪来举个例子。
1.当你发现了心跳仪(peripheral),里面携带着广告数据,广告数据一般是简单的数据介绍。比如一些服务的服务(UUID)。
2.当你找到了这个peripheral,接着你叫它汇报它提供的服务,这个peripheral会汇报所有服务给你。比如心跳仪器提供两种service,设备信息service与数据获取service.这样你就知道有哪几种服务了。
3.然后你可以对你感兴趣的服务进行操作。比如我们对数据获取的服务感兴趣,我就对这个获取的服务说,给我你的所有的characteriscs,所有的特征。假设这时候它返回两个特征,一个是心跳数据的characteristic,另外一个是心跳压力数据(瞎编的)。你就可以对其特征进行读写操作,这里获取操作,就是读操作。获取到对应数据源头

看一下来自官网的结构图


介绍完这些概念,我们来看看实际代码应该如何填写.这里对于我的蓝牙小票机来编写的,因为我要对蓝牙小票机器进行写操作,手机是搜索peripharal的,所以手机为client,小票机为peripharal,即server
1.首先导入<CoreBluetooth/CoreBluetooth.h>这个框架
2.该框架有主要有几个类值得我们注意,CBCentralManager,也就是我们之前提到的Central,可以用来发现外设的。

#import <CoreBluetooth/CoreBluetooth.h>@interface ViewController () <CBCentralManagerDelegate>@property (nonatomic, retain) CBCentralManager *centralManager;@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    // Do any additional setup after loading the view, typically from a nib.    self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];}


上面代码这里我们创建了一个CBCentralManager,用来发现外设,当创建成功,CBCentralManager会回调代理说创建成功了,如下面代码
/* Invoked whenever the central manager's state is updated. */- (void)centralManagerDidUpdateState:(CBCentralManager *)central{    NSString * state = nil;        switch ([central state])    {        case CBCentralManagerStateUnsupported:            state = @"The platform/hardware doesn't support Bluetooth Low Energy.";            break;        case CBCentralManagerStateUnauthorized:            state = @"The app is not authorized to use Bluetooth Low Energy.";            break;        case CBCentralManagerStatePoweredOff:            state = @"Bluetooth is currently powered off.";            break;        case CBCentralManagerStatePoweredOn:            state = @"work";            break;        case CBCentralManagerStateUnknown:        default:            ;    }        NSLog(@"Central manager state: %@", state);}
上面的代码如果这个时候如果是CBCentralManagerStatePoweredOn,代表蓝牙可用。一定要在该方法回调后去开启扫描外设,否则无反应.

3.现在可以连接扫描外设了
- (IBAction)scan:(id)sender {    [self.centralManager scanForPeripheralsWithServices:nil options:nil];}
上面代码我创建了一个按钮来扫描,就不上对应的xib图片了.
这个方法如果传入的事nil,代表扫描所有外设。

- (IBAction)scan:(id)sender {    [self.centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:@"FFE0"]] options:nil];}
如果你只想搜索有提供对应的服务号的外设(去peripharal 的advertising packet里匹配服务号,传入一个数组进入,对象为CBUUID,也就是Service的唯一标识符。一般我们搜索过一个nil的就会知道我们要的服务好是什么样子的了,之后编程就可以直接使用这个已知的服务好。除非你的蓝牙设备的厂家更改服务号,不过几乎不可能。

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{    static int i = 0;    NSString *str = [NSString stringWithFormat:@"Did discover peripheral. peripheral: %@ rssi: %@, UUID: %@ advertisementData: %@ ", peripheral, RSSI, peripheral.UUID, advertisementData];    NSLog(@"%@",str);    [self.discoverdPeriparals addObject:peripheral];}
当你发现了一个设备,该方法会回调。peripheral代表你发现的设备,advertisementData时广告数据,rssi代表着信号强度.


从广播数据中可以看到一个服务UUIDs,因为广播数据有数量大小限制,数据比较少。不过目前我们只是发现了这个设备,假设该设备已经是我们感兴趣的设备,你可以通过[self.centralManager stopScan]来停止扫描,也可以继续扫描。

4.连接发现的外设
- (IBAction)connect:(id)sender {    [self.centralManager connectPeripheral:[self.discoverdPeriparals firstObject]  options:nil];}


假设第一个是我们需要的外设,连接它。
/* Invoked whenever a connection is succesfully created with the peripheral. Discover available services on the peripheral */- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{    NSLog(@"Did connect to peripheral: %@", peripheral);    peripheral.delegate = self;    [central stopScan];    [peripheral discoverServices:nil];}
当连接成功后调用该方法。这个时候我们设置该peripheral的代理我们自己,让peripheral给我们返回所有服务。
<span style="font-size:18px;">[peripheral discoverServices:@[[CBUUID UUIDWithString:@"FFE0"]]];</span>
这个方法也是传入nil返回所有服务,如果是传入特定的服务id,只返回该服务
这里我们传入nil来返回所有服务

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{    if (error)    {        NSLog(@"Discovered services for %@ with error: %@", peripheral.name, [error localizedDescription]);        return;    }        for (CBService *service in peripheral.services)    {        NSLog(@"Service found with UUID: %@", service.UUID);        if ([service.UUID isEqual:[CBUUID UUIDWithString:@"FFE0"]])        {            [peripheral discoverCharacteristics:nil forService:service];        }       }}


这里看到返回了两个服务,因为需要FFE0,所以让该服务返回对应的characteristics.
[peripheral discoverCharacteristics:nil forService:service];
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{    if (error)    {        NSLog(@"Discovered characteristics for %@ with error: %@", service.UUID, [error localizedDescription]);        return;    }    for (CBCharacteristic * characteristic in service.characteristics)    {        DLog(@"%@",<span style="font-family: Arial, Helvetica, sans-serif;">characteristic</span>);        if( [characteristic.UUID isEqual:[CBUUID UUIDWithString:@"FFE1"]])        {            self.p = peripheral;            self.c = characteristic;                        //read            //[testPeripheral readValueForCharacteristic:characteristic];            NSLog(@"Found a Device Manufacturer Name Characteristic - Read manufacturer name");        }    }}
上面的方法是找到FEE0服务的所有特征,这里的只有一个,也就蓝牙小票机FFE0写服务的写特征.
获取到该特征。进行写服务,具体的log就不写了

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{    NSString *RStr = @"2764";    NSMutableString *str = [NSMutableString new];    [str appendFormat:@"%c", 28];    [str appendFormat:@"%c", 33];    [str appendFormat:@"%c", 8];        [self.p writeValue:[str dataUsingEncoding:CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000)] forCharacteristic:self.c type:CBCharacteristicWriteWithResponse];    RStr = @"吴水凤 你好呀!!!\n\n\n\n\n\n\n\n";    [self.p writeValue:[RStr dataUsingEncoding:CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000)] forCharacteristic:self.c type:CBCharacteristicWriteWithResponse];}
这里我对蓝牙小票机提供的写特征进行写服务。成功.

补充:
如果该特征是可以读特征,你可以对该特征进行订阅。

[peripheral setNotifyValue:YES forCharacteristic:interestingCharacteristic];

该方法回调peripheral:didUpdateValueForCharacteristic:error:方法

当你订阅成功后,如果数据有更新,则回调该方法。
你就可以去读取你想要的数据了。

如果想要了解更多,建议查看iOS官方文档提供的CoreBluetooth programming guid.小弟就写到这了。









0 0
原创粉丝点击