iOS WiFi打印机Socket通信及指令的代码实现

        这几天搞一个wifi打印机,开始用他们公司给的SDK开发感觉很轻松,接口基本都写好了,只需要简单的封装就ok,结果加到我们项目里面就一直重复定义,一个GCDAsyncSocket和友盟还是微信的SDK冲突了,没办法,只能硬着头皮自己写SDK.

悲惨的生活开始,以前自己写过一个socket 的Demo ,拿出来生搬硬套搞了半天,一直连不上打印机(原因:第一次没开打印机电源,第二次没开手机wifi).先附上我socket的代码:

首先我也用的GCDAsyncSocket,这个可以Github一搜就出来了.

//成功连接服务器

```

- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port{

}

```

//连接失败

- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err{

}

//连接成功

- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{

NSString *text = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];

[_socket readDataWithTimeout:-1 tag:0];

}

//发消息

- (IBAction)sendMsg:(id)sender {

NSString *text = _textField.text;

if (text.length == 0) {

return;

}

NSMutableData *sendData = [NSMutableData data];

[sendData appendBytes:0x0a length:1];

//把内容发送给服务器

[_socket writeData:sendData withTimeout:-1 tag:0];

[self showMsg:[NSString stringWithFormat:@"发出的消息: %@",text]];

_textField.text = @"";

}

//连接

- (IBAction)connect:(id)sender {

_socket = [[GCDAsyncSocket alloc]initWithDelegate:self delegateQueue:dispatch_get_main_queue() socketQueue:dispatch_get_main_queue()];

NSError *error = nil;

[_socket connectToHost:@"192.168.1.124" onPort:9100 error:&error];

}

这些可以实现最基本的连接上打印机,IP地址,端口号,代理什么的搞好就OK了.但是想想可能还会有冲突,果断去网上趴了一点别人的socket连接来看.代码如下:

-(instancetype)init {

if (self = [super init]) {

self.asyncSocket = [[AsyncSocket alloc] initWithDelegate:self];

[self.asyncSocket setRunLoopModes:@[NSRunLoopCommonModes]];

}

return self;

}

//连接打印机

-(void)socketConnectToPrint:(NSString *)host port:(UInt16)port timeout:(NSTimeInterval)timeout {

NSError *error = nil;

[self.asyncSocket connectToHost:host onPort:port withTimeout:timeout error:&error];

}

//检查连接状态

-(BOOL)socketIsConnect

{

BOOL isConn = [self.asyncSocket isConnected];

if (isConn) {

NSLog(@"host=%@\nport=%hu\nlocalHost=%@\nlocalPort=%hu",self.asyncSocket.connectedHost,self.asyncSocket.connectedPort,self.asyncSocket.localHost,self.asyncSocket.localPort);

}

return isConn;

}

//发送数据

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

[self.asyncSocket writeData:data withTimeout:-1 tag:0];

}

//手动断开连接

- (void)socketDisconnectSocket {

[self.asyncSocket disconnect];

}

#pragma mark - Delegate

- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port {

if (_blockCheckData) {

_blockPrintData();

}

//    [sock disconnectAfterWriting];

}

- (void)onSocketDidDisconnect:(AsyncSocket *)sock {

if (_blockCheckData) {

_blockCheckData();

}

}

//

- (BOOL)onSocketWillConnect:(AsyncSocket *)sock {

return YES;

}

- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {

NSLog(@"读取完成");

}

- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag {

NSLog(@"写入完成");

}

- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err {

NSLog(@"即将断开");

}

看了看别人的socket发现还是很美好的,果断还是使用了别人的代码,哈哈!

然后就要开始搞指令了,他们公司给了我一份开发文档,我一开始是一点都看不懂,慢慢摸索之后终于敢自己动手写,先来一段代码:

//55.打印条形码

