做蓝牙少,遇到了又不会 尴尬

菜鸟实验室 2017-11-03

首先IOS设备本身的蓝牙并不是用来给你传输文件的,这点你要深切的理解,苹果之所以给他们装上蓝牙不过是让你连连蓝牙耳机啊,蓝牙音箱之类的,因为非越狱苹果上面听歌不都是要花钱的么,如果你用蓝牙把歌曲传给别人,那不是侵权了么(当然,在TC没有侵权一说),所以啊,苹果在硬件上面就把你传输文件给限制了。

下面小编将分享一些蓝牙的基本思路和代码实现

iOS中蓝牙的实现策略

GameKit:多用于对战类游戏(比如五子棋对战),从iOS7开始过期。

MultipeerConnectivity:可以用于替代GameKit,多用于非联网状态下,通过WiFi或者蓝牙来进行文件共享,且只能用于iOS设备之间的连接,局限于同一个app的交互。

ExternalAccessory:用于第三方蓝牙设备交互,但设备必须经过苹果MFI认证。

CoreBluetooth:就是所谓的BLE,可用于第三方蓝牙设备交互,必须要支持蓝牙4.0;硬件至少是4s,系统至少是iOS6。最大特点主低功耗。也是目前应用最广泛的主流框架,常用的有运动手环、智能家居等。

Core Bluetooth
CoreBluetooth框架的核心就是peripheral和central。其API分别对应不同外设模式和中心模式。如下图:做蓝牙少,遇到了又不会 尴尬

做蓝牙少,遇到了又不会 尴尬

蓝牙设备状态

待机状态(standby):设备没有传输和发送数据,并且没有连接到任何外设

广播状态(Advertiser):周期性广播状态

扫描状态(Scanner):主动搜索正在广播的设备

发起链接状态(Initiator):主动向扫描设备发起连接

主设备(Master):作为主设备连接到其它设备.

从设备(Slave):作为从设备链接到其它设备

蓝牙工作状态

准备(Standby)

广播(Advertising)

监听扫描(Scanning)

发起连接(Initiating)

已连接(Connected)

BLE中心模式流程

建立中心角色

扫描外设(Discover Peripheral)

连接外设(Connect Peripheral)

扫描外设服务和特征(Discover Services And Characteristics)

获取外设services

获取外设Characteristics,获取characteristics值,获取Characteristics的Descriptor和Descriptor值

利用特征与外设做数据交互(Explore And Interact)

订阅Characteristic的通知

断开连接(Disconnect)

代码实战

# **** ↓ central模式 ↓ ****

1 . 建立主设备管理类,设置代理。

#import <CoreBluetooth/CoreBluetooth.h>

@interface LEOBLEController () <CBCentralManagerDelegate>

/**中心管理 */

@property (nonatomic, strong) CBCentralManager *cMgr;

@end

@implementation LEOBLEController

#pragma mark - 懒加载

// 1.建立中心管理者

- (CBCentralManager *)cMgr

{

if (!_cMgr) {

NSLog(@"%s, line = %d", __FUNCTION__, __LINE__);

/*

设置代理,CBCentralManagerDelegate

必须实现的:

- (void)centralManagerDidUpdateState:(CBCentralManager *)central;//主设备状态改变调用,在初始化CBCentralManager的适合会打开设备,只有当设备正确打开后才能使用

其他选择实现的委托中比较重要的:

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI; //找到外设

- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral;//连接外设成功

- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;//外设连接失败

- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;//断开外设

*/

_cMgr = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()]; // 默认主线程

}

return _cMgr;

}

- (void)viewDidLoad {

[super viewDidLoad];

self.title = @"LEOBLE";

self.view.backgroundColor = [UIColor redColor];

// 初始化

[self cMgr];

// 不能在此处扫描,因为状态还没变为打开

//[self.cMgr scanForPeripheralsWithServices:nil options:nil];

}

2 .扫描外设--<只有设备成功打开,才能开始扫描,否则会报错>。

#pragma mark - CBCentralManagerDelegate// 设备正确打开后使用

