Ekulelu's Blog

iOS蓝牙连接

iOS蓝牙连接其实不难,可以参照官方的例子教程或者使用github的开源库babyBluetooth。

iOS蓝牙连接的流程如下:

通过服务的UUID扫描外部设备 -> 连接外部设备 -> 连接成功后扫描设备的服务 -> 发现服务后,扫描该服务的Characteristics -> 扫描到Characteristics后,进行读、写、订阅 -> 读和订阅后,有数据回来,会回调一个代理方法didUpdateValueForCharacteristic获得数据。

下面介绍一下官方教程的代码,因为iOS是作为主端,所以只介绍主端的代码,从端的代码示例代码也有,可以参考,并不难。

官方教程的代码下载链接

主端官方的例子主要是参照BTLECentralViewController.m这个文件。iOS原生的蓝牙基本是使用了代理方法的结构来处理蓝牙功能。基本上流程的一步对应一个代理方法。

创建CBCentralManager对象,并设置好它的代理。

1
_centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];

使用CBCentralManager扫描外部设备,这个需要传递外部设备的服务的UUID,如果不传递的话,那么就会扫描所有设备。代码如下,

1
2
3
4
5
6
7
- (void)scan
{
[self.centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]]
options:@{ CBCentralManagerScanOptionAllowDuplicatesKey : @YES }];
NSLog(@"Scanning started");
}

发现设备后会回调一个代理方法,

1
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI

在这个方法里面连接设备

1
[self.centralManager connectPeripheral:peripheral options:nil];

设备连接成功后会回调一个方法,先停止扫描,然后在这个方法里面扫描设备的服务。如果不传服务的UUID,那么会扫描所有服务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
NSLog(@"Peripheral Connected");
// Stop scanning
[self.centralManager stopScan];
NSLog(@"Scanning stopped");
// Clear the data that we may already have
[self.data setLength:0];
// Make sure we get the discovery callbacks
peripheral.delegate = self;
// Search only for services that match our UUID
[peripheral discoverServices:@[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]]];
}

扫描到服务后继续调用另外回调方法,在这个方法扫描Characteristics

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
if (error) {
NSLog(@"Error discovering services: %@", [error localizedDescription]);
[self cleanup];
return;
}
// Discover the characteristic we want...
// Loop through the newly filled peripheral.services array, just in case there's more than one.
for (CBService *service in peripheral.services) {
[peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]] forService:service];
}
}

发现Characteristics后继续回调另外一个方法。这里面可以判断一下Characteristics的UUID,对需要订阅的Characteristics进行订阅,或者读写数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
// Deal with errors (if any)
if (error) {
NSLog(@"Error discovering characteristics: %@", [error localizedDescription]);
[self cleanup];
return;
}
// Again, we loop through the array, just in case.
for (CBCharacteristic *characteristic in service.characteristics) {
// And check if it's the right one
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) {
//订阅characteristic If it is, subscribe to it
[peripheral setNotifyValue:YES forCharacteristic:characteristic];
}
}
//读取characteristic
//[peripheral readValueForCharacteristic:characteristic];
// Once this is complete, we just need to wait for the data to come in.
}

如果读取或者订阅的Characteristic有更新,那么就会调用下面的方法。

1
2
3
4
5
6
7
8
9
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
if (error) {
NSLog(@"Error discovering characteristics: %@", [error localizedDescription]);
return;
}
//获得数据
NSData *data = characteristic.value;
}

如果要断开连接,调用下面方法

1
[self.centralManager cancelPeripheralConnection:peripheral];