蓝牙功能

偶尔善良 提交于 2020-03-03 15:29:54

蓝牙功能

 

作为蓝牙中心,连接外设

一般性的步骤是先扫描设备,然后根据蓝牙设备的名称等信息找到需要连接的设备,进行连接

然后获取设备的服务,可以订阅对应的服务,可以对设备进行写入

 

 

//
//  ViewController.m
//  BlueTooth
//
//  Created by JackXu on 15/6/9.
//  Copyright (c) 2015年 BFMobile. All rights reserved.
//

#import "ViewController.h"
#define MyDeviceName @"HMSoft"
@interface ViewController ()

@property (nonatomic, strong) CBCentralManager *centralMgr;
@property (nonatomic, strong) CBPeripheral *discoveredPeripheral;
@property (nonatomic, strong) CBCharacteristic *writeCharacteristic;

@property (nonatomic,strong) CBCharacteristic *testCharacteristic;
@property (weak, nonatomic) IBOutlet UITextField *editText;
@property (weak, nonatomic) IBOutlet UILabel *resultText;

@property (nonatomic,strong) CBPeripheral *smartWatchPeripheral;
@property (nonatomic,strong) NSMutableArray *discoveredPerpheralArray;



@property (nonatomic,strong) CBService *testService;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.centralMgr = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}

//检查App的设备BLE是否可用 (ensure that Bluetooth low energy is supported and available to use on the central device)
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
    switch (central.state)
    {
        case CBCentralManagerStatePoweredOn:
            //discover what peripheral devices are available for your app to connect to
            //第一个参数为CBUUID的数组,需要搜索特点服务的蓝牙设备,只要每搜索到一个符合条件的蓝牙设备都会调用didDiscoverPeripheral代理方法
            [self.centralMgr scanForPeripheralsWithServices:nil options:nil];
            break;
        default:
            NSLog(@"Central Manager did change state");
            break;
    }
}

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
    NSLog(@"peripheral == %@ rssi == %@",peripheral,RSSI);
    //找到需要的蓝牙设备,停止搜素,保存数据
    if([peripheral.name isEqualToString:MyDeviceName]){
        _discoveredPeripheral = peripheral;
        [_centralMgr connectPeripheral:peripheral options:nil];
    }
    
    for ( CBPeripheral *savedPeripheral in self.discoveredPerpheralArray) {
        if (![[savedPeripheral.identifier UUIDString] isEqualToString:[peripheral.identifier UUIDString]]) {
            
//            self.discoveredPerpheralArray 
            
            
        }
    }
    
    NSString *peripheralName = peripheral.name;
    NSRange wannaFitLocation = [peripheralName rangeOfString:@"WannaFit"];
    if (wannaFitLocation.location != NSNotFound){
        self.smartWatchPeripheral = peripheral;
        [_centralMgr connectPeripheral:peripheral options:nil];
    
    }
    
    
}

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

    NSLog(@"didDisconnectPeripheral %s",__FUNCTION__);
}

//连接成功
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
    
    NSLog(@"didConnectPeripheral %s",__FUNCTION__);
    //Before you begin interacting with the peripheral, you should set the peripheral’s delegate to ensure that it receives the appropriate callbacks(设置代理)
    [_discoveredPeripheral setDelegate:self];
    //discover all of the services that a peripheral offers,搜索服务,回调didDiscoverServices
    [_discoveredPeripheral discoverServices:nil];
    
    [self.smartWatchPeripheral setDelegate:self];
    
    [self.smartWatchPeripheral discoverServices:nil];
}

//连接失败,就会得到回调:
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
    //此时连接发生错误
    NSLog(@"connected periphheral failed");
}

//获取服务后的回调
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
    if (error)
    {
        NSLog(@"didDiscoverServices : %@", [error localizedDescription]);
        return;
    }
    
    for (CBService *s in peripheral.services)
    {
        NSLog(@"Service found with UUID : %@", s.UUID);
        //Discovering all of the characteristics of a service,回调didDiscoverCharacteristicsForService
        [s.peripheral discoverCharacteristics:nil forService:s];
    }
}

