经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 移动开发 » iOS » 查看文章
iOS蓝牙开发(4.0)详解
来源:cnblogs  作者:风中凌乱一整天  时间:2019/2/28 9:38:26  对本文有异议

最近由于项目需要, 一直在研究蓝牙4.0,在这儿分享给大家, 望共同进步.

一、关于蓝牙开发的一些重要的理论概念:

1.当前ios中开发蓝牙所运用的系统库是<CoreBluetooth/CoreBluetooth.h>。

2.蓝牙外设必须为4.0及以上(2.0需要MFI认证),否则无法开发,蓝牙4.0设备因为低耗电,所以也叫做BLE。

3.CoreBluetooth框架的核心其实是两个东西,peripheral和central, 可以理解成外设和中心,就是你的苹果手机就是中心,外部蓝牙称为外设。

4.服务和特征(service and characteristic):简而言之,外部蓝牙中它有若干个服务service(服务你可以理解为蓝牙所拥有的能力),而每个服务service下拥有若干个特征characteristic(特征你可以理解为解释这个服务的属性)。

5.Descriptor(描述)用来描述characteristic变量的属性。例如,一个descriptor可以规定一个可读的描述,或者一个characteristic变量可接受的范围,或者一个characteristic变量特定的单位。

6.我们使用的蓝牙模块是在淘宝买的, 大概十多元一个, ios大概每次可以接受90个字节, 安卓大概每次可以接收20个字节, 具体数字可能会浮动, 应该是与蓝牙模块有关。

二、蓝牙连接的主要步骤

  1. 1、创建一个CBCentralManager实例来进行蓝牙管理;
  2.  
  3. 2、搜索扫描外围设备;
  4.  
  5. 3、连接外围设备;
  6.  
  7. 4、获得外围设备的服务;
  8.  
  9. 5、获得服务的特征;
  10.  
  11. 6、从外围设备读取数据;
  12.  
  13. 7、给外围设备发送(写入)数据。

 

三、代码

// 加入权限访问, 否则上传AppStore会因为权限不足失败

1. 初始化

  1. #import <CoreBluetooth/CoreBluetooth.h>
  1. self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];

2. 搜索扫描外围设备

  1. /**
  2. * -- 初始化成功自动调用
  3. * -- 必须实现的代理,用来返回创建的centralManager的状态。
  4. * -- 注意:必须确认当前是CBCentralManagerStatePoweredOn状态才可以调用扫描外设的方法:
  5. scanForPeripheralsWithServices
  6. */
  7. - (void)centralManagerDidUpdateState:(CBCentralManager *)central{
  8. switch (central.state) {
  9. case CBCentralManagerStateUnknown:
  10. NSLog(@">>>CBCentralManagerStateUnknown");
  11. break;
  12. case CBCentralManagerStateResetting:
  13. NSLog(@">>>CBCentralManagerStateResetting");
  14. break;
  15. case CBCentralManagerStateUnsupported:
  16. NSLog(@">>>CBCentralManagerStateUnsupported");
  17. break;
  18. case CBCentralManagerStateUnauthorized:
  19. NSLog(@">>>CBCentralManagerStateUnauthorized");
  20. break;
  21. case CBCentralManagerStatePoweredOff:
  22. NSLog(@">>>CBCentralManagerStatePoweredOff");
  23. break;
  24. case CBCentralManagerStatePoweredOn:
  25. {
  26. NSLog(@">>>CBCentralManagerStatePoweredOn");
  27. // 开始扫描周围的外设。
  28. /*
  29. -- 两个参数为Nil表示默认扫描所有可见蓝牙设备。
  30. -- 注意:第一个参数是用来扫描有指定服务的外设。然后有些外设的服务是相同的,比如都有FFF5服务,那么都会发现;而有些外设的服务是不可见的,就会扫描不到设备。
  31. -- 成功扫描到外设后调用didDiscoverPeripheral
  32. */
  33. [self.centralManager scanForPeripheralsWithServices:nil options:nil];
  34. }
  35. break;
  36. default:
  37. break;
  38. }
  39. }
  1. #pragma mark 发现外设
  2. - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI{
  3. NSLog(@"Find device:%@", [peripheral name]);
  4. if (![_deviceDic objectForKey:[peripheral name]]) {
  5. NSLog(@"Find device:%@", [peripheral name]);
  6. if (peripheral!=nil) {
  7. if ([peripheral name]!=nil) {
  8. if ([[peripheral name] hasPrefix:@"根据设备名过滤"]) {
  9. [_deviceDic setObject:peripheral forKey:[peripheral name]];
  10. // 停止扫描, 看需求决定要不要加
  11. // [_centralManager stopScan];
  12. // 将设备信息传到外面的页面(VC), 构成扫描到的设备列表
  13. if ([self.delegate respondsToSelector:@selector(dataWithBluetoothDic:)]) {
  14. [self.delegate dataWithBluetoothDic:_deviceDic];
  15. }
  16. }
  17. }
  18. }
  19. }
  20. }

