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打印机的所有功能圆满结束.

你可能感兴趣的:(iOS WiFi打印机Socket通信及指令的代码实现)