美文网首页iOS 硬件
iOS WiFi打印机Socket通信及指令的代码实现

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

作者: 心在前方 | 来源:发表于2017-01-20 17:21 被阅读219次

            这几天搞一个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通信及指令的代码实现

      本文链接:https://www.haomeiwen.com/subject/titgbttx.html