这是我参与11月更文挑战的第13天,活动详情查看:​​2021最后一次更文挑战​​。

粉丝福利:搜索​​#小程序:iOS逆向 ​​​,关注​​公众号:iOS逆向​​领取福利【掘金小册5折优惠码】

目前仅剩一张,有效日期至 11月30日 23:59。

前言

应用场景:打印商品价格标签、打印交易小票

特色功能: 实现自动连接最近使用的打印机、统一处理蓝牙状态

解决的问题:人民币¥符号乱码的问题

效果图: 价格标签打印(品名支持多行显示)

iOS小技能:蓝牙打印商品价签和交易小票的模版_iOS

票据打印(自动实现%ns 自动补齐空格的功能)

iOS小技能:蓝牙打印商品价签和交易小票的模版_4s_02

iOS小技能:蓝牙打印商品价签和交易小票的模版_ios_03

​ private ​

切换佳博打印机的打印模式方法:​​按住FEED键 和Pause键,再打开开机键开机,​

I 、获取标签打印命令

NSData *)price_tscCommand{

TscCommand *command = [[TscCommand alloc]init];
[command addSize:40 :60];
[command addGapWithM:2 withN:0];
[command addReference:0 :0];
[command addTear:@"ON"];
[command addQueryPrinterStatus:ON];
[command addCls];

CGFloat marg = 10;
CGFloat topY = 5;

[command addTextwithX:200 withY:0+topY withFont:@"TSS24.BF2" withRotation:0 withXscal:1 withYscal:1 withText:@"商品名称"];// 字的高度30
// 间距10
//0、Barcode
[command addTextwithX:30 withY:30+marg+topY withFont:@"TSS24.BF2" withRotation:0 withXscal:1 withYscal:1 withText:@"2017.01.31"];
[command add1DBarcode:30 :70 :@"CODE128" :100 :1 :0 :2 :2 :@"1kn23456984"];

[command addTextwithX:47 withY:200+marg+topY withFont:@"TSS24.BF2"
withRotation:0 withXscal:1 withYscal:1 withText:@"6666.81/件"];// ¥
//1、¥
UIImage *image = [CtrlViewController imageFromText:@"¥" withFont:[UIFont systemFontOfSize:15] withColor:[UIColor blackColor]];


[command addBitmapwithX:30 withY:200+marg withMode:0 withWidth:15 withImage:image];


[command addPrint:1 :1];// M 行 n :列 打印两份

return

1.1 解决人民币¥符号乱码的问题

/**
将文字转为UIImage,用于打印¥,来避免乱码
*/
+(UIImage *)imageFromText:(NSString*)text withFont: (UIFont *)font withColor:(UIColor *)color
{

CGSize size = [text sizeWithFont:font constrainedToSize:CGSizeMake(MAXFLOAT, MAXFLOAT)];
CGRect rect = CGRectMake(0, 0, size.width, size.height);
UIGraphicsBeginImageContextWithOptions(size,YES,0.0);
NSMutableParagraphStyle* paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
paragraphStyle.lineBreakMode = NSLineBreakByClipping;
NSDictionary*attribute = @{NSFontAttributeName:font,
NSParagraphStyleAttributeName:paragraphStyle,
NSForegroundColorAttributeName:color
};
//1、针对打印机的特性:字体为黑色,因此设置背景颜色为b白色
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextFillRect(context, CGRectMake(0, 0, 200, 200));
//2、将文字绘画进上下文
[text drawWithRect:rect options:NSStringDrawingUsesLineFragmentOrigin attributes:attribute context:nil];
//3、从上下文获取图片
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return

II、获取票据打印命令

2.1 门店票据:使用字符串格式化进行排版

#pragma
+ (void) setupStoreListcommand:(EscCommand*)command name:(NSString*)name count:(char*)count price:(char*)price sum:(char*)sum {

// [count ]

[command addSetJustification:0];


[command addText:[NSString stringWithFormat:@"%@\n",name]];


[command addSetJustification:2];

/**
%3s, 格式输出字符串,右对齐,超出3个长度的,就全部输出;
%7.2s, 输出字符串占7个位置,右对齐,左补空格,输出2个字符;
%-5.3s: 输出3个字符,占位5个位置,左对齐右补空格。
%.4s, 仅输出4个字符,占位4个位置,右对齐;
*/

[command addText:[NSString stringWithFormat:@"%5s %8s %8s\n",count,price,sum]];
}

2.2 避免乱码问题,推荐使用%n@ 进行格式化,而非%ns

NSString *text = [NSString stringWithFormat:@"%8@\t%8@\n",column1str,column2str];
  • 不推荐的格式化方式
NSString *text = [NSString stringWithFormat:@"%8s\t%8s\n",column1str.UTF8String,column2str.UTF8String];

2.3 自动实现%ns 自动补齐空格的功能

#pragma
+ (void) setupStoreListcommand:(EscCommand*)command column1Name:(NSString*)column1Name column1Value:(NSString*)column1Value column2Name:(NSString*)column2Name column2Value:(NSString*)column2Value{


NSString *column1str = [NSString stringWithFormat:@"%@:%@",column1Name,column1Value];

NSString *column2str = [NSString stringWithFormat:@"%@:%@",column2Name,column2Value];




[command addSetJustification:0];
/**
%3s, 格式输出字符串,右对齐,超出3个长度的,就全部输出;
%7.2s, 输出字符串占7个位置,右对齐,左补空格,输出2个字符;
%-5.3s: 输出3个字符,占位5个位置,左对齐右补空格。
%.4s, 仅输出4个字符,占位4个位置,右对齐;
*/
//因为char是无编码的 存的是纯数据
// kCFStringEncodingGBK_95
//NSString 中保存的是UTF8编码的数据,%s输出的是ASCII吗的数据,UTF8编码的中文字符用ASCII码方式输出,必然是乱码。

// char tmp = [column1str characterAtIndex:0];

NSString *text = [NSString stringWithFormat:@"%8@\t%8@\n",[self addRightComplementspaces:column1str count:8],[self addRightComplementspaces:column2str count:8]];
// NSString *text = [NSString stringWithFormat:@"%8s\t%8s\n",column1str.UTF8String,column2str.UTF8String];
// String.format("%-4s%-8s%-10s%-4s","","1243KG", "850000.00","850000.00");
[command addText:text];
}

// 自己创建一个自动补齐空格的方式

+ (NSString*)addComplementspaces:(NSString*)str count:(NSInteger)count{

if (str.length>=count) {
return str;
}

NSMutableString *tmp = [NSMutableString new];
NSInteger tmpcount = count -str.length;
for (int i =0; i< tmpcount; i++) {
[tmp appendString:@" "];// 往左边补齐空格
}
[tmp appendString:str];// 往左边补齐空格
return tmp;
}


// 自己创建一个自动往右补齐空格的方式

+ (NSString*)addRightComplementspaces:(NSString*)str count:(NSInteger)count{

if (str.length>=count) {
return str;
}

NSMutableString *tmp = [[NSMutableString alloc]initWithString:str];
NSInteger tmpcount = count -str.length;
for (int i =0; i< tmpcount; i++) {
[tmp appendString:@" "];// 往右边补齐空格
}
return

III、 实现自动连接最近使用的打印机

- (void)connectLastPrint{
__weak __typeof__(self) weakSelf = self;

[KNConnecterManagerTool listenBluetoothpoweredState:^(CBPeripheral * _Nullable peripheral) {


return [weakSelf setupConnectPeripheral:peripheral];

}];

}

-(void) setupConnectPeripheral:(CBPeripheral *_Nullable)peripheral{
if ([peripheral.identifier.UUIDString isEqualToString:KBLUETOOTH]) {
NSLog(@"相同则开始连接此蓝牙");
[Manager connectPeripheral:peripheral options:nil timeout:50 connectBlack:^(ConnectState state) {
if (state == CONNECT_STATE_CONNECTED) {
[Manager stopScan];
// 修改状态
[self setupCONNECT_STATE_CONNECTED:peripheral];

}else if (state == CONNECT_STATE_TIMEOUT || state == CONNECT_STATE_FAILT || state == CONNECT_STATE_DISCONNECT){

if (state == CONNECT_STATE_DISCONNECT) {
[self setupCONNECT_STATE_DISCONNECT];
return ;
}

[SVProgressHUD showInfoWithStatus:@"请尝试重启蓝牙printer"];
[self connectLastPrint];
}

}

];
}
else{
NSLog(@"未找到该设备");
}
}

/**
* 断开连接
*/
- (IBAction)disconnectAction:(id)sender {
[Manager close];
}

#pragma

- (void) setupCONNECT_STATE_CONNECTED:(CBPeripheral*)peripheral{
self.connState.text = [NSString stringWithFormat:@"%@%@",@"连接状态:已连接",peripheral.name];
[SVProgressHUD showInfoWithStatus:@"连接成功"];
// [SVProgressHUD show
[self.navigationController popViewControllerAnimated:YES];

//1、保持连接成功之后的信息
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
[user setValue:peripheral.identifier.UUIDString forKey:@"blueTooth"];
[user setValue:peripheral.name forKey:@"blueName"];
[user synchronize];
}

#define
#define KBLUETOOTH [kUserDefaults valueForKey:@"blueTooth"]//商户连接过的打印

IV、常见问题

4.1 iOS蓝牙状态的处理【蓝牙关闭及未授权的处理】

4.2 CBCentralManagerStateUnsupported

如果使用timeout 时间太长容易导致这个问题,修改为时间小些就可以,例如2。

nil timeout:50

V、 see also

更多内容请关注 ​​#小程序:iOS逆​​​向,只为你呈现有价值的信息,专注于移动端技术研究领域;更多服务和咨询请关注​​#公众号:iOS逆向​​。

iOS小技能:蓝牙打印商品价签和交易小票的模版_ios_04