- (void)centralManagerDidUpdateState:(CBCentralManager *)central

{

NSLog(@"%s, line = %d", __FUNCTION__, __LINE__);

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表示扫描所有外设

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI;

*/

[self.cMgr scanForPeripheralsWithServices:nil options:nil];

break;

default:

break;

}

}// 扫描到设备会进入到此代理方法

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI

{

NSLog(@"%s, line = %d, per = %@, data = %@, rssi = %@", __FUNCTION__, __LINE__, peripheral, advertisementData, RSSI);

// 接下来连接设备

}

3 .连接外设扫描外设,打印结果

做蓝牙少,遇到了又不会 尴尬

4 .扫描到外设会进入到此代理方法

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI

{

NSLog(@"%s, line = %d, per = %@, data = %@, rssi = %@", __FUNCTION__, __LINE__, peripheral, advertisementData, RSSI);

// 判断扫描结果

if ([peripheral.name isEqualToString:@"OBand-75"]) {

/*

一个主设备最多能连7个外设,每个外设最多只能给一个主设备连接,连接成功,失败,断开会进入各自的代理

- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral;//连接外设成功

- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;//外设连接失败

- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;//断开外设

*/

// 保存外设,否则方法结束就销毁

self.per = peripheral;

[self.cMgr connectPeripheral:self.per options:nil];

}else

{

// 此处Alert提示#warning noCode

NSLog(@"没扫描到 >>>>>>>> %s, line = %d", __FUNCTION__, __LINE__);

}

}// 外设连接成功

- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral

{

NSLog(@"%s, line = %d", __FUNCTION__, __LINE__);

NSLog(@">>>连接到名称为(%@)的设备-成功",peripheral.name);

}// 外设连接失败

- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error

{

NSLog(@"%s, line = %d", __FUNCTION__, __LINE__);

}// 断开连接(丢失连接)

- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error

{

NSLog(@"%s, line = %d", __FUNCTION__, __LINE__);

}

5 .扫描外设中的服务和特征

获取外设的services,然后在代理方法peripheral:didDiscoverServices:中遍历services

// 外设连接成功

- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral

{

NSLog(@"%s, line = %d", __FUNCTION__, __LINE__);

NSLog(@">>>连接到名称为(%@)的设备-成功",peripheral.name);

//设置的peripheral代理CBPeripheralDelegate

//@interface ViewController : UIViewController<CBCentralManagerDelegate,CBPeripheralDelegate>

[peripheral setDelegate:self];

//扫描外设Services,成功后会进入方法:-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{

[peripheral discoverServices:nil];

/*

Discovers the specified services of the peripheral.

An array of CBUUID objects that you are interested in. Here, each CBUUID object represents a UUID that identifies the type of service you want to discover.

*/

}

#pragma mark - CBPeripheralDelegate// 发现外设的service

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error

{

if (error)

{

NSLog(@">>>Discovered services for %@ with error: %@", peripheral.name, [error localizedDescription]);

return;

}

for (CBService *service in peripheral.services) {

NSLog(@"service.UUID = %@", service.UUID);

//扫描每个service的Characteristics,扫描到后会进入方法: -(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error

[peripheral discoverCharacteristics:nil forService:service];

}

}

获取外设的characteris,获取Characteristics的值,获取Characteristics的Descriptor以及Descriptor的值

// 外设发现service的特征

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error

{

if (error)

{

NSLog(@"error Discovered characteristics for %@ with error: %@", service.UUID, [error localizedDescription]);

return;

}

for (CBCharacteristic *characteristic in service.characteristics)

{

NSLog(@"service:%@ 的 Characteristic: %@",service.UUID,characteristic.UUID);

}

#warning 分开并不符合编码规范,是为了方便看

//获取Characteristic的值,读到数据会进入方法:-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error

for (CBCharacteristic *characteristic in service.characteristics){

[peripheral readValueForCharacteristic:characteristic]; // 外设读取特征的值

}

//搜索Characteristic的Descriptors,读到数据会进入方法:-(void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error

for (CBCharacteristic *characteristic in service.characteristics){

[peripheral discoverDescriptorsForCharacteristic:characteristic]; // 外设发现特征的描述

}

}

