美文网首页
iOS蓝牙编程CoreBluetooth

iOS蓝牙编程CoreBluetooth

作者: 风继续吹0 | 来源:发表于2016-09-08 15:34 被阅读182次

    iOS的蓝牙框架是支持蓝牙4.0协议的。
    理解iOS CoreBluetooth两个很重要的概念,Central 和 Periperal Devices
    这两个概念可以用传统的模式client-server来理解,central意思是中心,其作用类似server,periperal就是外设,一般携带有数据,我们需要去其中获取数据,下图是苹果官网的例子,peripheral是心跳仪,按期作用,我们去这个外设中取心跳数据,则心跳仪的作用就类似server了,我们的手机去心跳仪中获取数据,类似client。


    Peripheral如何让central知道它的存在呢? peripheral.比如上图的心跳仪,通过不断广播自己的存在,并且在广播过程中附带广告包(advertising packet),这样你就发现了这个设备,并且获取到它提供的服务。


    介绍完这些概念,我们来看看实际代码应该如何填写.这里对于我的蓝牙小票机来编写的,因为我要对蓝牙小票机器进行写操作,手机是搜索peripharal的,所以手机为central,小票机为peripharal。

    1. 首先导入这个框架

    2. 该框架有主要有几个类值得我们注意,CBCentralManager,也就是我们之前提到的Central,可以用来发现外设的。
      #import

       @interface ViewController () 
      
       @property (nonatomic, retain) CBCentralManager *centralManager;
      
       @end
      
       @implementation ViewController
      
       - (void)viewDidLoad {
           [super viewDidLoad];
           // Do any additional setup after loading the view, typically from a nib.
           self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
       }
      

    上面代码这里我们创建了一个CBCentralManager,用来发现外设,当创建成功,CBCentralManager会回调代理说创建成功了,如下面代码

        /*
         Invoked whenever the central manager's state is updated.
         */
        - (void)centralManagerDidUpdateState:(CBCentralManager *)central
        {
        NSString * state = nil;
    
        switch ([central state])
        {
            case CBCentralManagerStateUnsupported:
                state = @"The platform/hardware doesn't support Bluetooth Low Energy.";
                break;
            case CBCentralManagerStateUnauthorized:
                state = @"The app is not authorized to use Bluetooth Low Energy.";
                break;
            case CBCentralManagerStatePoweredOff:
                state = @"Bluetooth is currently powered off.";
                break;
            case CBCentralManagerStatePoweredOn:
                state = @"work";
                break;
            case CBCentralManagerStateUnknown:
            default:
                ;
        }
    
        NSLog(@"Central manager state: %@", state);
        }
    

    上面的代码如果这个时候如果是CBCentralManagerStatePoweredOn,代表蓝牙可用。一定要在该方法回调后去开启扫描外设,否则无反应.

    1. 现在可以连接扫描外设了

       - (IBAction)scan:(id)sender {
       [self.centralManager scanForPeripheralsWithServices:nil options:nil];
       }
      

    上面代码我创建了一个按钮来扫描,就不上对应的xib图片了.
    这个方法如果传入的事nil,代表扫描所有外设。
    - (IBAction)scan:(id)sender {
    [self.centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:@"FFE0"]] options:nil];
    }
    如果你只想搜索有提供对应的服务号的外设(去peripharal 的advertising packet里匹配服务号,传入一个数组进入,对象为CBUUID,也就是Service的唯一标识符。一般我们搜索过一个nil的就会知道我们要的服务好是什么样子的了,之后编程就可以直接使用这个已知的服务好。除非你的蓝牙设备的厂家更改服务号,不过几乎不可能。
    - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
    {
    static int i = 0;
    NSString *str = [NSString stringWithFormat:@"Did discover peripheral. peripheral: %@ rssi: %@, UUID: %@ advertisementData: %@ ", peripheral, RSSI, peripheral.UUID, advertisementData];
    NSLog(@"%@",str);
    [self.discoverdPeriparals addObject:peripheral];
    }
    当你发现了一个设备,该方法会回调。peripheral代表你发现的设备,advertisementData时广告数据,rssi代表着信号强度.



    从广播数据中可以看到一个服务UUIDs,因为广播数据有数量大小限制,数据比较少。不过目前我们只是发现了这个设备,假设该设备已经是我们感兴趣的设备,你可以通过[self.centralManager stopScan]来停止扫描,也可以继续扫描。

    1. 连接发现的外设
      - (IBAction)connect:(id)sender {
      [self.centralManager connectPeripheral: [self.discoverdPeriparals firstObject] options:nil];
      }
      假设第一个是我们需要的外设,连接它。

       /*
        Invoked whenever a connection is succesfully created with the peripheral.
        Discover available services on the peripheral
        */
       - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
       {
           NSLog(@"Did connect to peripheral: %@", peripheral);
           peripheral.delegate = self;
           [central stopScan];
           [peripheral discoverServices:nil];
       }
      

    当连接成功后调用该方法。这个时候我们设置该peripheral的代理我们自己,让peripheral给我们返回所有服务。
    [peripheral discoverServices:@[[CBUUID UUIDWithString:@"FFE0"]]];
    这个方法也是传入nil返回所有服务,如果是传入特定的服务id,只返回该服务 这里我们传入nil来返回所有服务
    - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
    {
    if (error)
    {
    NSLog(@"Discovered services for %@ with error: %@", peripheral.name, [error localizedDescription]);
    return;
    }

            for (CBService *service in peripheral.services)
            {
                NSLog(@"Service found with UUID: %@", service.UUID);
                if ([service.UUID isEqual:[CBUUID UUIDWithString:@"FFE0"]])
                {
                     [peripheral discoverCharacteristics:nil forService:service];
                }   
            }
        }
    

    这里看到返回了两个服务,因为需要FFE0,所以让该服务返回对应的characteristics.
    [peripheral discoverCharacteristics:nil forService:service];

        - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
        {
            if (error)
            {
                NSLog(@"Discovered characteristics for %@ with error: %@", service.UUID, [error localizedDescription]);
                return;
            }
            for (CBCharacteristic * characteristic in service.characteristics)
            {
                DLog(@"%@",characteristic);
                if( [characteristic.UUID isEqual:[CBUUID UUIDWithString:@"FFE1"]])
                {
                    self.p = peripheral;
                    self.c = characteristic;
    
                    //read
                    //[testPeripheral readValueForCharacteristic:characteristic];
                    NSLog(@"Found a Device Manufacturer Name Characteristic - Read manufacturer name");
                }
            }
        }
    

    上面的方法是找到FEE0服务的所有特征,这里的只有一个,也就蓝牙小票机FFE0写服务的写特征. 获取到该特征。进行写服务,具体的log就不写了
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
    NSString *RStr = @"2764";
    NSMutableString *str = [NSMutableString new];
    [str appendFormat:@"%c", 28];
    [str appendFormat:@"%c", 33];
    [str appendFormat:@"%c", 8];

            [self.p writeValue:[str dataUsingEncoding:CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000)] forCharacteristic:self.c type:CBCharacteristicWriteWithResponse];
            RStr = @"吴彦祖 你好呀!!!\n\n\n\n\n\n\n\n";
            [self.p writeValue:[RStr dataUsingEncoding:CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000)] forCharacteristic:self.c type:CBCharacteristicWriteWithResponse];
        }
    

    这里我对蓝牙小票机提供的写特征进行写服务。成功.

    补充: 如果该特征是可以读特征,你可以对该特征进行订阅。

    [peripheral setNotifyValue:YES forCharacteristic:interestingCharacteristic];
    

    该方法回调peripheral:didUpdateValueForCharacteristic:error:方法

    当你订阅成功后,如果数据有更新,则回调该方法。 你就可以去读取你想要的数据了。

    如果想要了解更多,建议查看iOS官方文档提供的CoreBluetooth programming guid。

    相关文章

      网友评论

          本文标题:iOS蓝牙编程CoreBluetooth

          本文链接:https://www.haomeiwen.com/subject/bebsettx.html