iOS之蓝牙打印机

最近竞品公司出了一个接入蓝牙打印机的功能,作为竞争对手公司肯定不能少所以就给我分了任务,搞定蓝牙打印机

首先介绍一个公司的蓝牙打印功能设想,因为公司已经具备了wife打印机的打印功能而且非常完善,于是就在想是不是可以吧蓝牙当一个wife去使用这样工作量能少N倍啊,想到这里那就很简单了找资料开始搞

.首先你得先能和你玩具-蓝牙打印机连接上并且确定蓝牙打印机并且能给蓝牙打印机透传数据,这里科普一下蓝牙协议这个玩意蓝牙协议分为蓝牙2.0和蓝牙4.0;

首先你得清楚一点支持蓝牙2.0协议的设备和蓝牙4.0的区别,那就是蓝牙2.0的设备只能手动去建立蓝牙连接 而4.0设备却可以被简单的程序扫描到并且建立连接,为什么2.0设备没有被抛弃呢,这样能确保你的蓝牙设备非常安全的比如苹果的很多蓝牙设备都是2.0的

1.蓝牙2.0

iOS开发中蓝牙2.0协议使用ExternalAccessory这个基础库 由于2.0协议的特殊所以你使用遵循2.0协议的蓝牙设备的时候需要得知该设备蓝牙协议名称

只有在这里加了这个蓝牙协议名称你才能找到你的设备

具体视线代码如下,不建议直接复制 因为个人写的有残缺  但是主要的功能都已经实现

.h中代码如下

#import#import@interface ExternalAccessoryManager : NSObject

//会话渠道

@property (nonatomic,strong) EASession *session;

//代表打印机

@property (nonatomic,strong) EAAccessory *accessory;

//蓝牙设备列

@property (nonatomic,strong) NSMutableArray *deviceArr;

/**

蓝牙2.0协议管理单例

@return self

*/

+ (instancetype)shareExternalAccessoryManager;

//得到比索隆2.0蓝牙外设

- (NSArray *)getConnectBuleToolthDevice;

//打印

- (void)printMsgData:(NSData *)data;

@end

.m文件代码如下

#import "ExternalAccessoryManager.h"static ExternalAccessoryManager * g_ExternalAccessoryManager = nil;@interface ExternalAccessoryManager (){

}

@property (nonatomic,strong) NSData *printData;

@end

@implementation ExternalAccessoryManager

+ (instancetype)shareExternalAccessoryManager{

static dispatch_once_t oneceToken;

dispatch_once(&oneceToken, ^{

g_ExternalAccessoryManager = [[self alloc] init];

});

return g_ExternalAccessoryManager;

}

- (id)init{

self = [super init];

if (self) {

self.deviceArr = [NSMutableArray array];

}

return self;

}

- (NSArray *)getConnectBuleToolthDevice{

EAAccessoryManager *accessoryManager = [EAAccessoryManager sharedAccessoryManager];

NSArray *connectedAccessories = [accessoryManager connectedAccessories];

for (EAAccessory *accessory in connectedAccessories) {

//找到比索隆打印机

if ([@"com.bixolon.protocol" isEqualToString:[accessory.protocolStrings firstObject]] == YES) {

[self.deviceArr addObject:accessory];

}

}

return connectedAccessories;

}

//打印

- (void)printMsgData:(NSData *)data{

// search our device

for (EAAccessory *accessory in self.deviceArr) {

if ([@"com.bixolon.protocol" isEqualToString:[accessory.protocolStrings firstObject]] == YES) {

//            NSMutableString *info = [[NSMutableString alloc] init];

//            // 硬件的协议字符串和硬件厂商提供的一致,这个就是我们要找的设备了!

//            // log:可以打印一下该硬件的相关资讯

//            for (NSString *proStr in accessory.protocolStrings) {

//                [info appendFormat:@"protocolString = %@\n", proStr];

//                NSLog(@"打印机协议%@",proStr);

//            }

//            [info appendFormat:@"\n"];

//            [info appendFormat:@"manufacturer = %@\n", accessory.manufacturer];

//            [info appendFormat:@"name = %@\n", accessory.name];

//            [info appendFormat:@"modelNumber = %@\n", accessory.modelNumber];

//            [info appendFormat:@"serialNumber = %@\n", accessory.serialNumber];

//            [info appendFormat:@"firmwareRevision = %@\n", accessory.firmwareRevision];

//            [info appendFormat:@"hardwareRevision = %@\n", accessory.hardwareRevision];

//有打印设备并且有打印内容

if (accessory && data.length > 0) {

self.printData = data;

self.accessory = accessory;

[self openSession];

}

}

}

}

