这几天搞一个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打印机的所有功能圆满结束.