//获取特征后的回调
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
    if (error)
    {
        NSLog(@"didDiscoverCharacteristicsForService error : %@", [error localizedDescription]);
        return;
    }
    
    NSLog(@"service == %@",service);
    
    for (CBCharacteristic *c in service.characteristics)
    {
        NSLog(@"c.properties:%lu",(unsigned long)c.properties) ;
        //Subscribing to a Characteristic’s Value 订阅
        
        NSLog(@"characteristic == %@",c);
        [peripheral setNotifyValue:YES forCharacteristic:c];
        // read the characteristic’s value,回调didUpdateValueForCharacteristic
        [peripheral readValueForCharacteristic:c];
        _writeCharacteristic = c;
    }
    
    
    
    

}

//订阅的特征值有新的数据时回调
- (void)peripheral:(CBPeripheral *)peripheral
didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic
             error:(NSError *)error {
    if (error) {
        NSLog(@"Error changing notification state: %@",
              [error localizedDescription]);
    }
    
    [peripheral readValueForCharacteristic:characteristic];

}

- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
    
    NSLog(@"characteristic value == %@",characteristic.value);
    
    if (error)
    {
        NSLog(@"didUpdateValueForCharacteristic error : %@", error.localizedDescription);
        return;
    }
    
    NSData *data = characteristic.value;
    _resultText.text = [[ NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"characteristic properties == %lu value == %@ ",(unsigned long)characteristic.properties,characteristic.value);
    
//    NSLog(@"hex string == %@",[self convertDataToHexStr:data]);
//    
//
    
     

    
    
}



- (NSMutableArray *)discoveredPerpheralArray{
    if (!_discoveredPerpheralArray) {
        _discoveredPerpheralArray = [NSMutableArray array];
    }
    return _discoveredPerpheralArray;

}

#pragma mark 写数据
-(void)writeChar:(NSData *)data
{
    //回调didWriteValueForCharacteristic
    [_discoveredPeripheral writeValue:data forCharacteristic:_writeCharacteristic type:CBCharacteristicWriteWithoutResponse];
    
    
    NSData *data2 = [self test2Data];
    
    NSLog(@"data2 == %@",data2);
    
    for (CBService *service in self.smartWatchPeripheral.services) {
        
        
        for (CBCharacteristic *characteristic in service.characteristics) {
            
            
            [self.smartWatchPeripheral writeValue:data2  forCharacteristic:characteristic type:CBCharacteristicWriteWithoutResponse];
            
            [self.smartWatchPeripheral writeValue:data2 forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
            
        }
    }
   
    
}


//搜索到Characteristic的Descriptors
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    
    //打印出Characteristic和他的Descriptors
    NSLog(@"characteristic uuid:%@",characteristic.UUID);
    for (CBDescriptor *d in characteristic.descriptors) {
        NSLog(@"Descriptor uuid:%@",d.UUID);
    }
    
}
//获取到Descriptors的值
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForDescriptor:(CBDescriptor *)descriptor error:(NSError *)error{
    //打印出DescriptorsUUID 和value
    //这个descriptor都是对于characteristic的描述,一般都是字符串,所以这里我们转换成字符串去解析
    NSLog(@"characteristic uuid:%@  value:%@",[NSString stringWithFormat:@"%@",descriptor.UUID],descriptor.value);
}




#pragma mark 写数据后回调
- (void)peripheral:(CBPeripheral *)peripheral
didWriteValueForCharacteristic:(CBCharacteristic *)characteristic
             error:(NSError *)error {
    if (error) {
        NSLog(@"Error writing characteristic value: %@",
              [error localizedDescription]);
        return;
    }
    NSLog(@"写入%@成功",characteristic);
}

#pragma mark 发送按钮点击事件
- (IBAction)sendClick:(id)sender {
    // 字符串转Data
    NSData *data =[_editText.text dataUsingEncoding:NSUTF8StringEncoding];
    [self writeChar:data];
}