//打开传输通道

- (BOOL)openSession {

// 根据已经连接的EAAccessory对象和这个协议(反向域名字符串)来创建EASession对象,并打开输入、输出通道

self.session = [[EASession alloc] initWithAccessory:self.accessory forProtocol:@"com.bixolon.protocol"];

if(self.session != nil) {

// open input stream  接收

self.session.inputStream.delegate = self;

[self.session.inputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];

[self.session.inputStream open];

// open output stream 传输

self.session.outputStream.delegate = self;

[self.session.outputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];

[self.session.outputStream open];

}

else {

NSLog(@"2.0设备未能创建会话");

}

return (nil != self.session);

}

//NSStreamDelegate

// delegate回调的方法

- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode {

switch (eventCode) {

//没有事件

case NSStreamEventNone:

break;

//事件打开完成

case NSStreamEventOpenCompleted:

break;

//有数据传过来

case NSStreamEventHasBytesAvailable:{

//NSLog(@"Input stream is ready");

// 接收到硬件数据了,根据指令定义对数据进行解析。

}

break;

//有可用控件(发送内容)

case NSStreamEventHasSpaceAvailable:{

//NSLog(@"Output stream is ready");

// 可以发送数据给硬件了

[self writeToDevice];

}

break;

//事件发生错误

case NSStreamEventErrorOccurred:{

}

break;

//事件结束后

case NSStreamEventEndEncountered:{

//写入数据成功后关闭通道

[self.session.outputStream close];

}

break;

default:

break;

}

}

- (void)writeToDevice{

NSString *filePath = [[NSBundle mainBundle] pathForResource:@"print_guide_airkiss"ofType:@"txt"];

self.printData = [NSData dataWithContentsOfFile:filePath];

NSInteger length = [self.printData length];

NSString *dateStr = [[NSString alloc] initWithData:self.printData encoding:NSUTF8StringEncoding];

NSLog(@"内容编码%@",dateStr);

if (length > 0) {

[self.session.outputStream write:[self.printData bytes] maxLength:length];

}

}

2.蓝牙4.0就更简单了  它使用的是CoreBluetooth我在网上找到了一个大神封装的关于打印方面的一个第三方使用很是方便 大家可以去看看这里附上大神demo的readeME  这里可以很方便快捷的找到大神的数据

# HLBluetoothDemo# 提醒有部分开发人员,加群之后,直接问设备扫描不到,服务扫描出错,特性扫描报错,怎么办?对于这类问题,要严厉批评,都是因为懒,没有用心去看官方文档或者关于CoreBluetooth的教程。

