蓝牙常用开发步骤

如果你进来了,点下关注行不行_

随说 : 网上资料一大堆, 可以随便google搜一下加深理解, 这里作一个整理, 可收藏起来当资料随时翻查

蓝牙常用框架 : CoreBluetooth
蓝牙常用库 :
BabyBluetooth
YmsCoreBluetooth
基本概念要搞清楚

1. 名词解释#


CoreBluetooth框架的核心其实是两个东西,peripheral(CBCebtralManager类)和central(CBPeripheralManager类), 可以理解成外设和中心
打个比喻.小米手环是peripheral,我们的iphone手机是central,所以就会大量使用CBCebtralManager类。(Iphone理解为连接)
又比如像用一个ipad和一个iphone通讯, ipad可以认为是central,iphone端是peripheral ,这种情况下在iphone端就要使用CBPeripheralManager类来开发了。(Iphone理解为外设)
发起连接的时central,被连接的设备为perilheral


每个蓝牙4.0的设备都是通过服务和特征来展示自己的

service : 一个设备必然包含一个服务以上(至少包含一个服务,有可能包含更多的服务)
characteristic : 包含在服务下, 描述该服务下特定的功能的, 一般拥有多个characteristic, 而且characteristic有类型, 读(read), 写(write), 通知(notify)等
UUID(Universally Unique Identifier) : 设备的每一个service有他相应的UUID, 同时每一个characteristic也有相应的UUID

简单理解 : service and characteristic 每个设备会提供服务和特征,类似于服务端的api,但是机构不同。每个外设会有很多服务,每个服务中包含很多字段,这些字段的权限一般分为 读read,写write,通知notiy几种,就是我们连接设备后具体需要操作的内容。

蓝牙常用开发步骤_第1张图片

注 : 蓝牙设备硬件厂商通常都会提供他们的设备里面各个服务(service)和特征(characteristics)的功能,比如哪些是用来交互(读写),哪些可获取模块信息(只读)等, 也就是说, 蓝牙设备硬件厂商, 提供了这些


2. 开发基本步骤#

  1. 建立中心角色
  2. 扫描外设(discover)
  3. 连接外设 (connect)
  4. 扫描外设中的服务和特征(discover)
    • 4.1 获取外设的services
    • 4.2 获取外设的Characteristics,获取Characteristics的值,获取Characteristics的Descriptor和Descriptor的值
  5. 与外设做数据交互(explore and interact)
  6. 订阅Characteristic的通知
  7. 断开连接(disconnect)

一 : 建立中心角色####

// 连接中心角色, 所谓的中心角色,就是蓝牙设备管理对象, 可以把他理解为主设备,通过他,可以去扫描和链接外设
// 初始化并设置委托和线程队列,最好一个线程的参数可以为nil,默认会就main线程
self.centralManager = [[CBCentralManager alloc]initWithDelegate:self queue:dispatch_get_main_queue()];


// 这个是BabyBluetooth第三方库
// 单例模式
+ (instancetype)shareBabyBluetooth {
    static BabyBluetooth *share = nil;
    static dispatch_once_t oneToken;
    dispatch_once(&oneToken, ^{
        share = [[BabyBluetooth alloc]init];
    });
   return share;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        //初始化对象
        babyCentralManager = [[BabyCentralManager alloc]init];// 蓝牙中心模式实现类
        babySpeaker = [[BabySpeaker alloc]init]; // block查找和channel切换
        babyPeripheralManager = [[BabyPeripheralManager alloc]init]; // 外设模式实现类
        // babyPeripheralManager里面有一个成员属性babySpeaker , 将这个赋值于它
        babyPeripheralManager->babySpeaker = babySpeaker;
        // babyCentralManager里面有一个成员属性babySpeaker , 将这个赋值于它
        babyCentralManager->babySpeaker = babySpeaker;
    }
    return self;
    
}