- (NSString *)convertDataToHexStr:(NSData *)data {
    if (!data || [data length] == 0) {
        return @"";
    }
    NSMutableString *string = [[NSMutableString alloc] initWithCapacity:[data length]];
    
    [data enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) {
        unsigned char *dataBytes = (unsigned char*)bytes;
        for (NSInteger i = 0; i < byteRange.length; i++) {
            NSString *hexStr = [NSString stringWithFormat:@"%x", (dataBytes[i]) & 0xff];
            if ([hexStr length] == 2) {
                [string appendString:hexStr];
            } else {
                [string appendFormat:@"0%@", hexStr];
            }
        }
    }];
    
    return string;
}

- (NSData *)convertHexStrToData:(NSString *)str {
    if (!str || [str length] == 0) {
        return nil;
    }
    
    NSMutableData *hexData = [[NSMutableData alloc] initWithCapacity:8];
    NSRange range;
    if ([str length] % 2 == 0) {
        range = NSMakeRange(0, 2);
    } else {
        range = NSMakeRange(0, 1);
    }
    for (NSInteger i = range.location; i < [str length]; i += 2) {
        unsigned int anInt;
        NSString *hexCharStr = [str substringWithRange:range];
        NSScanner *scanner = [[NSScanner alloc] initWithString:hexCharStr];
        
        [scanner scanHexInt:&anInt];
        NSData *entity = [[NSData alloc] initWithBytes:&anInt length:1];
        [hexData appendData:entity];
        
        range.location += range.length;
        range.length = 2;
    }
    
    return hexData;
}

- (NSData *)test1Data{

    Byte bytes[20] = {0x89,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9A};
    
    NSData *data2 =  [NSData dataWithBytes:bytes length:20];
    return data2;

}
- (NSData *)test2Data{
    
    Byte bytes[20] = {0xA5,0x11,0x00,0x00,0x02,0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC2};
    
    NSData *data2 =  [NSData dataWithBytes:bytes length:20];
    return data2;
    
}




- (NSData *)setWatchTime{

    Byte bytes[10] = {0x08,0x14,0x0e,0x0a,0x1f,0x0f,0x38,0x1e,0x01,0x00};
    Byte resultByte = 0x00;
    
    for (int i = 0; i<9; i++) {
        
        resultByte += bytes[i];
    }
    NSLog(@"result bye == %x",resultByte);
    resultByte = resultByte & 0xff;
    NSLog(@"result bye == %x",resultByte);
    bytes[9] = resultByte;
    
    
    
    NSData *data2 =  [NSData dataWithBytes:bytes length:10];
    
    NSLog(@"data2 == %@",data2);
    
    return data2;

}

- (NSData *)getWatchInfo{

    Byte bytes[10] = {0xF6,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00};
    Byte resultByte = 0x00;
    
    for (int i = 0; i<9; i++) {
        
        resultByte += bytes[i];
    }
    NSLog(@"result bye == %x",resultByte);
    resultByte = resultByte & 0xff;
    NSLog(@"result bye == %x",resultByte);
    bytes[9] = resultByte;
    
    
    
    NSData *data2 =  [NSData dataWithBytes:bytes length:10];
    
    NSLog(@"data2 == %@",data2);
    
    return data2;
}

- (NSData *)findTheWatch{
    
    Byte bytes[10] = {0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00};
    Byte resultByte = 0x00;
    
    for (int i = 0; i<9; i++) {
        
        resultByte += bytes[i];
    }
    
    resultByte = resultByte & 0xff;
    bytes[9] = resultByte;
    
    
    
    NSData *data2 =  [NSData dataWithBytes:bytes length:10];
    
    NSLog(@"data2 == %@",data2);

    return data2;
}
@end

 

 

作为蓝牙设备


#import "BePeripheralViewController.h"



static NSString *const ServiceUUID1 =  @"FFF0";
static NSString *const notiyCharacteristicUUID =  @"FFF1";
static NSString *const readwriteCharacteristicUUID =  @"FFF2";
static NSString *const ServiceUUID2 =  @"FFE0";
static NSString *const readCharacteristicUUID =  @"FFE1";
static NSString *const localTimeUUID = @"Local Time Information";
  
static NSString * const LocalNameKey =  @"WannaFit-T10D-5F29";