- (void)printBarcode:(kBarcodeType)type barcode:(NSString *)barcode{

unsigned char typeData[] = {29,107,type,(UInt8)barcode.length};

[self addBytesCommand:typeData Length:4];

//PS:这里的这个length也是一个需要注意的地方,很容易改了上面忘记改下面.

NSMutableData* data = [NSMutableData data];

int idx;

for (idx = 0; idx < barcode.length; idx ++) {

NSRange range = NSMakeRange(idx, 1);

NSString* hexStr = [barcode substringWithRange:range];

NSScanner* scanner = [NSScanner scannerWithString:hexStr];

unsigned int intValue;

[scanner scanHexInt:&intValue];

intValue += 48;

[data appendBytes:&intValue length:1];

}

[self.sendData appendData:data];

}

用socket和打印机通信必须是用data,也就是所有数据都要转成byte,语法也是C语言的语法.用的相当头痛.

这个是把打印条形码的方法封装了出来,也是一波三折,根据开发文档要求,前两个字节是给定的,第三个是条形码类型,一会16进制,一会10进制给我搞懵逼了,最后干脆全部用十进制(开发文档上的数字真的很难理解什么类型,有可能10进制,有可能要转成ASCLL码),然后要遍历字符串把每一个字符转成data类型,也是煞费苦心.先把字符转成int型,然后开发文档要求ASCLL码,在+48.现在知道了感觉什么都很简单,其实当时各种问题各种错.

其实所有的指令封装都大同小异,基本都是这种思路.

这次的任务首先对socket的认识更加的深入了,然后NSScanner是以前根本不知道的类也学到了点,各种编码的转换关系也理的比较清楚了.对于wifi打印机我想已经难不倒我了.

最后对所有的进行封装,一个写了三个管理类,一个socketManager 一个PrintManager 一个ReceiptManager 提供给别人的接口其中就是ReceiptManager,在ReceiptManager里面写了很多方法以供调用:

- (instancetype)initWithHost:(NSString *)host port:(UInt16)port timeout:(NSTimeInterval)timeout {

if (self = [super init])

{

[self.asynaSocket socketConnectToPrint:host port:port timeout:timeout];

}

return self;

}

- (void)connectWithHost:(NSString *)host port:(UInt16)port timeout:(NSTimeInterval)timeout {

[self.asynaSocket socketConnectToPrint:host port:port timeout:timeout];

}

- (MMSocketManager *)asynaSocket {

if (!_asynaSocket) {

_asynaSocket = [[MMSocketManager alloc] init];

}

return _asynaSocket;

}

- (MMPrinterManager *)printerManager {

if (!_printerManager) {

_printerManager = [[MMPrinterManager alloc] init];

}

return _printerManager;

}

//基础设置

- (void)basicSetting {

[self.printerManager printInitialize];

[self.printerManager printSetStanderModel];

[self.printerManager printDotDistanceW:DotSpace h:DotSpace];

//    [self.printerManager printLeftMargin:5.0];

[self.printerManager printDefaultLineSpace];

//    [self.printerManager printAreaWidth:70];

[self.printerManager printSelectFont:standardFont];

}

//清空缓存数据

- (void)clearData {

self.printerManager.sendData.length = 0;

}

//单行文本输入(不及时打印)距离0.125mm为单位

- (void)writeData_text:(NSString *)text leftSpace:(NSInteger)space{

[_printerManager printAbsolutePosition:space];

[_printerManager printAddText:text];

}

//设置字号

- (void)setTextFont:(kCharScale)scale{

[_printerManager printCharSize:scale];

}

//打印进纸 换行输入

- (void)printAndGotoNextLine{

[_printerManager printAndGotoNextLine];

[_asynaSocket socketWriteData:[self.printerManager sendData]];

[self clearData];

}

//写入标题

- (void)writeData_title:(NSString *)title Scale:(kCharScale)scale Type:(kAlignmentType)type {

[_printerManager printCharSize:scale];

[_printerManager printAlignmentType:type];

[_printerManager printAddText:title];

[_printerManager printAndGotoNextLine];

}

//写入多行文字

- (void)writeData_items:(NSArray *)items {

[self.printerManager printCharSize:scale_1];

[_printerManager printAlignmentType:LeftAlignment];

for (NSString *item in items) {

[_printerManager printAddText:item];

[_printerManager printAndGotoNextLine];

}

}