3.连接外围设备

  1. // 连接设备(.h中声明出去的接口, 一般在点击设备列表连接时调用)
  2. - (void)connectDeviceWithPeripheral:(CBPeripheral *)peripheral
  3. {
  4. [self.centralManager connectPeripheral:peripheral options:nil];
  5. }
  1. #pragma mark 连接外设--成功
  2. - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
  3. //连接成功后停止扫描,节省内存
  4. [central stopScan];
  5. peripheral.delegate = self;
  6. self.peripheral = peripheral;
  7. //4.扫描外设的服务
  8. /**
  9. -- 外设的服务、特征、描述等方法是CBPeripheralDelegate的内容,所以要先设置代理peripheral.delegate = self
  10. -- 参数表示你关心的服务的UUID,比如我关心的是"FFE0",参数就可以为@[[CBUUID UUIDWithString:@"FFE0"]].那么didDiscoverServices方法回调内容就只有这两个UUID的服务,不会有其他多余的内容,提高效率。nil表示扫描所有服务
  11. -- 成功发现服务,回调didDiscoverServices
  12. */
  13. [peripheral discoverServices:@[[CBUUID UUIDWithString:@"你要用的服务UUID"]]];
  14. if ([self.delegate respondsToSelector:@selector(didConnectBle)]) {
  15. // 已经连接
  16. [self.delegate didConnectBle];
  17. }
  18. }
  1. #pragma mark 连接外设——失败
  2. - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
  3. NSLog(@"%@", error);
  4. }
  1. #pragma mark 取消与外设的连接回调
  2. - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
  3. NSLog(@"%@", peripheral);
  4. }

4. 获得外围设备的服务

  1. #pragma mark 发现服务回调
  2. - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
  3. //NSLog(@"didDiscoverServices,Error:%@",error);
  4. CBService * __nullable findService = nil;
  5. // 遍历服务
  6. for (CBService *service in peripheral.services)
  7. {
  8. //NSLog(@"UUID:%@",service.UUID);
  9. if ([[service UUID] isEqual:[CBUUID UUIDWithString:@"你要用的服务UUID"]])
  10. {
  11. findService = service;
  12. }
  13. }
  14. NSLog(@"Find Service:%@",findService);
  15. if (findService)
  16. [peripheral discoverCharacteristics:NULL forService:findService];
  17. }

5、获得服务的特征

  1. #pragma mark 发现特征回调
  2. /**
  3. -- 发现特征后,可以根据特征的properties进行:读readValueForCharacteristic、写writeValue、订阅通知setNotifyValue、扫描特征的描述discoverDescriptorsForCharacteristic。
  4. **/
  5. - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
  6. for (CBCharacteristic *characteristic in service.characteristics) {
  7. if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"你要用的特征UUID"]]) {
  8. /**
  9. -- 读取成功回调didUpdateValueForCharacteristic
  10. */
  11. self.characteristic = characteristic;
  12. // 接收一次(是读一次信息还是数据经常变实时接收视情况而定, 再决定使用哪个)
  13. // [peripheral readValueForCharacteristic:characteristic];
  14. // 订阅, 实时接收
  15. [peripheral setNotifyValue:YES forCharacteristic:characteristic];
  16. // 发送下行指令(发送一条)
  17. NSData *data = [@"硬件工程师给我的指令, 发送给蓝牙该指令, 蓝牙会给我返回一条数据" dataUsingEncoding:NSUTF8StringEncoding];
  18. // 将指令写入蓝牙
  19. [self.peripheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
  20. }
  21. /**
  22. -- 当发现characteristic有descriptor,回调didDiscoverDescriptorsForCharacteristic
  23. */
  24. [peripheral discoverDescriptorsForCharacteristic:characteristic];
  25. }
  26. }

6.从外围设备读取数据

  1. #pragma mark - 获取值
  2. - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
  3. // characteristic.value就是蓝牙给我们的值(我这里是json格式字符串)
  4. NSData *jsonData = [characteristic.value dataUsingEncoding:NSUTF8StringEncoding];
  5. NSDictionary *dataDic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:nil];
  6. // 将字典传出去就可以使用了
  7. }
  8. #pragma mark - 中心读取外设实时数据
  9. - (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
  10. if (characteristic.isNotifying) {
  11. [peripheral readValueForCharacteristic:characteristic];
  12. } else {
  13. NSLog(@"Notification stopped on %@. Disconnecting", characteristic);
  14. NSLog(@"%@", characteristic);
  15. [self.centralManager cancelPeripheralConnection:peripheral];
  16. }
  17. }

7. 给外围设备发送(写入)数据

  1. // 上文中发现特征之后, 发送下行指令的时候其实就是向蓝牙中写入数据
  2. // 例:
  3. // 发送检查蓝牙命令
  4. - (void)writeCheckBleWithBle
  5. {
  6. _style = 1;
  7. // 发送下行指令(发送一条)
  8. NSData *data = [@"硬件工程师提供给你的指令, 类似于5E16010203...这种很长一串" dataUsingEncoding:NSUTF8StringEncoding];
  9. [self.peripheral writeValue:data forCharacteristic:self.characteristic type:CBCharacteristicWriteWithResponse];
  10. }
  1. #pragma mark 数据写入成功回调
  2. - (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
  3. NSLog(@"写入成功");
  4. if ([self.delegate respondsToSelector:@selector(didWriteSucessWithStyle:)]) {
  5. [self.delegate didWriteSucessWithStyle:_style];
  6. }
  7. }

8. 另外

  1. // 扫描设备
  2. - (void)scanDevice
  3. {
  4. if (_centralManager == nil) {
  5. self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
  6. [_deviceDic removeAllObjects];
  7. }
  8. }
  1. #pragma mark - 断开连接
  2. - (void)disConnectPeripheral{
  3. /**
  4. -- 断开连接后回调didDisconnectPeripheral
  5. -- 注意断开后如果要重新扫描这个外设,需要重新调用[self.centralManager scanForPeripheralsWithServices:nil options:nil];
  6. */
  7. [self.centralManager cancelPeripheralConnection:self.peripheral];
  8. }
  1. #pragma mark - 停止扫描外设
  2. - (void)stopScanPeripheral{
  3. [self.centralManager stopScan];
  4. }

由于硬件方面刚开始用蓝牙2.0跟我对接, 导致程序一直搜索不到设备.希望小伙伴们注意一下这个问题. 如果有不清楚的地方欢迎留言探讨.

原文链接:http://www.cnblogs.com/shuaibaobao/p/10444878.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号