@implementation BePeripheralViewController{
    CBPeripheralManager *peripheralManager;
    //定时器
    NSTimer *timer;
    //添加成功的service数量
    int serviceNum;
    UILabel *info;
   
}
- (void)viewDidLoad {
    [super viewDidLoad];
    /*
     和CBCentralManager类似,蓝牙设备打开需要一定时间,打开成功后会进入委托方法
     - (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral;
     模拟器永远也不会得CBPeripheralManagerStatePoweredOn状态
     */
    peripheralManager = [[CBPeripheralManager alloc]initWithDelegate:self queue:nil];
   
    //页面样式
    [self.view setBackgroundColor:[UIColor whiteColor]];
    info = [[UILabel alloc]initWithFrame:self.view.frame];
    [info setText:@"正在打开设备"];
    [info setTextAlignment:NSTextAlignmentCenter];
    [self.view addSubview:info];
    
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    [peripheralManager stopAdvertising];
}



//配置bluetooch的
-(void)setUp{
    //characteristics字段描述
    CBUUID *CBUUIDCharacteristicUserDescriptionStringUUID = [CBUUID UUIDWithString:CBUUIDCharacteristicUserDescriptionString];
    
    /*
     可以通知的Characteristic
     properties:CBCharacteristicPropertyNotify 
     permissions CBAttributePermissionsReadable
     */
    CBMutableCharacteristic *notiyCharacteristic = [[CBMutableCharacteristic alloc]initWithType:[CBUUID UUIDWithString:notiyCharacteristicUUID] properties:CBCharacteristicPropertyNotify value:nil permissions:CBAttributePermissionsReadable];

    /*
     可读写的characteristics
     properties:CBCharacteristicPropertyWrite | CBCharacteristicPropertyRead
     permissions CBAttributePermissionsReadable | CBAttributePermissionsWriteable
     */
    CBMutableCharacteristic *readwriteCharacteristic = [[CBMutableCharacteristic alloc]initWithType:[CBUUID UUIDWithString:readwriteCharacteristicUUID] properties:CBCharacteristicPropertyWrite | CBCharacteristicPropertyRead value:nil permissions:CBAttributePermissionsReadable | CBAttributePermissionsWriteable];
    //设置description
    CBMutableDescriptor *readwriteCharacteristicDescription1 = [[CBMutableDescriptor alloc]initWithType: CBUUIDCharacteristicUserDescriptionStringUUID value:@"name"];
    [readwriteCharacteristic setDescriptors:@[readwriteCharacteristicDescription1]];
    

    /*
     只读的Characteristic
     properties:CBCharacteristicPropertyRead
     permissions CBAttributePermissionsReadable
     */
    CBMutableCharacteristic *readCharacteristic = [[CBMutableCharacteristic alloc]initWithType:[CBUUID UUIDWithString:readCharacteristicUUID] properties:CBCharacteristicPropertyRead value:nil permissions:CBAttributePermissionsReadable];

    
    //service1初始化并加入两个characteristics
    CBMutableService *service1 = [[CBMutableService alloc]initWithType:[CBUUID UUIDWithString:ServiceUUID1] primary:YES];
    NSLog(@"%@",service1.UUID);
    
    [service1 setCharacteristics:@[notiyCharacteristic,readwriteCharacteristic]];
    
    //service2初始化并加入一个characteristics
    CBMutableService *service2 = [[CBMutableService alloc]initWithType:[CBUUID UUIDWithString:ServiceUUID2] primary:YES];
    [service2 setCharacteristics:@[readCharacteristic]];
    
    //添加后就会调用代理的- (void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error
    [peripheralManager addService:service1];
    [peripheralManager addService:service2];
}




#pragma  mark -- CBPeripheralManagerDelegate

//peripheralManager状态改变
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral{
    switch (peripheral.state) {
            //在这里判断蓝牙设别的状态  当开启了则可调用  setUp方法(自定义)
        case CBPeripheralManagerStatePoweredOn:
            NSLog(@"powered on");
            [info setText:[NSString stringWithFormat:@"设备名%@已经打开,可以使用center进行连接",LocalNameKey]];
            [self setUp];
            break;
        case CBPeripheralManagerStatePoweredOff:
            NSLog(@"powered off");
            [info setText:@"powered off"];
            break;
            
        default:
            break;
    }
}