所以对于蓝牙的连接处理流程不清晰的,严重建议先看[iOS CoreBluetooth 的使用讲解](http://www.jianshu.com/p/1f479b6ab6df)

自己动手写Demo,把系统的CoreBluetooth的使用,以及蓝牙的流程搞懂了,再开始做蓝牙打印的功能。# 引言该项目中包含两个部分的工具类`HLBluetooth` 和`HLPrinter`,蓝牙操作和打印小票功能。

> 如果只是做蓝牙打印机打印小票的功能,可以看我的另一个工程[SEBLEPrinter](https://github.com/Halley-Wong/SEBLEPrinter)因为系统的蓝牙操作库是用delegate实现的,步骤比较繁多,操作很零散,需要写一堆的代理方法,特别麻烦

所以我用block方式重写了,蓝牙管理的所有代码在HLBluetooth目录中。

又因为项目中要用蓝牙控制打印机打印小票,我又把蓝牙打印机的操作封装了一下,所有代码在HLPrinter目录下。

# HLBluetooth介绍用block改写后,使用大致分为三步:* 获取蓝牙模块的状态* 扫描蓝牙外设* 连接、扫描服务、扫描特性、扫描描述。因为连接、扫描服务、扫描特性、扫描描述也是属于不同的阶段,所以在block返回时,也有阶段值返回。

~~---------------------------------------------------------------------------------------------------------~~

除了上面这些代理方法改写的block API之外,还有一些操作性方法,比如:* 读取特性值* 读取描述值* 往特性中写入数据* 往描述中写入数据* 读取信号数据* 取消蓝牙连接...以上这些方法也提供block方式和一般的调用方式。

# HLPrinter介绍蓝牙打印机模板可以打印的格式有* 单行文字格式```[printer appendText:title alignment:HLTextAlignmentCenter fontSize:HLFontSizeTitleBig];[printer appendText:str1 alignment:HLTextAlignmentCenter]; ```* 左标题右参数格式```[printer appendTitle:@"时间:" value:@"2016-04-27 10:01:50" valueOffset:150];[printer appendTitle:@"订单:" value:@"4000020160427100150" valueOffset:150];[printer appendTitle:@"总计:" value:totalStr];[printer appendTitle:@"实收:" value:@"100.00"];```* 三列数据格式```[printer appendLeftText:@"商品" middleText:@"数量" rightText:@"单价" isTitle:YES];[printer appendLeftText:dict[@"name"] middleText:dict[@"amount"] rightText:dict[@"price"] isTitle:NO];```* 分隔线```[printer appendSeperatorLine];```* 图片```[printer appendImage:[UIImage imageNamed:@"ico180"] alignment:HLTextAlignmentCenter maxWidth:300];```* 二维码```[printer appendQRCodeWithInfo:@"www.baidu.com" size:10];[printer appendQRCodeWithInfo:@"www.baidu.com"];```* 条形码```[printer appendBarCodeWithInfo:@"123456789012"];```# 效果图![1.png](https://github.com/Halley-Wong/HLBluetoothDemo/blob/master/HLBluetoothDemo/images/1.png) ![2.png](https://github.com/Halley-Wong/HLBluetoothDemo/blob/master/HLBluetoothDemo/images/2.png)![03.png](https://github.com/Halley-Wong/HLBluetoothDemo/blob/master/HLBluetoothDemo/images/03.png)![printer.png](https://github.com/Halley-Wong/HLBluetoothDemo/blob/master/HLBluetoothDemo/images/printer.png)# 使用方式关于详细的BLE使用方式和打印小票的功能,在[这里有篇文章详细说明](http://www.jianshu.com/p/90cc08d11b5a)打印机的指令有ASCII、10进制和16进制三种,我使用的是16进制。```    Byte QRSize [] = {0x1D,0x28,0x6B,0x03,0x00,0x31,0x43,size}; // 这是16进制,其中最后一个size是10进制数,转换为NSData后,会被转换为16进制。    Byte QRSize [] = {29,40,107,3,0,49,67,size}; // 这是10进制。```# 补充一些参数:>据佳博的一技术人员提供的一些参数:

汉字是24 x 24点阵,字符是12 x 24。

58mm 型打印机横向宽度384个点。(可是我用文字设置相对位置测试确实368,囧)

80mm 型打印机横向宽度576个点。

1mm 大概是8个点。

# 更新修复部分型号打印乱码,乱码后再次打印没反应的Bug。(2016-06-13,佳博 Gp-58MBIII和GP58MBIII和芯烨 XPrinter某型号测试通过) demo中也有一个使用的例子

如有使用错误或者更好的建议,请issues我。关于蓝牙打印机的问题,也欢迎大家加入群:552735579(iOS蓝牙打印机开发)。

具体4.0代码请大家自己去根据https://github.com/Halley-Wong/SEBLEPrinter 简单清晰明了 可以直接拿来使用的代码

3.以上两步做完之后就建立了你的app和蓝牙设备之间的连接,但是因为我是要打印所以那么还需要和服务器建立长连接实时接收服务器给的数据同时将数据透传给蓝牙打印机。关于打印机指令以及对应的什么模板 打印原理之类这些厂商都会给你提供文档  之前没有想到这样解决打印之前我就是通过了解这些指令用一行行的代码对其进行模板化 其中的辛酸苦辣简直不是一句话能解释通的  当然这只是一部分打印机  大多数打印机厂商提供的SDK还是很好用的  所以考验你们老板对你是不是真心的时候到了 

这里我是使用MQTT协议对服务器进行连接的,这个连接将有助与你详细了解MQTT

https://mcxiaoke.gitbooks.io/mqtt-cn/content/mqtt/01-Introduction.html

关于MQTT在iOS中的具体使用见我的另一片文章在这里就不多说了  

所以总结一下我的app就是找到打印机并建立与打印机之间的联系  同时与服务器建立长连接  那么这时候你就可以理解我的app和蓝牙设备加起来这才是一个完整的打印机  然后这个打印机与服务器连接起来了 就可以接受服务器发送的打印指令了

好了文笔不好就写到这吧

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

推荐阅读更多精彩内容