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

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

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

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

二、蓝牙连接的主要步骤

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

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

 3、连接外围设备;

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

 5、获得服务的特征;

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

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

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

1、导入苹果系统蓝牙框架<CoreBluetooth/CoreBluetooth.h>

2、遵循两个蓝牙框架相关的协议<CBCentralManagerDelegate,CBPeripheralDelegate>

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<NSString *, id> *)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}];

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,133评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,682评论 3 390
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,784评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,508评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,603评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,607评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,604评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,359评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,805评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,121评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,280评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,959评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,588评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,206评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,442评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,193评论 2 367
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,144评论 2 352

推荐阅读更多精彩内容