//perihpheral添加了service
- (void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error{
    if (error == nil) {
        serviceNum++;
    }

    //因为我们添加了2个服务,所以想两次都添加完成后才去发送广播
    if (serviceNum==2) {
        //添加服务后可以在此向外界发出通告 调用完这个方法后会调用代理的
        //(void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(NSError *)error
        [peripheralManager startAdvertising:@{
                                              CBAdvertisementDataServiceUUIDsKey : @[[CBUUID UUIDWithString:ServiceUUID1],[CBUUID UUIDWithString:ServiceUUID2]],
                                              CBAdvertisementDataLocalNameKey : LocalNameKey
                                             }
         ];
        
    }
    
}

//peripheral开始发送advertising
- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(NSError *)error{
    NSLog(@"in peripheralManagerDidStartAdvertisiong");
}

//订阅characteristics
-(void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic{
    NSLog(@"订阅了 %@的数据",characteristic.UUID);
    //每秒执行一次给主设备发送一个当前时间的秒数
    timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(sendData:) userInfo:characteristic  repeats:YES];
}

//取消订阅characteristics
-(void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic{
    NSLog(@"取消订阅 %@的数据",characteristic.UUID);
    //取消回应
    [timer invalidate];
}

//发送数据,发送当前时间的秒数
-(BOOL)sendData:(NSTimer *)t {
    CBMutableCharacteristic *characteristic = t.userInfo;
    NSDateFormatter *dft = [[NSDateFormatter alloc]init];
    [dft setDateFormat:@"ss"];
    NSLog(@"%@",[dft stringFromDate:[NSDate date]]);
    
    //执行回应Central通知数据
    return  [peripheralManager updateValue:[[dft stringFromDate:[NSDate date]] dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:(CBMutableCharacteristic *)characteristic onSubscribedCentrals:nil];
    
}


//读characteristics请求
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveReadRequest:(CBATTRequest *)request{
    NSLog(@"didReceiveReadRequest");
    NSLog(@"request == %@ request.value == %@",request,request.value);
    //判断是否有读数据的权限
    if (request.characteristic.properties & CBCharacteristicPropertyRead) {
        NSData *data = request.characteristic.value;
        [request setValue:data];
        //对请求作出成功响应
        [peripheralManager respondToRequest:request withResult:CBATTErrorSuccess];
    }else{
        [peripheralManager respondToRequest:request withResult:CBATTErrorWriteNotPermitted];
    }
}


//写characteristics请求
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests{
    NSLog(@"didReceiveWriteRequests");
    CBATTRequest *request = requests[0];
    
    //判断是否有写数据的权限
    if (request.characteristic.properties & CBCharacteristicPropertyWrite) {
        //需要转换成CBMutableCharacteristic对象才能进行写值
        CBMutableCharacteristic *c =(CBMutableCharacteristic *)request.characteristic;
        c.value = request.value;
        [peripheralManager respondToRequest:request withResult:CBATTErrorSuccess];
    }else{
        [peripheralManager respondToRequest:request withResult:CBATTErrorWriteNotPermitted];
    }
    
    
}

//
- (void)peripheralManagerIsReadyToUpdateSubscribers:(CBPeripheralManager *)peripheral{
    NSLog(@"peripheralManagerIsReadyToUpdateSubscribers");
    
}


@end

 

更进一步的蓝牙功能

https://my.oschina.net/u/2340880/blog/644432

https://github.com/ZYHshao/BlueGame

 

参考资料

iOS简易蓝牙对战五子棋游戏设计思路之一——核心蓝牙通讯类的设计

https://my.oschina.net/u/2340880/blog/644432

 

ios蓝牙开发(二)ios连接外设的代码实现

http://liuyanwei.jumppo.com/2015/08/14/ios-BLE-2.html

 

iOS-BLE蓝牙开发持续更新

http://www.jianshu.com/p/84b5b834b942

 

刘彦玮的技术博客中文章对应的demo http://liuyanwei.jumppo.com http://liuyanwei.jumppo.com

https://github.com/coolnameismy/demo

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!