- iOS中提供了4个框架用于实现蓝牙连接:
1.GameKit.framework(用法简单,只能用于iOS设备间,iOS 7过期)
2.MultipeerConnectivity.framework(只能iOS设备间,iOS 7用来替代GameKit,WiFi蓝牙都支持,WiFi优先级高)
3.ExternalAccessory.framework(可用于第三方蓝牙设备交互,但需要蓝牙设备经过苹果MFi认证)
4.CoreBluetooth(可用于第三方蓝牙设备交互,必须要支持蓝牙4.0)
当前主要使用CoreBluetooth(CoreBluetooth下无法使用模拟器进行演示)
蓝牙使用时需要两个两个设备,一个作为中心,一个作为外设,作为手机端,既可以作为外设,也可以作为中心,这里主要演示手机作为中心设备的场景
- CoreBluetooth实现的具体步骤主要有:
1.创建中央管理者
2.扫描外设
3.连接外设
4.查找服务
5.查找特征
6.读写数据
接收数据的示例代码:
#import "ViewController.h"
#import
@interface ViewController ()
// 扫描蓝牙设备按钮
@property (weak, nonatomic) IBOutlet UIButton *scanBtn;
// 中央管理者(自己的设备)
@property (nonatomic,strong) CBCentralManager *centralManager;
// 外设(相对自己,手机端需要去连接的设备)
@property (nonatomic,strong) CBPeripheral *peripheral;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 1. 创建一个中央管理者 (传递nil,将使用主队列)
self.centralManager = [[CBCentralManager alloc]initWithDelegate:self queue:nil];
self.scanBtn.enabled = NO;
}
// 扫描蓝牙
- (IBAction)scanBluetoothDevice{
// 2. 扫描外设 (传递nil 扫描所有外设)
[self.centralManager scanForPeripheralsWithServices:nil options:nil];
}
#pragma mark - CBCentralManagerDelegate
// 中央管理者已经更新状态后调用
- (void)centralManagerDidUpdateState:(CBCentralManager *)central{
/*
CBCentralManagerStateUnknown = 0, 未知
CBCentralManagerStateResetting, 正在重启
CBCentralManagerStateUnsupported, 不支持
CBCentralManagerStateUnauthorized, 未授权
CBCentralManagerStatePoweredOff, 关闭蓝牙
CBCentralManagerStatePoweredOn, 开启蓝牙 只有该状态才是正常情况
*/
if (central.state == CBCentralManagerStatePoweredOn) { // 蓝牙开启
// 当蓝牙开启时,扫描蓝牙
self.scanBtn.enabled = YES;
}
}
/**
* 已经发现某个外设后调用
*
* @param central 中央管理者
* @param peripheral 外设
* @param advertisementData 广播数据
* @param RSSI 信号强度 分贝
*/
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{
// 3. 连接外设(使用场景:显示搜索到的蓝牙设备列表,UI展示供用户选择,判断名称后进行连接)
/*
NSString *const CBAdvertisementDataLocalNameKey;
NSString *const CBAdvertisementDataManufacturerDataKey;
NSString *const CBAdvertisementDataServiceDataKey;
NSString *const CBAdvertisementDataServiceUUIDsKey;
NSString *const CBAdvertisementDataOverflowServiceUUIDsKey;
NSString *const CBAdvertisementDataTxPowerLevelKey;
NSString *const CBAdvertisementDataIsConnectable;
NSString *const CBAdvertisementDataSolicitedServiceUUIDsKey;
*/
if ([advertisementData[CBAdvertisementDataLocalNameKey] isEqualToString:@"外设名称"]) {
// 在查找到需要的设备后停止扫描外设
[self.centralManager stopScan];
// 连接外设
[self.centralManager connectPeripheral:peripheral options:nil];
// 记录外设
self.peripheral = peripheral;
}
}
/**
* 已经连接到外设后调用
*
* @param central 中央管理者
* @param peripheral 外设
*/
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
// 4. 查找服务 (传递nil,查找所有的服务)
[peripheral discoverServices:nil];
// 获取数据(查找的),设置外设的代理
peripheral.delegate = self;
}
#pragma mark - CBPeripheralDelegate
/**
* 已经查找到服务后调用
*
* @param peripheral 外设
* @param error 错误信息
*/
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
NSArray *serivicesArr = peripheral.services;
// 遍历服务,查找指定的所务
for (CBService *service in serivicesArr) {
if ([service.UUID.UUIDString isEqualToString:@"服务的UUID"] ) {
// 5. 查找特征
[peripheral discoverCharacteristics:nil forService:service];
}
}
}
// 已经查找到特征后调用
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
// 判断特征的UUID是否是需求的特征
for (CBCharacteristic *characteristic in service.characteristics) {
if ([characteristic.UUID.UUIDString isEqualToString:@"特征的UUID"]) {
// 6. 收发数据(读写数据)
// 读
[peripheral readValueForCharacteristic:characteristic];
}
}
}
// 当已经获取的更新的特征的数据后调用
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
NSData *data = characteristic.value;
NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
}
@end
如果需要发送数据,在didUpdateValueForCharacteristic中调用writeValue forCharacteristic方法
- (void)writeValue:(NSData *)data forCharacteristic:(CBCharacteristic *)characteristic type:(CBCharacteristicWriteType)type;
如果需要回应,发送数据时的类型需要为:CBCharacteristicWriteWithResponse
// 已经发送成功后调用
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
NSLog(@"发送成功");
}
完整的发送数据实例代码:
#import "ViewController.h"
#import
@interface ViewController ()
// 扫描蓝牙设备按钮
@property (weak, nonatomic) IBOutlet UIButton *scanBtn;
// 中央管理者(自己的设备)
@property (nonatomic,strong) CBCentralManager *centralManager;
// 外设
@property (nonatomic,strong) CBPeripheral *peripheral;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 1. 创建一个中央管理者 (传递nil,将使用主队列)
self.centralManager = [[CBCentralManager alloc]initWithDelegate:self queue:nil];
self.scanBtn.enabled = NO;
}
// 扫描蓝牙
- (IBAction)scanBluetoothDevice{
// 2. 扫描外设 (传递nil 扫描所有外设)
[self.centralManager scanForPeripheralsWithServices:nil options:nil];
}
#pragma mark - CBCentralManagerDelegate
// 中央管理者已经更新状态后调用
- (void)centralManagerDidUpdateState:(CBCentralManager *)central{
/*
CBCentralManagerStateUnknown = 0, 未知
CBCentralManagerStateResetting, 正在重启
CBCentralManagerStateUnsupported, 不支持
CBCentralManagerStateUnauthorized, 未授权
CBCentralManagerStatePoweredOff, 关闭蓝牙
CBCentralManagerStatePoweredOn, 开启蓝牙 只有该状态才是正常情况
*/
if (central.state == CBCentralManagerStatePoweredOn) { // 蓝牙开启
// 当蓝牙开启时,扫描蓝牙
self.scanBtn.enabled = YES;
}
}
/**
* 已经发现某个外设后调用
*
* @param central 中央管理者
* @param peripheral 外设
* @param advertisementData 广播数据
* @param RSSI 信号强度 分贝
*/
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{
// 3. 连接外设(使用场景:显示搜索到的蓝牙设备列表,UI展示供用户选择,判断名称后进行连接)
/*
NSString *const CBAdvertisementDataLocalNameKey;
NSString *const CBAdvertisementDataManufacturerDataKey;
NSString *const CBAdvertisementDataServiceDataKey;
NSString *const CBAdvertisementDataServiceUUIDsKey;
NSString *const CBAdvertisementDataOverflowServiceUUIDsKey;
NSString *const CBAdvertisementDataTxPowerLevelKey;
NSString *const CBAdvertisementDataIsConnectable;
NSString *const CBAdvertisementDataSolicitedServiceUUIDsKey;
*/
if ([advertisementData[CBAdvertisementDataLocalNameKey] isEqualToString:@"外设名称"]) {
// 连接外设
[self.centralManager connectPeripheral:peripheral options:nil];
// 记录外设
self.peripheral = peripheral;
}
}
/**
* 已经连接到外设后调用
*
* @param central 中央管理者
* @param peripheral 外设
*/
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
// 4. 查找服务 (传递nil,查找所有的服务)
[peripheral discoverServices:nil];
// 获取数据(查找的),设置外设的代理
peripheral.delegate = self;
}
#pragma mark - CBPeripheralDelegate
/**
* 已经查找到服务后调用
*
* @param peripheral 外设
* @param error 错误信息
*/
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
NSArray *serivicesArr = peripheral.services;
// 遍历服务,查找指定的所务
for (CBService *service in serivicesArr) {
if ([service.UUID.UUIDString isEqualToString:@"服务的UUID"] ) {
// 5. 查找特征
[peripheral discoverCharacteristics:nil forService:service];
}
}
}
// 已经查找到特征后调用
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
// 判断特征的UUID是否是需求的特征
for (CBCharacteristic *characteristic in service.characteristics) {
if ([characteristic.UUID.UUIDString isEqualToString:@"特征的UUID"]) {
// 6. 收发数据(读写数据)
// 读
[peripheral readValueForCharacteristic:characteristic];
}
}
}
// 当已经获取的更新的特征的数据后调用
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
// 发送数据
NSString *write = @"发送数据";
/*
CBCharacteristicWriteWithResponse = 0, 回应
CBCharacteristicWriteWithoutResponse, 只发送,不知道是否成功
*/
[peripheral writeValue:[write dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
}
// 已经发送成功后调用
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
NSLog(@"发送成功");
}
@end