如果你进来了,点下关注行不行_
随说 : 网上资料一大堆, 可以随便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几种,就是我们连接设备后具体需要操作的内容。
注 : 蓝牙设备硬件厂商通常都会提供他们的设备里面各个服务(service)和特征(characteristics)的功能,比如哪些是用来交互(读写),哪些可获取模块信息(只读)等, 也就是说, 蓝牙设备硬件厂商, 提供了这些
2. 开发基本步骤#
- 建立中心角色
- 扫描外设(discover)
- 连接外设 (connect)
- 扫描外设中的服务和特征(discover)
- 4.1 获取外设的services
- 4.2 获取外设的Characteristics,获取Characteristics的值,获取Characteristics的Descriptor和Descriptor的值
- 与外设做数据交互(explore and interact)
- 订阅Characteristic的通知
- 断开连接(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 框架
所以这篇文章不予谈论