// 注册蓝牙中心后, 必须调用的代理方法, 不然会报错
// 主设备状态改变的委托,在初始化CBCentralManager的适合会打开设备,只有当设备正确打开后才能使用
// 特别注意, 需要在状态CBCentralManagerStatePoweredOn下才能使用任何设备
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
    
    //发送通知
    [[NSNotificationCenter defaultCenter]postNotificationName:BabyNotificationAtCentralManagerDidUpdateState object:@{@"central":central}];
    
    switch (central.state) {
        case CBCentralManagerStateUnknown:
            BabyLog(@">>>CBCentralManagerStateUnknown");
            break;
        case CBCentralManagerStateResetting:
            BabyLog(@">>>CBCentralManagerStateResetting");
            break;
        case CBCentralManagerStateUnsupported:
            BabyLog(@">>>CBCentralManagerStateUnsupported");
            break;
        case CBCentralManagerStateUnauthorized:
            BabyLog(@">>>CBCentralManagerStateUnauthorized");
            break;
        case CBCentralManagerStatePoweredOff:
            BabyLog(@">>>CBCentralManagerStatePoweredOff");
            break;
        case CBCentralManagerStatePoweredOn:
            BabyLog(@">>>CBCentralManagerStatePoweredOn");
            [[NSNotificationCenter defaultCenter] postNotificationName:BabyNotificationAtCentralManagerEnable object:@{@"central":central}];
            break;
        default:
            break;
    }
    //状态改变callback
    if ([currChannel blockOnCentralManagerDidUpdateState]) {
        [currChannel blockOnCentralManagerDidUpdateState](central);
    }
}



二 : 扫描设备####

// 框架提供的方法
/*!
 *  @method scanForPeripheralsWithServices:options:
 *
 *  @param serviceUUIDs UUID列表, 参数有值的话则只扫描改UUID
 *  @param options      An optional dictionary specifying options for the scan.
 *
 *
 *  @see               发现设备就会调用这个代理方法 centralManager:didDiscoverPeripheral:advertisementData:RSSI:
 *  @seealso            CBCentralManagerScanOptionAllowDuplicatesKey
 * @seealso   CBCentralManagerScanOptionSolicitedServiceUUIDsKey
 *
 */
- (void)scanForPeripheralsWithServices:(nullable NSArray *)serviceUUIDs options:(nullable NSDictionary *)options;

// 当然有扫描方法就有停止扫描的方法
/*!
 *  @method stopScan:
 *
 *  @discussion Stops scanning for peripherals.
 *
 */
- (void)stopScan;



//这个是BabyBluetooth第三方库实现的扫描方法
//扫描Peripherals
- (void)scanPeripherals {
    [centralManager scanForPeripheralsWithServices:[currChannel babyOptions].scanForPeripheralsWithServices options:[currChannel babyOptions].scanForPeripheralsWithOptions];
}

三 : 发现设备 - 连接设备####

//这个是BabyBluetooth第三方库实现的连接方法
//扫描到Peripherals, 当扫描到设备, 就会执行这个代理方法entralManager:didDiscoverPeripheral:advertisementData:RSSI:
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
    
    //日志
    //BabyLog(@"当扫描到设备:%@",peripheral.name);
    [self addDiscoverPeripheral:peripheral];
    
    //发出通知
    [[NSNotificationCenter defaultCenter]postNotificationName:BabyNotificationAtDidDiscoverPeripheral
                                                       object:@{@"central":central,@"peripheral":peripheral,@"advertisementData":advertisementData,@"RSSI":RSSI}];
    //扫描到设备callback
    if ([currChannel filterOnDiscoverPeripherals]) {
        if ([currChannel filterOnDiscoverPeripherals](peripheral.name,advertisementData,RSSI)) {
           // 执行回调Block, 然后就会执行setBlockOnDiscoverToPeripherals:(void (^)(CBCentralManager *central,CBPeripheral *peripheral,NSDictionary *advertisementData, NSNumber *RSSI))block
             if ([currChannel blockOnDiscoverPeripherals]) { 
                [[babySpeaker callbackOnCurrChannel] blockOnDiscoverPeripherals](central,peripheral,advertisementData,RSSI);
            }
        }
    }
    
    //处理连接设备
    if (needConnectPeripheral) {
        if ([currChannel filterOnconnectToPeripherals](peripheral.name,advertisementData,RSSI)) {
            [centralManager connectPeripheral:peripheral options:[currChannel babyOptions].connectPeripheralWithOptions];
            //开一个定时器监控连接超时的情况
            connectTimer = [NSTimer scheduledTimerWithTimeInterval:5.0f target:self selector:@selector(disconnect:) userInfo:peripheral repeats:NO];
        }
    }
}