// 获取characteristic的值

- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error

{

//打印出characteristic的UUID和值

//!注意,value的类型是NSData,具体开发时,会根据外设协议制定的方式去解析数据

NSLog(@"%s, line = %d, characteristic.UUID:%@ value:%@", __FUNCTION__, __LINE__, characteristic.UUID, characteristic.value);

}// 获取Characteristics的 descriptor的值

- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForDescriptor:(nonnull CBDescriptor *)descriptor error:(nullable NSError *)error

{

//打印出DescriptorsUUID 和value

//这个descriptor都是对于characteristic的描述,一般都是字符串,所以这里我们转换成字符串去解析

NSLog(@"%s, line = %d, descriptor.UUID:%@ value:%@", __FUNCTION__, __LINE__, descriptor.UUID, descriptor.value);

}// 发现特征Characteristics的描述Descriptor

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error

{

NSLog(@"%s, line = %d", __FUNCTION__, __LINE__);

for (CBDescriptor *descriptor in characteristic.descriptors) {

NSLog(@"descriptor.UUID:%@",descriptor.UUID);

}

}

6 . 写数据到特征中

// 5.将数据写入特征(自定义方法,为了看的更清楚,没别的意思)

- (void)leo_peripheral:(CBPeripheral *)peripheral writeData:(NSData *)data forCharacteristic:(CBCharacteristic *)characteristic

{

/*

typedef NS_OPTIONS(NSUInteger, CBCharacteristicProperties) {

CBCharacteristicPropertyBroadcast = 0x01,

CBCharacteristicPropertyRead = 0x02,

CBCharacteristicPropertyWriteWithoutResponse = 0x04,

CBCharacteristicPropertyWrite = 0x08,

CBCharacteristicPropertyNotify = 0x10,

CBCharacteristicPropertyIndicate = 0x20,

CBCharacteristicPropertyAuthenticatedSignedWrites = 0x40,

CBCharacteristicPropertyExtendedProperties = 0x80,

CBCharacteristicPropertyNotifyEncryptionRequired NS_ENUM_AVAILABLE(NA, 6_0) = 0x100,

CBCharacteristicPropertyIndicateEncryptionRequired NS_ENUM_AVAILABLE(NA, 6_0) = 0x200

};

打印出特征的权限(characteristic.properties),可以看到有很多种,这是一个NS_OPTIONS的枚举,可以是多个值

常见的又read,write,noitfy,indicate.知道这几个基本够用了,前俩是读写权限,后俩都是通知,俩不同的通知方式

*/

NSLog(@"%s, line = %d, characteristic.properties:%d", __FUNCTION__, __LINE__, characteristic.properties);

// 只有特征的properties中有写的属性时候,才写

if (characteristic.properties & CBCharacteristicPropertyWrite) {

// 这句才是正宗的核心代码

[peripheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];

}

}

7 .订阅特征的通知

// 设置通知

- (void)leo_peripheral:(CBPeripheral *)peripheral setNotifyForCharacteristic:(CBCharacteristic *)characteristic

{

// 设置通知, 数据会进入 peripheral:didUpdateValueForCharacteristic:error:方法

[peripheral setNotifyValue:YES forCharacteristic:characteristic];

}// 取消通知

- (void)leo_peripheral:(CBPeripheral *)peripheral cancelNotifyForCharacteristic:(CBCharacteristic *)characteristic

{

[peripheral setNotifyValue:NO forCharacteristic:characteristic];

}

8 .断开连接

// 7.断开连接

- (void)leo_cMgr:(CBCentralManager *)cMgr stopScanAndDisConnectWithPeripheral:(CBPeripheral *)peripheral

{

// 停止扫描

[cMgr stopScan];

// 断开连接

[cMgr cancelPeripheralConnection:peripheral];

}

需要的 留下邮箱 发给你们

相关推荐

faguoduifangui / 0评论 2019-10-27
chinaycheng / 0评论 2019-10-22