? ? ? ? 這幾天搞一個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打印機的所有功能圓滿結束.