iOS开发--蓝牙开发(4.0)

作者: CoderW | 来源:发表于2018-07-02 15:33 被阅读133次

最近由于项目需要, 一直在研究蓝牙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、创建一个CBCentralManager实例来进行蓝牙管理;

 2、搜索扫描外围设备;

 3、连接外围设备;

 4、获得外围设备的服务;

 5、获得服务的特征;

 6、从外围设备读取数据;

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

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


WechatIMG4.jpeg
  1. 初始化
#import <CoreBluetooth/CoreBluetooth.h>
self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
  1. 搜索扫描外围设备
/**
 *  --  初始化成功自动调用
 *  --  必须实现的代理,用来返回创建的centralManager的状态。
 *  --  注意:必须确认当前是CBCentralManagerStatePoweredOn状态才可以调用扫描外设的方法:
 scanForPeripheralsWithServices
 */
- (void)centralManagerDidUpdateState:(CBCentralManager *)central{
    switch (central.state) {
        case CBCentralManagerStateUnknown:
            NSLog(@">>>CBCentralManagerStateUnknown");
            break;
        case CBCentralManagerStateResetting:
            NSLog(@">>>CBCentralManagerStateResetting");
            break;
        case CBCentralManagerStateUnsupported:
            NSLog(@">>>CBCentralManagerStateUnsupported");
            break;
        case CBCentralManagerStateUnauthorized:
            NSLog(@">>>CBCentralManagerStateUnauthorized");
            break;
        case CBCentralManagerStatePoweredOff:
            NSLog(@">>>CBCentralManagerStatePoweredOff");
            break;
        case CBCentralManagerStatePoweredOn:
        {
            NSLog(@">>>CBCentralManagerStatePoweredOn");
            // 开始扫描周围的外设。
            /*
             -- 两个参数为Nil表示默认扫描所有可见蓝牙设备。
             -- 注意:第一个参数是用来扫描有指定服务的外设。然后有些外设的服务是相同的,比如都有FFF5服务,那么都会发现;而有些外设的服务是不可见的,就会扫描不到设备。
             -- 成功扫描到外设后调用didDiscoverPeripheral
             */
            [self.centralManager scanForPeripheralsWithServices:nil options:nil];
        }
            break;
        default:
            break;
    }
}
#pragma mark 发现外设
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI{
    NSLog(@"Find device:%@", [peripheral name]);
    if (![_deviceDic objectForKey:[peripheral name]]) {
        NSLog(@"Find device:%@", [peripheral name]);
        if (peripheral!=nil) {
            if ([peripheral name]!=nil) {
                if ([[peripheral name] hasPrefix:@"根据设备名过滤"]) {
                    [_deviceDic setObject:peripheral forKey:[peripheral name]];
                     // 停止扫描, 看需求决定要不要加
//                    [_centralManager stopScan];
                    // 将设备信息传到外面的页面(VC), 构成扫描到的设备列表
                    if ([self.delegate respondsToSelector:@selector(dataWithBluetoothDic:)]) {
                        [self.delegate dataWithBluetoothDic:_deviceDic];
                    }
                }
            }
        }
    }
}

3.连接外围设备

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

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

        /**
         -- 当发现characteristic有descriptor,回调didDiscoverDescriptorsForCharacteristic
         */
        [peripheral discoverDescriptorsForCharacteristic:characteristic];
    }
}

6.从外围设备读取数据

#pragma mark - 获取值
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    // characteristic.value就是蓝牙给我们的值(我这里是json格式字符串)
    NSData *jsonData = [characteristic.value dataUsingEncoding:NSUTF8StringEncoding];
        NSDictionary *dataDic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:nil];
    // 将字典传出去就可以使用了
}

#pragma mark - 中心读取外设实时数据
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    if (characteristic.isNotifying) {
        [peripheral readValueForCharacteristic:characteristic];
    } else { 
        NSLog(@"Notification stopped on %@.  Disconnecting", characteristic);
        NSLog(@"%@", characteristic);
        [self.centralManager cancelPeripheralConnection:peripheral];
    }
}
  1. 给外围设备发送(写入)数据
// 上文中发现特征之后, 发送下行指令的时候其实就是向蓝牙中写入数据
// 例:
// 发送检查蓝牙命令
- (void)writeCheckBleWithBle
{
    _style = 1;
    // 发送下行指令(发送一条)
    NSData *data = [@"硬件工程师提供给你的指令, 类似于5E16010203...这种很长一串" dataUsingEncoding:NSUTF8StringEncoding];
    [self.peripheral writeValue:data forCharacteristic:self.characteristic type:CBCharacteristicWriteWithResponse];
}
#pragma mark 数据写入成功回调
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    NSLog(@"写入成功");
    if ([self.delegate respondsToSelector:@selector(didWriteSucessWithStyle:)]) {
        [self.delegate didWriteSucessWithStyle:_style];
    }
}
  1. 另外
