iOS中蓝牙与打印机连接使用

公司最近帮一家物流公司做一个员工使用的APP,需要用到蓝牙去连接设备打印运单信息,下面记录一些在对接蓝牙打印时候遇到的问题,也总结一下其他技术文章中的一些知识点供大家参考,网上也有别人做好的第三方BabyBluetooth,这个第三方也可以在我们找的几种设备上正常打印,同学们可以去看看这个怎么使用,有问题的地方希望大家提出来。

一、关于蓝牙开发的一些重要的理论概念:

1、服务(services):蓝牙外设对外广播的时候一定会有一个服务,有些时候也可以是有多个服务,服务下面包含一些特性,服务可以理解成一个模块的窗口;
2、特征(characteristic):特征存在于服务下面的,一个服务下面可以有多个特征,特征可以理解成具体实现功能的窗口,一般的特性都会有value,也就是特征值,是特征和外界交互的最小单位;
3、UUID:蓝牙上的唯一标示符,为了区分不同服务和特征,就用UUID来表示。

二、蓝牙连接的主要步骤

 1、创建一个CBCentralManager实例来进行蓝牙管理;

 2、使用CBCentralManager对象搜索扫描外围设备;

 3、连接外围设备;

 4、获得外围设备的服务;

 5、获得服务的特征;

 6、从外围设备读取数据;

 7、给外围设备发送(写入)数据。

三、蓝牙连接和数据读写的具体步骤

1、导入苹果系统蓝牙框架

2、遵循两个蓝牙框架相关的协议

3、新建两个实例属性,一个特征属性
@property (nonatomic, strong) CBCentralManager *centralManager; //中心管理者
@property (nonatomic, strong) CBPeripheral *peripheral; //连接到的外设
@property (nonatomic, strong) CBCharacteristic *characteristic; //特征

4、实例化CBCentralManager对象进行蓝牙管理
self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()]; //创建实例进行蓝牙管理

在实例化该对象之后,就会触发下面这个必须实现的代理方法,否则在实例化之后会闪退,在该方法里面也可以获取到蓝牙的状态,可以在此处提示用户去打开蓝牙

- (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:
            ;
    }
}

客户的需求里面有下次进入该界面自动连接设备的功能,开始做的时候是实例化之后马上开始连接之前的设备,但是总是连接不上。实际上等这个回调函数调用之后就可以连接了,包括去搜索也是一样,如果大家操作相关功能之后没有效果,可能是这个函数还没调用的原因,怎么连接之前的设备一会会讲到。

5.扫描蓝牙设备(根据SERVICE_UUID来扫描外设,如果不设置则扫描所有蓝牙设备)

[central scanForPeripheralsWithServices:nil options:nil];

执行扫描动作之后,如果扫描到外设了,就会自动回调下面的协议方法

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
     /*这边可以打印设备的名称,我们可以先将所有搜索到的设备都存储起来显示到UI上,根据选择来连接
      搜索到的设备会重复,所以需要过滤
      peripheral.name
     */
      if(![self.deviceLists containsObject: peripheral]){
          [self.deviceLists addObject: peripheral];
      }
}

6.连接外围设备

选择设备进行连接
[central connectPeripheral:peripheral options:nil];

连接外围设备,中心管理者连接外设成功,如果连接成功就会回调这个协议方法

- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
    /连接成功之后,可以进行服务和特性的发现。 停止中心管理设备的扫描动作,要不然在你和已经连接好的外设进行数据沟通时,如果又有一个外设进行广播且符合你的连接条件,那么你的iOS设备也会去连接这个设备(因为iOS BLE4.0是支持一对多连接的),导致数据的混乱。
    //停止扫描
    [self.centralManager stopScan];
    // 设置外设的代理
    peripheral.delegate = self;
    // 根据UUID来寻找服务
    //[peripheral discoverServices:@[[CBUUID UUIDWithString:SERVICE_UUID]]];
    //外设发现服务,传nil代表不过滤,一次性读出外设的所有服务
    [peripheral discoverServices:nil];
}

