ios Bluetooth 蓝牙

要理解iOS CoreBluetooth,有两个很重要的概念:Central 和 Periperal Devices

这两个概念可以用传统的模式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];
    }
}



你可能感兴趣的:(ios,server,蓝牙,BlueTooth,peripheral)