以下代码实现了蓝牙广播、读特征、写特征、订阅特征
手机界面:
Main.storyboard:
文件结构:
生成UUID的方式:在终端输入下方指令
laimin$ uuidgen
主体代码:
//
// CoreBluetooth.h
// 01-蓝牙通信
//
// Created by laimin on 2018/3/1.
// Copyright © 2018年 laimin. All rights reserved.
//
#ifndef CoreBluetooth_h
#define CoreBluetooth_h
//服务
#define ServiceUUID @"59889B5B-4716-4F03-B480-5659CB289AC3"
//读特征
#define CharacteristicUUID @"7F5BCCCE-BC8C-4779-9B9F-0094324BF70C"
//写特征
#define WriteCharacteristicUUID @"7D1AF1E0-F1A7-4A47-982D-19683D796A7C"
//订阅特征
#define NotifyCharacteristicUUID @"A4C4CC7E-1E39-48EA-8BC0-004681DD10A2"
#endif /* CoreBluetooth_h */
//
// PhoneVC.m
// 01-蓝牙通信
//
// Created by laimin on 2018/3/1.
// Copyright © 2018年 laimin. All rights reserved.
//
#import "PhoneVC.h"
#import <CoreBluetooth/CoreBluetooth.h>
#import "CoreBluetooth.h"
@interface PhoneVC ()<CBCentralManagerDelegate, CBPeripheralDelegate>
@property (strong, nonatomic) CBCentralManager *centralManager;
//外部设备
@property (strong, nonatomic) CBPeripheral *peripheral;
@end
@implementation PhoneVC
- (IBAction)scanBluetoothDevice:(UIButton *)sender {
self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_global_queue(0, 0)];
}
#pragma mark - 代理方法
#pragma mark - CBCentralManagerDelegate
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
/**
CBManagerStateUnknown = 0,
CBManagerStateResetting,
CBManagerStateUnsupported,
CBManagerStateUnauthorized,
CBManagerStatePoweredOff,
CBManagerStatePoweredOn,
*/
switch (central.state) {
case CBManagerStatePoweredOn:{
NSLog(@"蓝牙功能已打开");
CBUUID *uuid = [CBUUID UUIDWithString:ServiceUUID];
[central scanForPeripheralsWithServices:@[uuid] options:nil];
}
break;
case CBManagerStatePoweredOff:{
NSLog(@"蓝牙功能已关闭");
}
break;
default:
break;
}
}
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI
{
NSLog(@"peripheral = %@", peripheral);
NSLog(@"advertisementData = %@", advertisementData);
NSLog(@"RSSI = %@", RSSI);
//绑定发现的外部设备
self.peripheral = peripheral;
//连接外部设备
/**
CBConnectPeripheralOptionNotifyOnConnectionKey
CBConnectPeripheralOptionNotifyOnDisconnectionKey
CBConnectPeripheralOptionNotifyOnNotificationKey
*/
[self.centralManager connectPeripheral:self.peripheral options:@{
CBConnectPeripheralOptionNotifyOnConnectionKey: @(1),
CBConnectPeripheralOptionNotifyOnDisconnectionKey:@(1),
CBConnectPeripheralOptionNotifyOnNotificationKey: @(1)
}];
}
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
peripheral.delegate = self;
//发现设备的服务
[peripheral discoverServices:@[[CBUUID UUIDWithString:ServiceUUID]]];
}
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSLog(@"连接外部设备失败 error = %@", error);
}
#pragma mark - CBPeripheralDelegate
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
if (error) {
NSLog(@"发现服务失败 error = %@", error);
return;
}
NSArray<CBService *> *services = peripheral.services;
for (CBService *service in services) {
NSLog(@"service = %@", service);
if ([service.UUID isEqual:[CBUUID UUIDWithString:ServiceUUID]]) {
NSLog(@"找到所需服务");
//从服务中查找特征
[peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:CharacteristicUUID], [CBUUID UUIDWithString:WriteCharacteristicUUID], [CBUUID UUIDWithString:NotifyCharacteristicUUID]] forService:service];
}
}
}
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
if (error) {
NSLog(@"查找特征失败 error = %@", error);
return;
}
//判断查找到的特征类型
for (CBCharacteristic *characteristic in service.characteristics) {
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:CharacteristicUUID]]) {//查找到读特征
//读取特征的值
[peripheral readValueForCharacteristic:characteristic];
} else if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:WriteCharacteristicUUID]]) {//查找到写特征
[peripheral writeValue:[@"我是主机,请从机们放下武器,双手抱头,投降吧!" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
} else if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:NotifyCharacteristicUUID]]) {//查找到写特征
NSLog(@"查找到了订阅特征值");
//订阅特征
[peripheral setNotifyValue:YES forCharacteristic:characteristic];
}
}
}
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
if (error) {
NSLog(@"读取特征值失败 error = %@", error);
return;
}
NSData *data = characteristic.value;
NSString *dataString = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"characteristic = %@ dataString = %@", characteristic, dataString);
}
/**
查看=写特征的结果
*/
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
if (error) {
NSLog(@"写特征失败 error = %@", error);
return;
}
NSLog(@"写特征成功 characteristic = %@", characteristic);
}
@end
//
// DeviceVC.m
// 01-蓝牙通信
//
// Created by laimin on 2018/3/1.
// Copyright © 2018年 laimin. All rights reserved.
//
#import "DeviceVC.h"
#import <CoreBluetooth/CoreBluetooth.h>
#import "CoreBluetooth.h"
#import "MoreVC.h"
@interface DeviceVC ()<CBPeripheralManagerDelegate>
@property (weak, nonatomic) IBOutlet UILabel *showLabel;
@property (strong, nonatomic) CBPeripheralManager *peripheralManager;
//订阅特征
@property (strong, nonatomic) CBMutableCharacteristic *notifyCharacteristic;
//订阅的主机
@property (strong, nonatomic) CBCentral *subscribeCentral;
@end
@implementation DeviceVC
- (IBAction)pushAction:(UIButton *)sender {
MoreVC *vc = [[MoreVC alloc]init];
WEAK_SELF
// __weak typeof(self) weakSelf = self;
vc.moreBlock = ^(NSString *moreStr) {
// __strong typeof(self) strongSelf = weakSelf;
STRONG_SELF
strongSelf.showLabel.text = moreStr;
};
[self.navigationController pushViewController:vc animated:YES];
}
- (IBAction)broadcast:(id)sender
{
self.peripheralManager = [[CBPeripheralManager alloc]initWithDelegate:self queue:dispatch_get_global_queue(0, 0)];
}
#pragma mark - 代理方法
#pragma mark - CBPeripheralManagerDelegate
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral
{
/**
typedef NS_ENUM(NSInteger, CBManagerState) {
CBManagerStateUnknown = 0,
CBManagerStateResetting,
CBManagerStateUnsupported,
CBManagerStateUnauthorized,
CBManagerStatePoweredOff,
CBManagerStatePoweredOn,
} NS_ENUM_AVAILABLE(10_13, 10_0);
*/
switch (peripheral.state) {
case CBManagerStatePoweredOn:
{
NSLog(@"蓝牙设备打开");
//准备数据
[self preparaDataForBroadca];
}
break;
case CBManagerStatePoweredOff:
{
NSLog(@"蓝牙设备未打开");
}
break;
case CBManagerStateUnsupported:{
NSLog(@"不支持蓝牙");
}
break;
default:
break;
}
}
/**
准备广播的数据
*/
- (void)preparaDataForBroadca
{
//=================== 添加服务 ===================
//在终端使用 uuidgen 生成随机的唯一 UUID
CBUUID *serviceUUID = [CBUUID UUIDWithString:ServiceUUID];
CBMutableService *service = [[CBMutableService alloc]initWithType:serviceUUID primary:YES];
//服务添加特征
//=================== 添加读特征 ===================
CBUUID *characteristicUUID = [CBUUID UUIDWithString:CharacteristicUUID];
NSData *data = [@"你发现我了?我是一个蓝牙设备" dataUsingEncoding:NSUTF8StringEncoding];
CBMutableCharacteristic *characteristic = [[CBMutableCharacteristic alloc] initWithType:characteristicUUID properties:CBCharacteristicPropertyRead value:data permissions:CBAttributePermissionsReadable];
//=================== 添加写特征 ===================
CBUUID *writeCharacteristicUUID = [CBUUID UUIDWithString:WriteCharacteristicUUID];
CBMutableCharacteristic *writeCharacteristic = [[CBMutableCharacteristic alloc]initWithType:writeCharacteristicUUID properties:CBCharacteristicPropertyWrite value:nil permissions:CBAttributePermissionsWriteable];
//=================== 添加订阅特征 ===================
CBUUID *notifyUUID = [CBUUID UUIDWithString:NotifyCharacteristicUUID];
_notifyCharacteristic = [[CBMutableCharacteristic alloc]initWithType:notifyUUID properties:CBCharacteristicPropertyNotify value:nil permissions:CBAttributePermissionsReadable];
service.characteristics = @[characteristic, writeCharacteristic, _notifyCharacteristic];
[self.peripheralManager addService:service];
}
- (void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error
{
if (errno) {
NSLog(@"添加服务失败 %@", error);
return;
}
//开始广播
/**
advertisementData
An optional dictionary containing the data you want to advertise. The possible keys of an advertisementData dictionary are detailed in CBCentralManagerDelegate. That said, only two of the keys are supported for peripheral manager objects: CBAdvertisementDataLocalNameKey and CBAdvertisementDataServiceUUIDsKey.
SDKs iOS 6.0+, macOS 10.9+, tvOS 9.0+, watchOS 4.0+
Declared In Core Bluetooth
More Method Reference
*/
CBUUID *serviceUUID = [CBUUID UUIDWithString:ServiceUUID];
NSDictionary *parameters = @{
CBAdvertisementDataLocalNameKey: @"iPhoneX",
CBAdvertisementDataServiceUUIDsKey: @[serviceUUID]
};
[peripheral startAdvertising:parameters];
}
- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(NSError *)error
{
if (error) {
NSLog(@"广播出错 %@", error);
return;
}
NSLog(@"正在广播......");
}
/**
接收到主机的写特征
*/
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray<CBATTRequest *> *)requests
{
for (CBATTRequest *request in requests) {
NSLog(@"request.dataString = %@", [[NSString alloc]initWithData:request.value encoding:NSUTF8StringEncoding]);
}
}
/**
有人订阅
*/
- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic
{
NSLog(@"有人订阅了特征");
self.subscribeCentral = central;
}
/**
修改订阅特征的值
*/
static int subscribeValue = 0;
- (IBAction)changeNotifyValue:(id)sender {
NSLog(@"正在修改订阅特征值");
[self.peripheralManager updateValue:[[NSString stringWithFormat:@"%d", subscribeValue] dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:_notifyCharacteristic onSubscribedCentrals:@[_subscribeCentral]];
subscribeValue++;
}
@end