这两个概念可以用传统的模式client-server来理解,central意思是中心其作用类似server; periperal就是外设,一般携带有数据,我们需要去其中获取数据,下图是苹果官网的例子,peripheral是心跳仪,按期作用,我们去这个外设中取心跳数据,则心跳仪的作用就类似server了,我们的手机去心跳仪中获取数据,类似client。
在介绍代码之前我导入了以上框架
在serverViewController.m 的代码如下:
#import "serverViewController.h"
//generated by command "uuidgen" 这是我的两个蓝牙UUID
static NSString *const kServiceUUID = @"DDDD4D86-502A-4F58-B747-347B186F6812";
static NSString *const kCharacteristicUUID = @"6A6201D6-CEAA-4714-8CF2-DBF471874321";
@interface ViewController ()
//周边管理者
@property (nonatomic , strong) CBPeripheralManager *peripheralManager;
@property (nonatomic , strong) CBMutableCharacteristic *customCharacteristic;
@property (nonatomic , strong) CBMutableService *customService;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil];
}
//上面代码这里我们创建了一个CBCentralManager,用来发现外设
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - 私有函数
- (void)setupService
{
//creates the characteristic UUID
CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID];
//create the characteristic
self.customCharacteristic = [[CBMutableCharacteristic alloc] initWithType:characteristicUUID
properties:CBCharacteristicPropertyNotify
value:nil
permissions:CBAttributePermissionsReadable];
//create the service UUID
CBUUID *servieceUUID = [CBUUID UUIDWithString:kServiceUUID];
//creates the service and adds the charecteristic to it
self.customService = [[CBMutableService alloc] initWithType:servieceUUID primary:YES];
//sets the characteristics for this service
[self.customService setCharacteristics:@[self.customCharacteristic]];
//publishs the service
[self.peripheralManager addService:self.customService];
}
#pragma mark -
#pragma mark - CBPeripheralManagerDelegate
- (void)peripheralManager:(CBPeripheralManager *)peripheral willRestoreState:(NSDictionary *)dict
{
NSLog(@"%s,dict = %@",__PRETTY_FUNCTION__,dict);
}
- (void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error
{
if (error == nil) {
//starts advertising the service
[self.peripheralManager startAdvertising:@{CBAdvertisementDataLocalNameKey:@"服务门店",
CBAdvertisementDataServiceUUIDsKey:@[[CBUUID UUIDWithString:kServiceUUID]]}];
} else {
NSLog(@"%s,error = %@",__PRETTY_FUNCTION__,error);
}
}
- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic
{
NSLog(@"central=%@设备拒绝请求,%s,",central,__PRETTY_FUNCTION__);
}
- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic
{
NSLog(@"已经有central=%@设备接受了服务,我们要给它生成动态数据\n连接请求,%s,",central,__PRETTY_FUNCTION__);
NSString *messageText = [NSString stringWithFormat:@"已经有鱼儿(%@)上钩->_->\n是否投放鱼饵?",central.identifier];
[SimplifyAlertView alertWithTitle:@"发现连接者" message:messageText operationResult:^(NSInteger selectedIndex) {
if (selectedIndex == 1) {
NSLog(@"投放");
[peripheral updateValue:[@"我们推出最新的优惠活动啦" dataUsingEncoding:NSUTF8StringEncoding]
forCharacteristic:self.customCharacteristic onSubscribedCentrals:@[central]];
}
} cancelButtonTitle:@"取消" otherButtonTitles:@"投放", nil];
//通过下面函数往central发送数据
// [peripheral updateValue:<#(NSData *)#> forCharacteristic:<#(CBMutableCharacteristic *)#> onSubscribedCentrals:<#(NSArray *)#>];
}
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveReadRequest:(CBATTRequest *)request
{
NSLog(@"%s",__PRETTY_FUNCTION__);
}
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests
{
NSLog(@"%s",__PRETTY_FUNCTION__);
}
- (void)peripheralManagerIsReadyToUpdateSubscribers:(CBPeripheralManager *)peripheral
{
NSLog(@"%s",__PRETTY_FUNCTION__);
}
- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(NSError *)error
{
NSLog(@"开始广播%s,error = %@",__PRETTY_FUNCTION__,error);
}
//下面的代码如果这个时候如果是CBCentralManagerStatePoweredOn,代表蓝牙可用。一定要在该方法回调后去开启扫描外设,否则无反应.
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral
{
switch (peripheral.state) {
case CBPeripheralManagerStatePoweredOn:
{
NSLog(@"Bluetooth is currently powered on and available to use.");
[self setupService];
}
break;
case CBPeripheralManagerStatePoweredOff:
{
NSLog(@"Bluetooth is currently powered off.");
[[[UIAlertView alloc] initWithTitle:nil message:@"蓝牙已经关闭,请打开先" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil] show];
}
break;
case CBPeripheralManagerStateUnauthorized:
{
NSLog(@"The application is not authorized to use the Bluetooth Low Energy Peripheral/Server role.");
[[[UIAlertView alloc] initWithTitle:nil message:@"蓝牙已经关闭,请打开先" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil] show];
}
break;
case CBPeripheralManagerStateUnsupported:
{
NSLog(@"The platform doesn't support the Bluetooth Low Energy Peripheral/Server role.");
[[[UIAlertView alloc] initWithTitle:nil message:@"蓝牙已经关闭,请打开先" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil] show];
}
break;
case CBPeripheralManagerStateResetting:
{
NSLog(@"The connection with the system service was momentarily lost, update imminent.");
[[[UIAlertView alloc] initWithTitle:nil message:@"蓝牙已经关闭,请打开先" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil] show];
}
break;
case CBPeripheralManagerStateUnknown:
{
NSLog(@"State unknown, update imminent.");
[[[UIAlertView alloc] initWithTitle:nil message:@"蓝牙已经关闭,请打开先" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil] show];
}
break;
default:
NSLog(@"Peripheral Manager did change state");
break;
}
}
@end
在"peripheralViewController.m"文件中代码如下:
#import "peripheralViewController.h"
#import <CoreBluetooth/CoreBluetooth.h>
#import <math.h>
//generated by command "uuidgen"
static NSString *const kServiceUUID = @"DDDD4D86-502A-4F58-B747-347B186F6812";
static NSString *const kCharacteristicUUID = @"6A6201D6-CEAA-4714-8CF2-DBF471874321";
@interface ViewController () <CBCentralManagerDelegate,CBPeripheralDelegate>
@property (nonatomic , strong) CBCentralManager *centralManager;
@property (nonatomic , strong) NSMutableData *data;
@property (nonatomic , strong) CBPeripheral *peripheral;
@property (nonatomic , strong) UILabel *mainLabel;
@property (nonatomic , copy) NSString *serviceName;
@property (nonatomic , strong) NSTimer *timer;
@end
@implementation ViewController
- (NSString *)serviceName
{
if (!_serviceName || [_serviceName length] == 0) {
_serviceName = @"";
}
return _serviceName;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
self.mainLabel = [[UILabel alloc] initWithFrame:self.view.frame];
self.mainLabel.numberOfLines = 0;
self.mainLabel.textColor = [UIColor whiteColor];
self.mainLabel.font = [UIFont boldSystemFontOfSize:18.];
self.mainLabel.backgroundColor = [[UIColor greenColor] colorWithAlphaComponent:0.3];
[self.view addSubview:self.mainLabel];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark -
#pragma mark - 私有函数
- (void)readBLEServiceRSSI
{
NSLog(@"变化");
[self.peripheral readRSSI];
}
#pragma mark -
#pragma mark - CBCentralManagerDelegate
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
switch (central.state) {
case CBCentralManagerStatePoweredOn:
{
NSLog(@"可用,现在可以搜索blueServer了");
//第一个参数指定了要搜寻的服务,如果传nil,表示搜寻搜有的服务
[self.centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:kServiceUUID]]
options:@{CBCentralManagerScanOptionAllowDuplicatesKey:@YES}];
}
break;
case CBCentralManagerStatePoweredOff:
{
NSLog(@"Bluetooth is currently powered off.");
}
break;
case CBCentralManagerStateUnauthorized:
{
NSLog(@"The application is not authorized to use the Bluetooth Low Energy Central/Client role.");
}
break;
case CBCentralManagerStateUnsupported:
{
NSLog(@"The platform doesn't support the Bluetooth Low Energy Central/Client role.");
}
break;
case CBCentralManagerStateResetting:
{
NSLog(@"The connection with the system service was momentarily lost, update imminent.");
}
break;
case CBCentralManagerStateUnknown:
{
NSLog(@"State unknown, update imminent.");
}
break;
default:
break;
}
}
//一旦一个peripheral被搜寻到,这个代理方法被调用
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
NSLog(@"找到了服务:%@,信号质量:%@",advertisementData,RSSI);
self.serviceName = [advertisementData objectForKey:@"kCBAdvDataLocalName"];
[self.centralManager stopScan];
if (self.peripheral != peripheral) {
self.peripheral = peripheral;
NSLog(@"开始连接blueServer:%@",peripheral);
[self.centralManager connectPeripheral:self.peripheral options:nil];
//这个connect本身没有超时限制,所以通过下面的方法来断开连接,此处120s后断开
double delayInSeconds = 120.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[self.centralManager cancelPeripheralConnection:self.peripheral];
});
}
}
//下面的connect回调会告诉我们连接的结果
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
//因为一个peripheral可能不止提供一个service
NSLog(@"连接成功,进一步获取peripheral的service");
self.timer = [NSTimer scheduledTimerWithTimeInterval:.1 target:self selector:@selector(readBLEServiceRSSI) userInfo:nil repeats:YES];
[self.data setLength:0];
[self.peripheral setDelegate:self];
//让peripheral发现自己
[self.peripheral discoverServices:@[[CBUUID UUIDWithString:kServiceUUID]]];
}
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSLog(@"失去连接,error = %@",error);
[self.timer invalidate];
}
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSLog(@"连接失败,error = %@",error);
}
#pragma mark -
#pragma mark - CBPeripheralDelegate
- (void)peripheralDidUpdateRSSI:(CBPeripheral *)peripheral error:(NSError *)error
{
NSLog(@"%s,%@",__PRETTY_FUNCTION__,peripheral);
int rssi = abs([peripheral.RSSI intValue]);
CGFloat ci = (rssi - 49) / (10 * 4.);
self.mainLabel.text = [NSString stringWithFormat:@"发现BLT4.0热点:%@,距离:%.1fm",self.serviceName,pow(10,ci)];
}
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
if (error) {
NSLog(@"%s,error=%@",__PRETTY_FUNCTION__,error);
} else {
for (CBService *service in peripheral.services) {
NSLog(@"发现UUID=%@的服务",service.UUID);
NSLog(@"开始检测这个服务的特征码...");
if ([service.UUID isEqual:[CBUUID UUIDWithString:kServiceUUID]]) {
[self.peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:kCharacteristicUUID]] forService:service];
}
}
}
}
//如果一个特征被检测到
//现在,一旦特征值被更新,使用-setNotifyValue:forCharacteristic:监听确保peripheral:didUpdateNotificationStateForCharacteristic:error可以收到通知
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
if (error) {
NSLog(@"%s,%@",__PRETTY_FUNCTION__,error);
} else {
if ([service.UUID isEqual:[CBUUID UUIDWithString:kServiceUUID]]) {
for (CBCharacteristic *characteristic in service.characteristics) {
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:kCharacteristicUUID]]) {
[peripheral setNotifyValue:YES
forCharacteristic:characteristic];
}
}
}
}
}
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
NSLog(@"peripheral = %@,%s",peripheral,__PRETTY_FUNCTION__);
NSString *messageText = [[NSString alloc] initWithData:[characteristic value] encoding:NSUTF8StringEncoding];
if ([messageText length] != 0) {
[[[UIAlertView alloc] initWithTitle:@"收到新消息" message:messageText delegate:nil
cancelButtonTitle:@"取消" otherButtonTitles:@"看看", nil] show];
}
}
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForDescriptor:(CBDescriptor *)descriptor error:(NSError *)error
{
NSLog(@"%s",__PRETTY_FUNCTION__);
}
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
if (error) {
NSLog(@"%s,%@",__PRETTY_FUNCTION__,error);
}
if (![characteristic.UUID isEqual:[CBUUID UUIDWithString:kCharacteristicUUID]]) {
return;
}
//已经发送通知
if (characteristic.isNotifying) {
NSLog(@"Notification began on %@",characteristic);
[peripheral readValueForCharacteristic:characteristic];
} else {
//Notification has stopped
//so disconnect from the peripheral
NSLog(@"Notification stopped on %@ Disconnecting",characteristic);
[self.centralManager cancelPeripheralConnection:self.peripheral];
}
}