/** 连接失败的回调 */

- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
    NSLog(@"%s, line = %d, %@=连接失败", __FUNCTION__, __LINE__, peripheral.name);
}

/** 断开连接 */

- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error {
    NSLog(@"%s, line = %d, %@=断开连接", __FUNCTION__, __LINE__, peripheral.name);
    // 断开连接可以设置重新连接
    [central connectPeripheral:peripheral options:nil];
}

7、获取外围设备服务和特征
peripheral调用discoverServices方法之后,在下面的回调函数中发现服务

/** 发现服务 */
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
    // 遍历出外设中所有的服务
    for (CBService *service in peripheral.services) {
         //查找服务中所有的特征
         [peripheral discoverCharacteristics:nil forService:service];
    }
}

peripheral调用查询对应服务下面的特征之后,会在下面的回调函数中返回

/** 发现特征 */
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
    if (error==nil) {
        for (CBCharacteristic *characteristic in service.characteristics){
            if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"49535343-8841-43F4-A8D4-ECBE34729BB3"]]){
                 self. characteristic = characteristic;
            }else if([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"49535343-1E4D-4BD9-BA61-23C647249616"]]){
                 [peripheral setNotifyValue:TRUE forCharacteristic:characteristic];
            }
            self.peripheral = peripheral;
        }
    }
}

到现在打印所需要的所有内容都获取到了,就可以往打印机发送数据了

8、从外围设备读取数据
凡是从蓝牙传过来的数据都要经过这个回调,简单的说这个方法就是你拿数据的唯一方法,你可以判断是否 从外围设备读数据

/** 接收到数据回调 */
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
    NSData *data = characteristic.value; //获取到的数据
    NSLog(@"bbb-----%@----",data); //打印出来应该是<01a5>这样的数据,可以通过下面的方式去判断一些自己想要的逻辑
    Byte * resultByte = (Byte *)[data bytes];
    if(data.length>=1){
        if(resultByte[0]==16){ //16代表前两位的值
            NSLog(@"---打印机打开---");
        }else if (resultByte[0]==1){ //01
            NSLog(@"----打印机缺纸-----");
        }
    }
    //下面的处理方式我没处理过,大家可以试试
    //self.textFild.text = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}

9、向蓝牙设备写数据

    Byte byte[] = {0x1B,0x68};//打印机状态指令
    NSData *data = [[NSData alloc] initWithBytes:byte length:3];
    if(self.peripheral&&self.characteristic) {
        NSLog(@"发送获取状态指令");
        [peripheral writeValue:data forCharacteristic: characteristic type:CBCharacteristicWriteWithResponse];
    }

这里说明怎么连接上一次或者之前连接的设备,可以保存之前设备的标识,进入App之后通过这个标识实例化服务来进行链接;通过这种方式不行的同学可以试试保存这个标识,下次进入的时候后台扫描设备,判断那个设备的标识和存储的一样,连接表示一样的那个...

//这个是需要保存的标识
NSString *connectId = peripheral.identifier.UUIDString;
//进入App之后获取存储的标识进行初始化服务
NSUUID *identifier = [[NSUUID UUID]initWithUUIDString: connectId];
CBPeripheral *peri = [[self.centralManager retrievePeripheralsWithIdentifiers:@[identifier]] firstObject];
if (peri == nil) {
    return;
}
if(peri.state==CBPeripheralStateConnected){
    [self alertMs:@"设备已被连接"];
    return;
}
[centralManager connectPeripheral:peri options:@{CBConnectPeripheralOptionNotifyOnConnectionKey : @YES}];

关于蓝牙打印的知识暂时分享到这里,下面贴出参考的文章
蓝牙的连接和数据的读写

你可能感兴趣的:(iOS中蓝牙与打印机连接使用)