//打印图片

- (void)writeData_image:(UIImage *)image alignment:(kAlignmentType)alignment maxWidth:(CGFloat)maxWidth {

[self.printerManager printAlignmentType:alignment];

//    UIImage *inImage = image;

CGFloat width = image.size.width;

if (width > maxWidth) {

CGFloat height = image.size.height;

CGFloat maxHeight = maxWidth * height / width;

image = [self createCurrentImage:image width:maxWidth height:maxHeight];

}

[self.printerManager printBitmapModel:image];

[self.printerManager printAndGotoNextLine];

}

// 缩放图片

- (UIImage *)createCurrentImage:(UIImage *)inImage width:(CGFloat)width height:(CGFloat)height {

CGSize size = CGSizeMake(width, height);

UIGraphicsBeginImageContext(size);

[inImage drawInRect:CGRectMake(0, 0, width, height)];

UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

return resultImage;

}

//func createCurrentImage(inImage:UIImage, width:CGFloat, height:CGFloat)->UIImage{

//    //        let w = CGFloat(width)

//    //        let h = CGFloat(height)

//    let size = CGSizeMake(width, height)

//    UIGraphicsBeginImageContext(size)

//    inImage.drawInRect(CGRectMake(0, 0, width, height))

//    let image = UIGraphicsGetImageFromCurrentImageContext()

//    UIGraphicsEndImageContext()

//    return image

//}

//条目,菜单,有间隔,如:

//  炸鸡排    2      12.50      25.00

- (void)writeData_content:(NSArray *)items {

[self.printerManager printCharSize:scale_1];

[_printerManager printAlignmentType:LeftAlignment];

for (NSDictionary *dict in items) {

[self writeData_spaceItem:dict];

}

}

- (void)writeData_spaceItem:(NSDictionary *)item {

[_printerManager printAddText:[item objectForKey:@"key01"]];

[_printerManager printAbsolutePosition:250];

[_printerManager printAddText:[item objectForKey:@"key02"]];

[_printerManager printAbsolutePosition:400];

[_printerManager printAddText:[item objectForKey:@"key03"]];

[_printerManager printAbsolutePosition:500];

[_printerManager printAddText:[item objectForKey:@"key04"]];

[_printerManager printAndGotoNextLine];

}

//打印分割线

- (void)writeData_line {

[self.printerManager printAlignmentType:MiddleAlignment];

[self.printerManager printAddText:@"------------------------------------------"];

[self.printerManager printAndGotoNextLine];

}

//打开钱箱

- (void)openCashDrawer {

[self.printerManager printOpenCashDrawer];

}

//打印小票并切纸

- (void)printReceipt {

[self.printerManager printCutPaper:feedPaperHalfCut Num:12];

[_asynaSocket socketWriteData:[self.printerManager sendData]];

[self clearData];

}

//打印条形码

- (void)printBarcode:(kBarcodeType)type barcode:(NSString *)barcode width:(UInt8)width height:(UInt8)height{

[self.printerManager setBarcodeWidth:width];

[self.printerManager setBarcodeHeight:height];

[self.printerManager printBarcode:type barcode:barcode];

}

其中我本来认为打印图片可以打印二维码和条形码,结果我用CIFile生成的二维码和条形码,只有二维码能够被打印出来,想了很多办法至今没有解决,只能按照指令自己写打印条形码,如果谁知道是什么回事,谢谢你与我分享.

代码完工,提交,汇报老大,在几番测试之下,新的bug又出来了.老大说他只点了三次打印却打印了6行数据.

第一反应是难道哪里的打印方法写重复了?排查一遍并没有,然后自己拿起打印机继续调试,发现打印2次会有3行数据,规律出来了,叠加了,把数据装进了data,执行打印之后data发送给了打印机,但是并没有清楚掉,补上clear方法之后,终于,wifi打印机的所有功能圆满结束.

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

推荐阅读更多精彩内容