- (void)scanDevice
{
    if (_centralManager == nil) {
    self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
    [_deviceDic removeAllObjects];
     }
}
#pragma mark 断开连接
- (void)disConnectPeripheral{
    /**
     -- 断开连接后回调didDisconnectPeripheral
     -- 注意断开后如果要重新扫描这个外设,需要重新调用[self.centralManager scanForPeripheralsWithServices:nil options:nil];
     */
    [self.centralManager cancelPeripheralConnection:self.peripheral];
}
#pragma mark 停止扫描外设
- (void)stopScanPeripheral{
    [self.centralManager stopScan];
}

关于蓝牙4.0, 基本上用到的就是这些, 由于之前没有做过蓝牙开发, 硬件方面刚开始用蓝牙2.0跟我对接, 导致程序一直搜索不到设备.希望小伙伴们注意一下这个问题, 少踩一下坑. 另外如果使用蓝牙2.0, 想要发布在AppStore的话,需要进行MFI认证, 据说认证费很贵.需要的可以了解一下.蓝牙4.0就没有这么多说道了, 希望这篇文章可以帮到你.

相关文章

  • iOS开发蓝牙4.0初识

    iOS开发蓝牙4.0初识转载 2015-09-20 15:26:44标签:ios开发蓝牙ios开发蓝牙4.0ios...

  • iOS 蓝牙4.0开发

    iOS 蓝牙4.0开发

  • iOS蓝牙4.0,收发数据设计

    iOS蓝牙开发,现在常规使用的是CoreBlueTooth.framework,即蓝牙4.0开发框架。 1.CBC...

  • iOS 蓝牙BLE4.0开发

    蓝牙开发,现在普遍的都是BLE4.0低功耗蓝牙,CoreBluetooth是iOS 开发I比较推荐的一种开发方法...

  • iOS学习-蓝牙

    一、Core Bluetooth iOS中使用Core Bluetooth这个框架来进行蓝牙的开发支持蓝牙4.0,...

  • iOS BlueTooth HID(Human Interfac

    1.HID做什么用的? 在iOS蓝牙开发当中,现在的主流是使用蓝牙4.0,使用CoreBluetooth来进行开发...

  • iOS蓝牙4.0,后台监听来电

    在上一篇文章《iOS蓝牙4.0收发数据设计》,有简单的介绍收发数据设计。在iOS蓝牙4.0开发过程中,肯定还有许多...

  • iOS蓝牙4.0基础开发

    1.蓝牙开发基础 蓝牙4.0是低电量模式所以也叫4.0BLE。本文将使用iOS系统提供的CoreBluetooth...

  • iOS开发--蓝牙开发(4.0)

    最近由于项目需要, 一直在研究蓝牙4.0,在这儿分享给大家, 望共同进步. 一、关于蓝牙开发的一些重要的理论概念:...

  • iOS蓝牙(BLE4.0低功耗)详细渗透讲解

    iOS 蓝牙4.0开发使用 嗨大家好,我是iOS开发一枚大帅比,过去的几年项目涉及到蓝牙比较多,抽空之余,把使用的...

网友评论

  • CoderW:感谢《iOS 开发成神之路》,《程序员》,《iOS Developer》专题收录~
  • ZHG:我想在蓝牙扫描到的时候,接受广播,获取广播data,Android 只要解析scanRecod 就能得到自己想要的信息,iOS 怎么弄呢 ??
    CoderW:@Mr_Four kCBAdvDataManufacturerData就是广播包数据, 正常情况是可以收到的, 我也不知道你这个的具体原因, 感觉还是硬件工程师那边的事. 对于接收不到广播包, 大部分原因就是因为蓝牙模块是iBeacon模式, 所以还是建议检查一下.可以改成从透传试一下
    ZHG:@CoderW 应该不是iBeacon模式
    我可以获得到
    {
    kCBAdvDataIsConnectable = 1;
    kCBAdvDataLocalName = BLE;
    kCBAdvDataServiceUUIDs = (
    "6E41111A-B5A3-F393-E0A9-00000000"
    );
    kCBAdvDataTxPowerLevel = 0;
    }
    这些数据,就是没有kCBAdvDataManufacturerData 这个key,我需要硬件更改些什么呢?
    CoderW:苹果方面一般是禁止读取广播信息的,扫描设备时可以解析advertisementData, 可以得到kCBAdvDataManufacturerData, 如果真要的话你可以让硬件那边把数据做到 kCBAdvDataManufacturerData 这个字段里面.
    另外检查一下外设是否设置成了iBeacon模式, ibeacon会限制ios可接收的广播信息。通过蓝牙模块源码中的simpleBLEPeripheral.c或者修改AT指令集更改模式.希望对你有所帮助.

本文标题:iOS开发--蓝牙开发(4.0)

本文链接:https://www.haomeiwen.com/subject/nghluftx.html