前言
最近项目中使用到了打印机,最后总算打印出自己想要打印的数据了,还算不错,做一个小结吧,希望对需要的朋友有些帮助。
打印机
我们使用的打印机是 《佳博ZH3080条码打印蓝牙标签机.....》,特殊说明一下,我使用的是标签模式(有标签模式和小票模式),而且使用标签模式的时候,如果打印机中的纸比较窄的话,每次打印,打印机都会回退纸张,这样就无法使用了,因为每次都是贴着边缘撕的纸,回退的话,纸就出不来了。必须选用宽大的纸,我使用的纸大概宽度有8CM
效果
工程设置
不设置会直接Crash
Paste_Image.png步骤
- 链接上打印机
- 组装要打印的数据
- 设置打印机参数
- 执行打印
步骤解析和源码示例
链接打印机
打印机SDK头文件.png# ConnectViewController是Dome中提供的 带有 xib的链接类,继承自 CBController。CBController 的实现文件 .m是封装到SDK中的,我们不得而知,但是这里用到继承是为了 获取CBController 的方法和全局变量,下面会解释
@interface ConnectViewController : CBController
#CBController 的代理方法,
************************************************************
#[self startScan]; 调用后会返回这个方法,在这个方法中刷新列表,而且数据都在 CBController 的中 devicesList 中返回所有搜素到的设备
- (void)updateDiscoverPeripherals {
[super updateDiscoverPeripherals];
[devicesTableView reloadData];
}
#断开一个打印机,会触发这个代理方法来通知子类,
- (void)updateMyPeripheralForDisconnect:(MyPeripheral *)myPeripheral {
}
#链接一个打印机,会触发这个代理方法来通知子类,
- (void)updateMyPeripheralForNewConnected:(MyPeripheral *)myPeripheral {
}
*************************************************************
- (void)viewDidAppear:(BOOL)animated {
[self startScan];
}
#这个方法会执行 CBController 中搜索附近打印机设备的方法,并且以代理updateDiscoverPeripherals的方法把结果放到 devicesList中
- (void)startScan {
[super startScan];
}
# 在表的 numberOfRowsInSection 方法中过滤掉未识别的设备
for (MyPeripheral *tmpPeripheral in devicesList) {
if (!tmpPeripheral.advName) {
[devicesList removeObject:tmpPeripheral];
}
}
return [devicesList count];
组装要打印的数据
#最终的效果如下
NSArray *textArray = @[@"领料单详情",
@"领料人:张笑傲",
@"2016-12-16",
@"----------------------------------",
@"商品名称 数量 单位",
@"西瓜 11 斤",
@"(领取生产日期为,\n严格核对严格核对严格核对)",
@"西瓜 11 斤",
@"(领取生产日期为,严格\n核对严格核对严格核对)",
@"西瓜 11 斤",
@"(领取生产日期为,严格核\n对严格核对严格核对)",
@"西瓜 11 斤",
@"(领取生产日期为,严格核对严格核对严格核对)",
@"西瓜 11 斤",
@"(领取生产日期为,严格核对严格核对严格核对)",
@"-----------------------------------",
@"商品种类数:5",];
#根据一个字典,组装数据
- (void)initPrintStrWith :(NSDictionary *)dataDic;
{
[printStrArray removeAllObjects];
[printStrArray addObject:@"领料单详情"];
[printStrArray addObject:[NSString stringWithFormat:@"领料人:%@",dataDic[@"cgd"][@"zdperson"]]];
[printStrArray addObject:dataDic[@"cgd"][@"lldate"]];
[printStrArray addObject:@"--------------------------------------"];
[printStrArray addObject:[self getPrintString:@"商品名称" :@"数量" tail:@"单位"]];
NSArray *listArray = dataDic[@"xqlist"];
for (int i = 0; i<listArray.count; i++) {
NSDictionary *dic = listArray[i];
NSString *name = dic[@"hpname"];
NSString *numer = [dic[@"hpnumber"] stringValue];
NSString *danwei = dic[@"dwname"];
#组成固定长度的字符串,中间填充 空格
NSString *inforStr = [self getPrintString:name :numer tail:danwei];
[printStrArray addObject:inforStr];
if ([self recursionSubStr:dic[@"hpscrq"]]) {
#递归的方法截字符串
[printStrArray addObjectsFromArray:[self recursionSubStr:[dic[@"hpscrq"] stringByReplacingOccurrencesOfString:@"#" withString:@""]]];
}
}
[printStrArray addObject:@"--------------------------------------"];
[printStrArray addObject:[NSString stringWithFormat:@"商品种类数:%lu",(unsigned long)listArray.count]];
}
#判断中英混合的的字符串长度,
#如果你的打印效果是同一种类型的文字当然可以,但如果同时包含字母,汉子,数字等,那么用length计算的长度就不准确了,因为字母,汉子的编码不同,字节数是不同的,所以要转换成Unicode编码统一的计算。**
- (int)convertToInt:(NSString*)strtemp
{
int strlength = 0;
char* p = (char*)[strtemp cStringUsingEncoding:NSUnicodeStringEncoding];
for (int i=0 ; i<[strtemp lengthOfBytesUsingEncoding:NSUnicodeStringEncoding] ;i++) {
if (*p) {
p++;
strlength++;
}
else {
p++;
}
}
return strlength;
}
#三部分数据拼成固定长度Str 中间填充空格组装成固定长度的字符串
- (NSString *)getPrintString:(NSString *)leader :(NSString *)middle tail:(NSString *)tail
{
static int TOTAL = 30;//这里是根据你的纸张宽度试验出来的一个合适的总字数
NSMutableString *printString = [NSMutableString new];
[printString appendString:leader];
int lenderLen = [self convertToInt:leader];
if (tail && middle) {
int midddleLen = [self convertToInt:middle];
int tailLen = [self convertToInt:tail];
int detal = (int)(TOTAL - lenderLen - tailLen - midddleLen)/2;
for (int i = 0; i < detal; i ++) {
[printString appendString:@" "];
}
[printString appendString:middle];
for (int i = 0; i < detal; i ++) {
[printString appendString:@" "];
}
[printString appendString:tail];
}
return printString;
}
#递归的方法分割字符串, 把比较长的字符串截成几段固定长度的字符串后放入数组中
- (NSArray *)recursionSubStr:(NSString *)origaneStr
{
NSMutableArray *strA = [[NSMutableArray alloc]initWithCapacity:0];
if (origaneStr.length<30) {
[strA addObject:origaneStr];
return strA;
}
[strA addObject:[origaneStr substringToIndex:29]];
[strA addObjectsFromArray:[self recursionSubStr:[origaneStr substringFromIndex:29]]];
return strA;
}
设置打印机参数
- (void)printAction;
{
if (printStrArray.count==0) {
return;
}
TscCommand *tscCmd = [[TscCommand alloc] init];
#设置为YES才能打印
[tscCmd setHasResponse:YES];
#设置打印纸的打印尺寸 从打印纸的右边开始计算宽度 设置的尺寸要小于实际的宽度才能在左边留白 高度为打印区域的高度 都是 mm 单位,尺寸为实际打印出的尺寸(可以用尺子测量)
[tscCmd addSize:73 :((int)(printStrArray.count+3)*3+10)];
#设置标签间隙尺寸 没什么用
[tscCmd addGapWithM:10 withN:10];
#不设置会有异常,不设置第一次打印出现很大的空白空隙
[tscCmd addReference:10
:10];
#打印速度
[tscCmd addSpeed:4];
[tscCmd addDensity:8];
#0正向 1反向(尾部的先打印出来)
[tscCmd addDirection:0];
[tscCmd addComonCommand];
[tscCmd addCls];
# x,y 值 目测是 1/100 厘米 x,从左到右依次增大,y从上到下依次增大
NSMutableArray *xArray = [[NSMutableArray alloc]initWithCapacity:0];
for (int i = 0; i<printStrArray.count; i++) {
if (i==0) {
[xArray addObject:@"200"];
}else{
[xArray addObject:@"0"];
}
}
#设置每条要打印的字符串的 x,y 值
for (int i=0; i<printStrArray.count;i++) {
[tscCmd addTextwithX:[xArray[i] intValue]
withY:(i*30)
withFont:@"TSS24.BF2"
withRotation:0
withXscal:1
withYscal:1
withText:printStrArray[i]];
}
#打印二维码
[tscCmd addQRCode:380
:(15)
:@"L"
:4
:@"A"
:0
:allDataDic[@"cgd"][@"ewmcode"]];
#不在最后打印 . 底部留白太少,撕下来时会撕不完整,打印一个 . 在底部即可达到底部留白的效果,
#而且有时候,不在最后打印 .\n 很多内容打印不出来,不知道为什么。
[tscCmd addTextwithX:20
withY:((int)(printStrArray.count)*30+5)
withFont:@"TSS24.BF2"
withRotation:0
withXscal:1
withYscal:1
withText:@".\n"];
#print 执行打印命令
[tscCmd addPrint:1 :1];
}
执行打印
//打印操作
- (void)NewRightNavItemClick
{
if([[BLKWrite Instance] isConnecting]){
[printManager initPrintStrWith:intBackDic :YES];
[printManager printAction];
}
else{
[[BLKWrite Instance] setBWiFiMode:NO];
[self.navigationController pushViewController:[[ConnectViewController alloc] initWithNibName:nil bundle:nil] animated:YES];
**************************************************************
#这里有一个值得注意的地方,如果链接了打印机,还想点击进入链接页面,展示出链接的打印机信息,需要使用下面的方法,
#即进入上次创建的哪个视图,不能新建,新建的话会遇到SDK报错Alert弹框。这里是用了单例保存了上次新建的链接视图。
// [[BLKWrite Instance] setBWiFiMode:NO];
// AppDelegate *dele = [UIApplication sharedApplication].delegate;
// [self.navigationController pushViewController:dele.mConnBLE animated:YES];
#AppDelegate中
@property (strong, nonatomic) ConnectViewController *mConnBLE;
self.mConnBLE = [[ConnectViewController alloc] initWithNibName:nil bundle:nil];
}
}
网友评论
/**
* 方法说明:查询打印机状态<ESC>!?
*询问打印机状态指令为立即响应型指令,该指令控制字符是以<ESC> (ASCII 27=0x1B, escape字符)为控制字符.!(ASCII 33=0x21),?(ASCII 63=0x3F)
*即使打印机在错误状态中仍能透过 RS-232 回传一个 byte 资料来表示打印机状态,若回传值为 0 则表示打印
*机处于正常的状态
* @return void
*/
-(void) queryPrinterStatus;
Next Steps
To resolve this issue, please revise your app to add support for Bluetooth Low Energy communication through Core Bluetooth in your app or remove the bluetooth- values from the UIBackgroundModes key.
- (void)configureDeviceInformationServiceUUID: (NSString *)UUID1 UUID2:(NSString *)UUID2;这个方法具体是做什么用的?