注意 : 
1, 回调这个代理方法,(CBPeripheral *)peripheral就是返现到的服务, 必须保存下来作为
2, 需要过滤搜索结果, 可以通过filterOnDiscoverPeripherals Block


------------

连接成功与失败,断开连接等会调用的三个代理方法
//连接到Peripherals-成功
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
            NSLog(@">>>连接到名称为(%@)的设备-成功",peripheral.name);
        }

//连接到Peripherals-失败
-(void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
            NSLog(@">>>连接到名称为(%@)的设备-失败,原因:%@",[peripheral name],[error localizedDescription]);
        }

//Peripherals断开连接
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
            NSLog(@">>>外设连接断开连接 %@: %@\n", [peripheral name], [error localizedDescription]);
        }

---------------

//BabyBluetooth第三方库实现的连接情况Block
//设置设备连接成功的委托,同一个baby对象,使用不同的channel切换委托回调
    [baby setBlockOnConnectedAtChannel:channelOnPeropheralView block:^(CBCentralManager *central, CBPeripheral *peripheral) {
        [SVProgressHUD showInfoWithStatus:[NSString stringWithFormat:@"设备:%@--连接成功",peripheral.name]];
    }];
    
    //设置设备连接失败的委托
    [baby setBlockOnFailToConnectAtChannel:channelOnPeropheralView block:^(CBCentralManager *central, CBPeripheral *peripheral, NSError *error) {
        NSLog(@"设备:%@--连接失败",peripheral.name);
        [SVProgressHUD showInfoWithStatus:[NSString stringWithFormat:@"设备:%@--连接失败",peripheral.name]];
    }];

    
    //设置设备断开连接的委托
    [baby setBlockOnDisconnectAtChannel:channelOnPeropheralView block:^(CBCentralManager *central, CBPeripheral *peripheral, NSError *error) {
        NSLog(@"设备:%@--断开连接",peripheral.name);
        [SVProgressHUD showInfoWithStatus:[NSString stringWithFormat:@"设备:%@--断开失败",peripheral.name]];
    }];

一些坑爹的情况#

1.为什么扫描不到外设?
->情况1:设备不支持
babybluetooth支持BLE4.0蓝牙设备,如果是2.0的设备,那肯定扫描不到
模拟器不支持蓝牙调试,必须使用真机调试
ios操作系统至少要在6.0以上

->情况2:外设没有开启广播
默认情况下打开手机或者ipad的蓝牙,在使用babybluetooth是扫描不到设备的,因为手机和ipad只是打开了蓝牙设备的电源而已,并没有发送广播,如果想扫描到设备,需要编程的方式,通过iphone或ipad,mac发送蓝牙广播。demo程序中有一个iphone和一个mac发送蓝牙广播的程序。
已连接的设备会停止广播,所以也搜索不到

->情况3:为什么系统的蓝牙能找到设备,但是使用babybluetooth的demo却无法找到?
这种情况一般是因为那个蓝牙设备是支持MFI的,并不是普通的ble设备。
关于MFI这里补充一下 :
MFI ( make for ipad ,iphone, itouch ), 专们为苹果设备制作的设备, 开发使用的是 ExternalAccessory 框架
所以这篇文章不予谈论

你可能感兴趣的:(蓝牙常用开发步骤)