蓝牙连接以及发送数据

"没成功说明不够努力"

Posted by 李勇 on 2016-12-13

1.连接蓝牙的常规代码

1.首先引入库:#import <CoreBluetooth/CoreBluetooth.h>
2.代理:<CBCentralManagerDelegate,CBPeripheralDelegatea>
3.准备设备管理

1
2
3
4
5
//创建中心管理者,管理中心设备
self.mgr = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
[self cleanup];
//开始搜索蓝牙设备
[self.mgr scanForPeripheralsWithServices:nil options:nil];

4.代理方法–代码中有注释,特别注意代码中的“kServiceUUID,kCharacteristicUUID,SERVICE_UUID,CHAR_UUID这四个参数”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#pragma mark - 清理蓝牙
//清理缓存
- (void)cleanup
{
if (!self.myPeripheral) {
return;
}
if (self.myPeripheral.state==CBPeripheralStateDisconnected||self.myPeripheral.state == CBPeripheralStateConnecting)
{
self.myPeripheral=nil;
self.characteristic = nil;
return;
}
if (self.service != nil&&self.characteristic!=nil)
{
if (self.characteristic.isNotifying)
{
[self.myPeripheral setNotifyValue:NO forCharacteristic:self.characteristic];
}
}
[self.mgr cancelPeripheralConnection:self.myPeripheral];
[self.mgr stopScan];
self.myPeripheral=nil;
self.service=nil;
self.characteristic=nil;
}
#pragma mark - CBCentralManagerDelegate
//设备蓝牙状态更新
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
switch (central.state) {
case CBCentralManagerStateUnsupported:
NSLog(@"该设备不支持BLE蓝牙");
break;
case CBCentralManagerStateUnauthorized:
NSLog(@"该设备未授权BLE蓝牙");
break;
case CBCentralManagerStatePoweredOff:
NSLog(@"该设备BLE蓝牙已关闭");
break;
case CBCentralManagerStateUnknown:
NSLog(@"该设备BLE蓝牙发生未知错误");
break;
case CBCentralManagerStateResetting:
NSLog(@"该设备BLE蓝牙重置中");
break;
case CBCentralManagerStatePoweredOn:
[self cleanup];
[self.mgr scanForPeripheralsWithServices:nil options:nil];
break;
default:
NSLog(@"Central Manager did change state");
break;
}
}
//发现外部设备时候调用此方法
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
NSString *periName = peripheral.name;
self.myPeripheral = peripheral;
//连接设备,这里是连接了所有设备,应该做的是跟据设备的已知信息去连接设备
[self.mgr connectPeripheral:self.myPeripheral options:nil];
//停止扫描蓝牙
[self.mgr stopScan];
}
//连接蓝牙成功
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
//发现服务
self.myPeripheral .delegate = self;
[self.myPeripheral discoverServices:nil];
}
//连接蓝牙失败
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSString *err = [NSString stringWithFormat:@"连接蓝牙门禁%@失败,原因:%@",peripheral.name,[error localizedDescription]];
NSLog(@"%@",err);
}
//断开蓝牙连接
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
}
#pragma mark - CBPeripheralDelegate
//外设已经查找到服务
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
if (error) return; //发现服务失败
//遍历所有服务
for (CBService *service in self.myPeripheral.services) {
NSLog(@"%@",service.UUID);
if ([service.UUID isEqual:[CBUUID UUIDWithString:kServiceUUID]]){
self.service = service;
break;
}
}
if (self.service) {
[self.myPeripheral discoverCharacteristics:nil forService:self.service];
}
}
#pragma mark 找到特征时调用
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
if (error) return; //发现特征失败
for (CBCharacteristic *characteristic in self.service.characteristics)
{
NSLog(@"%@",characteristic.UUID);
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:kCharacteristicUUID]])
{
self.characteristic = characteristic;
//对此特征设置通知和读取返回数据
[self.myPeripheral setNotifyValue:YES forCharacteristic:self.characteristic];
[self.myPeripheral readValueForCharacteristic:self.characteristic];
[self sendMessageToBle];
break;
}
}
}
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
if (error) {
NSLog(@"%@",error);
return;
} //发送数据失败
}
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
if (error) return; //接收特征数据失败
NSString *value = [[NSString alloc] initWithData:characteristic.value encoding:NSASCIIStringEncoding];
NSLog(@"value==============%@",value);//蓝牙返回的信息,需要对蓝牙设备做特殊处理才能按照一定的格式返回数据
if ([[value lowercaseString] isEqualToString:@"success"]){
}else if ([[value lowercaseString] isEqualToString:@"fail"]){
}
}
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
if (error) return; //开启特征数据返回通知失败
}

2.iOS开发过程中没有直接获取蓝牙Mac地址的方法,需要从读取的数据中提出

参考MacPu的博客-iOS如果获取蓝牙Mac地址 谢谢!
将“kServiceUUID,kCharacteristicUUID“分别设置为“180A,2A23”,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
if (error) return; //接收特征数据失败
NSString *value = [NSString stringWithFormat:@"%@",characteristic.value];
NSMutableString *macString = [[NSMutableString alloc] init];
[macString appendString:[[value substringWithRange:NSMakeRange(16, 2)] uppercaseString]];
[macString appendString:@":"];
[macString appendString:[[value substringWithRange:NSMakeRange(14, 2)] uppercaseString]];
[macString appendString:@":"];
[macString appendString:[[value substringWithRange:NSMakeRange(12, 2)] uppercaseString]];
[macString appendString:@":"];
[macString appendString:[[value substringWithRange:NSMakeRange(5, 2)] uppercaseString]];
[macString appendString:@":"];
[macString appendString:[[value substringWithRange:NSMakeRange(3, 2)] uppercaseString]];
[macString appendString:@":"];
[macString appendString:[[value substringWithRange:NSMakeRange(1, 2)] uppercaseString]];
NSLog(@"macString:%@",macString);
}

3.向蓝牙设备发送数据,并且接收返回数据

在我的实际操作中,发现每次向蓝牙发送数据的时候总是失败,需要借助下面的代码才能发送成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#pragma mark - 向蓝牙发送数据
- (void)sendMessageToBle{
//加密数据
int index = arc4random() % 20;
NSString *doorcode = self.doorArray[index];
NSString *dateStr1 = [NSDate stringFromDate:[NSDate date] withFormat:@"yyyyMMdd"];
NSString *dateStr2 = [NSDate stringFromDate:[NSDate date] withFormat:@"MMddyyyy"];
NSString *dateStr = [NSString stringWithFormat:@"%@%@",dateStr1,dateStr2];
NSString *strA1 = @"OW15LjrCaY2bfcMl";
NSString *strB1 = @"aWuK48JRDPePsYXE";
Byte *A = [self strToByte:dateStr];
Byte *A1 = [self strToByte:strA1];
Byte *B = [self strToByte:doorcode];
Byte *B1 = [self strToByte:strB1];
Byte bleData[16] = {0};
for (int i = 0; i < strA1.length; i ++) {
Byte left = (Byte)(A[i] & A1[i]);
Byte right = (Byte)(B[i] | B1[i]);
bleData[i] = (Byte)(left ^ right);
}
Byte bleMD5[16] ={0};
CC_MD5(bleData, 16, bleMD5);
Byte final[15] = {0};
final[0] = 15;
for (int i = 0; i < 12; i ++) {
final[i + 1] = bleMD5[i];
}
final[13] = 13;
final[14] = 10;
NSData *finalData = [NSData dataWithBytes:final length:15];
[self writeValue:SERVICE_UUID characteristicUUID:CHAR_UUID p:self.myPeripheral data:finalData];
}
-(void) writeValue:(int)serviceUUID characteristicUUID:(int)characteristicUUID p:(CBPeripheral *)p data:(NSData *)data {
//这里对服务值以及特征值做了一下处理,按照硬件的识别方式转换一下
UInt16 s = [self swap:serviceUUID];
UInt16 c = [self swap:characteristicUUID];
NSData *sd = [[NSData alloc] initWithBytes:(char *)&s length:2];
NSData *cd = [[NSData alloc] initWithBytes:(char *)&c length:2];
CBUUID *su = [CBUUID UUIDWithData:sd];
CBUUID *cu = [CBUUID UUIDWithData:cd];
CBService *service = [self findServiceFromUUIDEx:su p:p];
if (!service) {
printf("Could not find service with UUID %s on peripheral with UUID %s\r\n",[self CBUUIDToString:su],[self UUIDToString:(__bridge CFUUIDRef )p.identifier]);
return;
}
CBCharacteristic *characteristic = [self findCharacteristicFromUUIDEx:cu service:service];
if (!characteristic) {
printf("Could not find characteristic with UUID %s on service with UUID %s on peripheral with UUID %s\r\n",[self CBUUIDToString:cu],[self CBUUIDToString:su],[self UUIDToString:(__bridge CFUUIDRef )p.identifier]);
return;
}
[p setNotifyValue:YES forCharacteristic:characteristic];
//写入数据时选择有返回数据/无返回数据
if(characteristic.properties & CBCharacteristicPropertyWriteWithoutResponse)
{
[p writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithoutResponse];
}else
{
[p writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
}
}
-(UInt16) swap:(UInt16)s {
UInt16 temp = s << 8;
temp |= (s >> 8);
return temp;
}
-(CBService *) findServiceFromUUIDEx:(CBUUID *)UUID p:(CBPeripheral *)p {
for(int i = 0; i < p.services.count; i++) {
CBService *s = [p.services objectAtIndex:i];
if ([self compareCBUUID:s.UUID UUID2:UUID]) return s;
}
return nil; //Service not found on this peripheral
}
-(int) compareCBUUID:(CBUUID *) UUID1 UUID2:(CBUUID *)UUID2 {
char b1[16];
char b2[16];
[UUID1.data getBytes:b1];
[UUID2.data getBytes:b2];
if (memcmp(b1, b2, UUID1.data.length) == 0)return 1;
else return 0;
}
-(const char *) CBUUIDToString:(CBUUID *) UUID {
return [[UUID.data description] cStringUsingEncoding:NSStringEncodingConversionAllowLossy];
}
-(const char *) UUIDToString:(CFUUIDRef)UUID {
if (!UUID) return "NULL";
CFStringRef s = CFUUIDCreateString(NULL, UUID);
return CFStringGetCStringPtr(s, 0);
}
-(CBCharacteristic *) findCharacteristicFromUUIDEx:(CBUUID *)UUID service:(CBService*)service {
for(int i=0; i < service.characteristics.count; i++) {
CBCharacteristic *c = [service.characteristics objectAtIndex:i];
if ([self compareCBUUID:c.UUID UUID2:UUID]) return c;
}
return nil; //Characteristic not found on this service
}
//字符串转byte
- (Byte *)strToByte:(NSString *)strBefor{
Byte *bt = (Byte *)malloc(16);
for (int i =0; i < strBefor.length; i++) {
int strInt = [strBefor characterAtIndex:i];
Byte b = (Byte) ((0xff & strInt) );//( Byte) 0xff&iByte;
bt[i] = b;
}
return bt;
}

直戳demo源码