iOS 打印小票
2018-09-13 本文已影响44人
高乔人
#import <CoreBluetooth/CoreBluetooth.h>
#ifndef JWBluetoothBlocks_h
#define JWBluetoothBlocks_h
// 打印流程: 搜索蓝牙外设 -->连接蓝牙 -->搜索服务 -->搜索特性 -->
写入数据 -->打印成功
// 连接上打印机,需要判断扫描的阶段,如果直接进行打印会有可能导致 没有搜索到特性阶段,调用打印API是打印不成功的,所以等待特性回调之后打印 万无一失
typedef NS_ENUM(NSInteger, JWScanStage) {
JWScanStageConnection = 0, //蓝牙连接阶段
JWScanStageServices, //服务阶段
JWScanStageCharacteristics, //特性阶段 //注意 只有到达特性阶段才能进行打印
};
/**
蓝牙外设扫描结束成功之后的block
@param peripherals 蓝牙外设列表
@param rssis 蓝牙信号强度
*/
typedef void(^JWScanPerpheralsSuccess)(NSArray<CBPeripheral *>
*peripherals,NSArray<NSNumber *> *rssis);
/**
扫描失败的block
@param status 失败的枚举 CBManagerStatePoweredOn 是正常使用的
*/
typedef void(^JWScanPeripheralFailure)(CBManagerState status);
/**
连接完成的block
@param perpheral 要连接的蓝牙外设
*/
typedef void(^JWConnectPeripheralCompletion)(CBPeripheral
*perpheral, NSError *error);
/**
蓝牙断开连接
@param perpheral 蓝牙外设
@param error 错误
*/
typedef void(^JWDisconnectPeripheralBlock)(CBPeripheral *perpheral, NSError *error);
/**
打印之后回调
@param completion 是否完成打印
@param peripheral 外设
@param errorString 出错的原因
*/
typedef void(^JWPrintResultBlock)(BOOL completion, CBPeripheral *peripheral,NSString * errorString);
#endif /* JWBluetoothBlocks_h */
////////////////////////////////////////////////
#import <Foundation/Foundation.h>
#import "JWBluetoothBlocks.h"
#import "ProgressShow.h"
#import "JWPrinter.h"
@interface JWBluetoothManage : NSObject
//单例方法
+ (instancetype)sharedInstance;
@property (nonatomic, strong,readonly)CBPeripheral *connectedPerpheral; // 当前连接的外设蓝牙
/**
开始扫描蓝牙外设,block方式返回结果
@param success 扫描成功的回调
@param failure 扫描失败的回调
*/
- (void)beginScanPerpheralSuccess:(JWScanPerpheralsSuccess)success failure:(JWScanPeripheralFailure)failure;
/**
连接蓝牙外设,连接成功后会停止扫描蓝牙外设,block方式返回结果
@param peripheral 要连接的蓝牙外设
@param completion 连接成功回调(有成功 跟失败判断error是否为空就可以了)
*/
- (void)connectPeripheral:(CBPeripheral *)peripheral completion:(JWConnectPeripheralCompletion)completion;
/**
自动连接上次连接的蓝牙
//因为使用自动连接的话同样也会扫描设备 所以如果单一只是想要连接外设,用此API就可以了
@param completion 连接成功回调(有成功 跟失败判断error是否为空就可以了)
*/
- (void)autoConnectLastPeripheralCompletion:(JWConnectPeripheralCompletion)completion;
/**
需要判断JWScanStage来进行打印,如果只是连接 不需要关心,
*/
@property (nonatomic, assign) JWScanStage stage;
/**
断开连接的block
*/
@property (nonatomic, copy) JWDisconnectPeripheralBlock disConnectBlock;
/**
停止扫描设备
*/
- (void)stopScanPeripheral;
/**
取消某个设备的连接
@param peripheral 设备
*/
- (void)cancelPeripheralConnection:(CBPeripheral *)peripheral;
/**
进行打印
@param data 打印数据
@param result 结果回调
*/
- (void)sendPrintData:(NSData *)data completion:(JWPrintResultBlock)result;
@end
接下来是.m文件。
#import "JWBluetoothManage.h"
static JWBluetoothManage * manage = nil;
@interface JWBluetoothManage () <CBCentralManagerDelegate,CBPeripheralDelegate>
@property (nonatomic, strong) CBCentralManager *centralManager; // 服务设备管理器
@property (nonatomic, strong) NSMutableArray *peripherals; // 搜索到的蓝牙设备数组
@property (nonatomic, strong) NSMutableArray *rssis; // 搜索到的蓝牙设备列表信号强度数组
@property (nonatomic, strong) NSMutableArray *printeChatactersArray; // 可以打印的的特性数组
@property (nonatomic, copy) JWScanPerpheralsSuccess scanPerpheralSuccess; // 扫描设备成功的回调
@property (nonatomic, copy) JWScanPeripheralFailure scanPerpheralFailure; // 扫描设备失败的回调
@property (nonatomic, copy) JWConnectPeripheralCompletion connectCompletion; // 连接完成的回调
@property (nonatomic, copy) JWPrintResultBlock printResult; // 打印结果的回调
//此参数是为了计算打印有没有出错
@property (nonatomic, assign) BOOL autoConnect; // 是否自动连接
@property (nonatomic, assign) NSInteger writeCount; // 写入次数
@property (nonatomic, assign) NSInteger responseCount; // 返回次数
@end
@implementation JWBluetoothManage
#pragma mark - Singleton Medth
+ (instancetype)sharedInstance{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manage = [[JWBluetoothManage alloc] init];
});
return manage;
}
- (instancetype)init{
if (self = [super init]) {
[self _initBluetooth];
}
return self;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manage = [super allocWithZone:zone];
});
return manage;
}
- (void) _initBluetooth{
_centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()];
[self.peripherals removeAllObjects];
[self.rssis removeAllObjects];
[self.printeChatactersArray removeAllObjects];
_connectedPerpheral = nil;
}
#pragma mark - Bluetooth Medthod
//开始搜索
- (void)beginScanPerpheralSuccess:(JWScanPerpheralsSuccess)success failure:(JWScanPeripheralFailure)failure{
//block 赋值
_scanPerpheralSuccess = success;
_scanPerpheralFailure = failure;
if (_centralManager.state == CBManagerStatePoweredOn) {
//开启搜索
NSLog(@"开启扫描");
[_centralManager scanForPeripheralsWithServices:nil options:nil];
return;
}
//防止因为权限问题造成BUG
[self _initBluetooth];
}
#pragma mark - CBCentralManagerDelegate Medthod
//权限改变重新搜索设备
- (void)centralManagerDidUpdateState:(CBCentralManager *)central{
if (central.state != CBManagerStatePoweredOn) {
if (_scanPerpheralFailure) {
_scanPerpheralFailure(central.state);
}
}else{
[central scanForPeripheralsWithServices:nil options:nil];
}
}
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *, id> *)advertisementData RSSI:(NSNumber *)RSSI{
NSLog(@"扫描中....");
if (peripheral.name.length <= 0) {
return ;
}
if (_peripherals.count == 0) {
[_peripherals addObject:peripheral];
[_rssis addObject:RSSI];
} else {
__block BOOL isExist = NO;
//去除相同设备 UUIDString 是每个外设的唯一标识
[_peripherals enumerateObjectsUsingBlock:^(CBPeripheral * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
CBPeripheral *per = [_peripherals objectAtIndex:idx];
if ([per.identifier.UUIDString isEqualToString:peripheral.identifier.UUIDString]) {
isExist = YES;
[_peripherals replaceObjectAtIndex:idx withObject:peripheral];
[_rssis replaceObjectAtIndex:idx withObject:RSSI];
}
}];
if (!isExist) {
[_peripherals addObject:peripheral];
[_rssis addObject:RSSI];
}
}
if (_scanPerpheralSuccess) {
_scanPerpheralSuccess(_peripherals,_rssis);
}
if (_autoConnect) {
NSString * uuid = GetLastConnectionPeripheral_UUID();
if ([peripheral.identifier.UUIDString isEqualToString:uuid]) {
peripheral.delegate = self;
[_centralManager connectPeripheral:peripheral options:nil];
}
}
}
#pragma mark - 连接外设 Medthod
- (void)connectPeripheral:(CBPeripheral *)peripheral completion:(JWConnectPeripheralCompletion)completion{
_connectCompletion = completion;
if (_connectedPerpheral) {
[self cancelPeripheralConnection:_connectedPerpheral];
}
[self connectPeripheral:peripheral];
}
//连接外设设置代理
- (void)connectPeripheral:(CBPeripheral *)peripheral{
[_centralManager connectPeripheral:peripheral options:nil];
peripheral.delegate = self;
}
- (void)autoConnectLastPeripheralCompletion:(JWConnectPeripheralCompletion)completion{
_connectCompletion = completion;
_autoConnect = YES;
if (_centralManager.state == CBManagerStatePoweredOn) {
//开启搜索
NSLog(@"开启扫描");
[_centralManager scanForPeripheralsWithServices:nil options:nil];
}
}
- (void)cancelPeripheralConnection:(CBPeripheral *)peripheral{
if (!peripheral) {
return;
}
//去除次自动连接
RemoveLastConnectionPeripheral_UUID();
[_centralManager cancelPeripheralConnection:peripheral];
_connectedPerpheral = nil;
//取消连接 清楚可打印输入
[_printeChatactersArray removeAllObjects];
}
- (void)stopScanPeripheral{
[_centralManager stopScan];
}
#pragma mark - 连接外设代理 Medthod
//成功连接
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
//当前设备赋值
_connectedPerpheral = peripheral;
//存入标识符 下次自动
SetLastConnectionPeripheral_UUID(peripheral.identifier.UUIDString);
//链接成功 停止扫描
[_centralManager stopScan];
if (_connectCompletion) {
_connectCompletion(peripheral,nil);
}
_stage = JWScanStageConnection;
peripheral.delegate = self;
//发现服务 扫描服务
[peripheral discoverServices:nil];
}
//连接失败
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error{
if (_connectCompletion) {
_connectCompletion(peripheral,error);
}
_stage = JWScanStageConnection;
}
//断开连接
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error{
_connectedPerpheral = nil;
[_printeChatactersArray removeAllObjects];
if (_disConnectBlock) {
_disConnectBlock(peripheral,error);
}
_stage = JWScanStageConnection;
}
#pragma mark 蓝牙服务代理
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(nullable NSError *)error{
if (error) {
NSLog(@"发现服务出错 错误原因-%@",error.domain);
}else{
for (CBService *service in peripheral.services) {
[peripheral discoverCharacteristics:nil forService:service];
}
}
_stage = JWScanStageServices;
}
#pragma mark 蓝牙服务特性代理
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(nullable NSError *)error{
if (error) {
NSLog(@"发现特性出错 错误原因-%@",error.domain);
}else{
for (CBCharacteristic *character in service.characteristics) {
CBCharacteristicProperties properties = character.properties;
if (properties & CBCharacteristicPropertyWrite) {
NSDictionary *dict = @{@"character":character,@"type":@(CBCharacteristicWriteWithResponse)};
[_printeChatactersArray addObject:dict];
}
}
}
if (_printeChatactersArray.count > 0) {
_stage = JWScanStageCharacteristics;
}
}
#pragma mark 写入数据 跟block
// 发送数据时,需要分段的长度,部分打印机一次发送数据过长就会乱码,需要分段发送。这个长度值不同的打印机可能不一样,你需要调试设置一个合适的值(最好是偶数)
#define kLimitLength 146
- (void)sendPrintData:(NSData *)data completion:(JWPrintResultBlock)result{
if (!self.connectedPerpheral) {
if (result) {
result(NO,_connectedPerpheral,@"未连接蓝牙设备");
}
return;
}
if (self.printeChatactersArray.count == 0) {
if (result) {
result(NO,_connectedPerpheral,@"该蓝牙设备不支持写入数据");
}
return;
}
NSDictionary *dict = [_printeChatactersArray lastObject];
_writeCount = 0;
_responseCount = 0;
// 如果kLimitLength 小于等于0,则表示不用分段发送
if (kLimitLength <= 0) {
_printResult = result;
[_connectedPerpheral writeValue:data forCharacteristic:dict[@"character"] type:[dict[@"type"] integerValue]];
_writeCount ++;
return;
}
if (data.length <= kLimitLength) {
_printResult = result;
[_connectedPerpheral writeValue:data forCharacteristic:dict[@"character"] type:[dict[@"type"] integerValue]];
_writeCount ++;
} else {
//分段打印
NSInteger index = 0;
for (index = 0; index < data.length - kLimitLength; index += kLimitLength) {
NSData *subData = [data subdataWithRange:NSMakeRange(index, kLimitLength)];
[_connectedPerpheral writeValue:subData forCharacteristic:dict[@"character"] type:[dict[@"type"] integerValue]];
_writeCount++;
}
_printResult = result;
NSData *leftData = [data subdataWithRange:NSMakeRange(index, data.length - index)];
if (leftData) {
[_connectedPerpheral writeValue:leftData forCharacteristic:dict[@"character"] type:[dict[@"type"] integerValue]];
_writeCount++;
}
}
}
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error{
if (!_printResult) {
return;
}
_responseCount ++;
if (_writeCount != _responseCount) {
return;
}
if (error) {
_printResult(NO,_connectedPerpheral,@"发送失败");
} else {
_printResult(YES,_connectedPerpheral,@"已成功发送至蓝牙设备");
}
}
#pragma mark - init containers
- (NSMutableArray *)peripherals{
if (!_peripherals) {
_peripherals = @[].mutableCopy;
}
return _peripherals;
}
- (NSMutableArray *)rssis{
if (!_rssis) {
_rssis = @[].mutableCopy;
}
return _rssis;
}
-(NSMutableArray *)printeChatactersArray{
if (!_printeChatactersArray) {
_printeChatactersArray = @[].mutableCopy;
}
return _printeChatactersArray;
}
NSString * GetLastConnectionPeripheral_UUID(){
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSString *uuid = [userDefaults objectForKey:@"BluetoothPeripheral_uuid"];
return uuid;
}
void SetLastConnectionPeripheral_UUID(NSString * uuid){
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:uuid forKey:@"BluetoothPeripheral_uuid"];
[userDefaults synchronize];
}
void RemoveLastConnectionPeripheral_UUID(){
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults removeObjectForKey:@"BluetoothPeripheral_uuid"];
[userDefaults synchronize];
}
@end
控制文字对齐方式,字号,信息等。
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "UIImage+Bitmap.h"
typedef NS_ENUM(NSInteger, HLPrinterStyle) {
HLPrinterStyleDefault,
HLPrinterStyleCustom
};
/** 文字对齐方式 */
typedef NS_ENUM(NSInteger, HLTextAlignment) {
HLTextAlignmentLeft = 0x00,
HLTextAlignmentCenter = 0x01,
HLTextAlignmentRight = 0x02
};
/** 字号 */
typedef NS_ENUM(NSInteger, HLFontSize) {
HLFontSizeTitleSmalle = 0x00,
HLFontSizeTitleMiddle = 0x11,
HLFontSizeTitleBig = 0x22
};
@interface JWPrinter : NSObject
/**
添加单行标题,默认字号是小号字体
@param text 标题名称
@param alignment 标题对齐方式
*/
- (void)appendText:(NSString *)text alignment:(HLTextAlignment)alignment;
/**
添加单行标题
@param text 标题名称
@param alignment 标题对齐方式
@param fontSize 标题字号
*/
- (void)appendText:(NSString *)text alignment:(HLTextAlignment)alignment fontSize:(HLFontSize)fontSize;
/**
添加单行信息,左边名称(左对齐),右边实际值(右对齐),默认字号是小号。
@param title 名称
@param value 实际值
*/
- (void)appendTitle:(NSString *)title value:(NSString *)value;
/**
添加单行信息,左边名称(左对齐),右边实际值(右对齐)。
@param title 名称
@param value 实际值
@param fontSize 字号大小
警告:因字号和字体与iOS中字体不一致,计算出来有误差,所以建议用在价格方面
*/
- (void)appendTitle:(NSString *)title value:(NSString *)value fontSize:(HLFontSize)fontSize;
/**
设置单行信息,左标题,右实际值
@提醒 该方法的预览效果与实际效果误差较大,请以实际打印小票为准
@param title 标题
@param value 实际值
@param offset 实际值偏移量
*/
- (void)appendTitle:(NSString *)title value:(NSString *)value valueOffset:(NSInteger)offset;
/**
设置单行信息,左标题,右实际值
@提醒 该方法的预览效果与实际效果误差较大,请以实际打印小票为准
@param title 标题
@param value 实际值
@param offset 实际值偏移量
@param fontSize 字号
*/
- (void)appendTitle:(NSString *)title value:(NSString *)value valueOffset:(NSInteger)offset fontSize:(HLFontSize)fontSize;
/**
添加选购商品信息标题,一般是三列,名称、数量、单价
@param left 左标题
@param middle 中间标题
@param right 右标题
@param isTitle 是否是标题
*/
- (void)appendLeftText:(NSString *)left middleText:(NSString *)middle rightText:(NSString *)right isTitle:(BOOL)isTitle;
/**
添加图片,一般是添加二维码或者条形码
⚠️提醒:这种打印图片的方式,是自己生成图片,然后用位图打印
@param image 图片
@param alignment 图片对齐方式
@param maxWidth 图片的最大宽度,如果图片过大,会等比缩放
*/
- (void)appendImage:(UIImage *)image alignment:(HLTextAlignment)alignment maxWidth:(CGFloat)maxWidth;
/**
添加条形码图片
⚠️提醒:这种打印条形码的方式,是自己生成条形码图片,然后用位图打印图片
@param info 条形码中包含的信息,默认居中显示,最大宽度为300。如果大于300,会等比缩放。
*/
- (void)appendBarCodeWithInfo:(NSString *)info;
/**
添加条形码图片
⚠️提醒:这种打印条形码的方式,是自己生成条形码图片,然后用位图打印图片
@param info 条形码中的信息
@param alignment 图片对齐方式
@param maxWidth 图片最大宽度
*/
- (void)appendBarCodeWithInfo:(NSString *)info alignment:(HLTextAlignment)alignment maxWidth:(CGFloat)maxWidth;
/**
添加二维码
✅推荐:这种方式使用的是打印机的指令生成二维码并打印机,所以比较推荐这种方式
@param info 二维码中的信息
@param size 二维码的大小 取值范围1 <= size <= 16
*/
- (void)appendQRCodeWithInfo:(NSString *)info size:(NSInteger)size;
/**
添加二维码
✅推荐:这种方式使用的是打印机的指令生成二维码并打印机,所以比较推荐这种方式
@param info 二维码中的信息
@param size 二维码大小,取值范围 1 <= size <= 16
@param alignment 设置图片对齐方式
*/
- (void)appendQRCodeWithInfo:(NSString *)info size:(NSInteger)size alignment:(HLTextAlignment)alignment;
/**
添加二维码图片
⚠️提醒:这种打印条二维码的方式,是自己生成二维码图片,然后用位图打印图片
@param info 二维码中的信息
*/
- (void)appendQRCodeWithInfo:(NSString *)info;
/**
添加二维码图片
⚠️提醒:这种打印条二维码的方式,是自己生成二维码图片,然后用位图打印图片
@param info 二维码中的信息
@param centerImage 二维码中间的图片
@param alignment 对齐方式
@param maxWidth 二维码的最大宽度
*/
- (void)appendQRCodeWithInfo:(NSString *)info centerImage:(UIImage *)centerImage alignment:(HLTextAlignment)alignment maxWidth:(CGFloat )maxWidth;
/**
* 添加一条分割线,like this:---------------------------
*/
- (void)appendSeperatorLine;
/**
添加底部信息
@param footerInfo 不填默认为 谢谢惠顾,欢迎下次光临!
*/
- (void)appendFooter:(NSString *)footerInfo;
/**
换行符
*/
- (void)appendNewLine;
/**
获取最终的data
@return 最终的data
*/
- (NSData *)getFinalData;
@end
JWPrinter.m文件如下:
#import "JWPrinter.h"
#define kMargin 20
#define kPadding 2
#define kWidth 320
@interface JWPrinter ()
/** 将要打印的排版后的数据 */
@property (strong, nonatomic) NSMutableData *printerData;
@end
@implementation JWPrinter
- (instancetype)init
{
self = [super init];
if (self) {
[self defaultSetting];
}
return self;
}
- (void)defaultSetting
{
_printerData = [[NSMutableData alloc] init];
// 1.初始化打印机
Byte initBytes[] = {0x1B,0x40};
[_printerData appendBytes:initBytes length:sizeof(initBytes)];
// 2.设置行间距为1/6英寸,约34个点
// 另一种设置行间距的方法看这个 @link{-setLineSpace:}
Byte lineSpace[] = {0x1B,0x32};
[_printerData appendBytes:lineSpace length:sizeof(lineSpace)];
// 3.设置字体:标准0x00,压缩0x01;
Byte fontBytes[] = {0x1B,0x4D,0x00};
[_printerData appendBytes:fontBytes length:sizeof(fontBytes)];
}
#pragma mark - -------------基本操作----------------
/**
* 换行
*/
- (void)appendNewLine
{
Byte nextRowBytes[] = {0x0A};
[_printerData appendBytes:nextRowBytes length:sizeof(nextRowBytes)];
}
/**
* 回车
*/
- (void)appendReturn
{
Byte returnBytes[] = {0x0D};
[_printerData appendBytes:returnBytes length:sizeof(returnBytes)];
}
/**
* 设置对齐方式
*
* @param alignment 对齐方式:居左、居中、居右
*/
- (void)setAlignment:(HLTextAlignment)alignment
{
Byte alignBytes[] = {0x1B,0x61,alignment};
[_printerData appendBytes:alignBytes length:sizeof(alignBytes)];
}
/**
* 设置字体大小
*
* @param fontSize 字号
*/
- (void)setFontSize:(HLFontSize)fontSize
{
Byte fontSizeBytes[] = {0x1D,0x21,fontSize};
[_printerData appendBytes:fontSizeBytes length:sizeof(fontSizeBytes)];
}
/**
* 添加文字,不换行
*
* @param text 文字内容
*/
- (void)setText:(NSString *)text
{
NSStringEncoding enc = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
NSData *data = [text dataUsingEncoding:enc];
[_printerData appendData:data];
}
/**
* 添加文字,不换行
*
* @param text 文字内容
* @param maxChar 最多可以允许多少个字节,后面加...
*/
- (void)setText:(NSString *)text maxChar:(int)maxChar
{
NSStringEncoding enc = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
NSData *data = [text dataUsingEncoding:enc];
if (data.length > maxChar) {
data = [data subdataWithRange:NSMakeRange(0, maxChar)];
text = [[NSString alloc] initWithData:data encoding:enc];
if (!text) {
data = [data subdataWithRange:NSMakeRange(0, maxChar - 1)];
text = [[NSString alloc] initWithData:data encoding:enc];
}
text = [text stringByAppendingString:@"..."];
}
[self setText:text];
}
/**
* 设置偏移文字
*
* @param text 文字
*/
- (void)setOffsetText:(NSString *)text
{
// 1.计算偏移量,因字体和字号不同,所以计算出来的宽度与实际宽度有误差(小字体与22字体计算值接近)
NSDictionary *dict = @{NSFontAttributeName:[UIFont systemFontOfSize:22.0]};
NSAttributedString *valueAttr = [[NSAttributedString alloc] initWithString:text attributes:dict];
int valueWidth = valueAttr.size.width;
// 2.设置偏移量
[self setOffset:368 - valueWidth];
// 3.设置文字
[self setText:text];
}
/**
* 设置偏移量
*
* @param offset 偏移量
*/
- (void)setOffset:(NSInteger)offset
{
NSInteger remainder = offset % 256;
NSInteger consult = offset / 256;
Byte spaceBytes2[] = {0x1B, 0x24, remainder, consult};
[_printerData appendBytes:spaceBytes2 length:sizeof(spaceBytes2)];
}
/**
* 设置行间距
*
* @param points 多少个点
*/
- (void)setLineSpace:(NSInteger)points
{
//最后一位,可选 0~255
Byte lineSpace[] = {0x1B,0x33,60};
[_printerData appendBytes:lineSpace length:sizeof(lineSpace)];
}
/**
* 设置二维码模块大小
*
* @param size 1<= size <= 16,二维码的宽高相等
*/
- (void)setQRCodeSize:(NSInteger)size
{
Byte QRSize [] = {0x1D,0x28,0x6B,0x03,0x00,0x31,0x43,size};
// Byte QRSize [] = {29,40,107,3,0,49,67,size};
[_printerData appendBytes:QRSize length:sizeof(QRSize)];
}
/**
* 设置二维码的纠错等级
*
* @param level 48 <= level <= 51
*/
- (void)setQRCodeErrorCorrection:(NSInteger)level
{
Byte levelBytes [] = {0x1D,0x28,0x6B,0x03,0x00,0x31,0x45,level};
// Byte levelBytes [] = {29,40,107,3,0,49,69,level};
[_printerData appendBytes:levelBytes length:sizeof(levelBytes)];
}
/**
* 将二维码数据存储到符号存储区
* [范围]: 4≤(pL+pH×256)≤7092 (0≤pL≤255,0≤pH≤27)
* cn=49
* fn=80
* m=48
* k=(pL+pH×256)-3, k就是数据的长度
*
* @param info 二维码数据
*/
- (void)setQRCodeInfo:(NSString *)info
{
NSInteger kLength = info.length + 3;
NSInteger pL = kLength % 256;
NSInteger pH = kLength / 256;
Byte dataBytes [] = {0x1D,0x28,0x6B,pL,pH,0x31,0x50,48};
// Byte dataBytes [] = {29,40,107,pL,pH,49,80,48};
[_printerData appendBytes:dataBytes length:sizeof(dataBytes)];
NSData *infoData = [info dataUsingEncoding:NSUTF8StringEncoding];
[_printerData appendData:infoData];
// [self setText:info];
}
/**
* 打印之前存储的二维码信息
*/
- (void)printStoredQRData
{
Byte printBytes [] = {0x1D,0x28,0x6B,0x03,0x00,0x31,0x51,48};
// Byte printBytes [] = {29,40,107,3,0,49,81,48};
[_printerData appendBytes:printBytes length:sizeof(printBytes)];
}
#pragma mark - ------------function method ----------------
#pragma mark 文字
- (void)appendText:(NSString *)text alignment:(HLTextAlignment)alignment
{
[self appendText:text alignment:alignment fontSize:HLFontSizeTitleSmalle];
}
- (void)appendText:(NSString *)text alignment:(HLTextAlignment)alignment fontSize:(HLFontSize)fontSize
{
// 1.文字对齐方式
[self setAlignment:alignment];
// 2.设置字号
[self setFontSize:fontSize];
// 3.设置标题内容
[self setText:text];
// 4.换行
[self appendNewLine];
if (fontSize != HLFontSizeTitleSmalle) {
[self appendNewLine];
}
}
- (void)appendTitle:(NSString *)title value:(NSString *)value
{
[self appendTitle:title value:value fontSize:HLFontSizeTitleSmalle];
}
- (void)appendTitle:(NSString *)title value:(NSString *)value fontSize:(HLFontSize)fontSize
{
// 1.设置对齐方式
[self setAlignment:HLTextAlignmentLeft];
// 2.设置字号
[self setFontSize:fontSize];
// 3.设置标题内容
[self setText:title];
// 4.设置实际值
[self setOffsetText:value];
// 5.换行
[self appendNewLine];
if (fontSize != HLFontSizeTitleSmalle) {
[self appendNewLine];
}
}
- (void)appendTitle:(NSString *)title value:(NSString *)value valueOffset:(NSInteger)offset
{
[self appendTitle:title value:value valueOffset:offset fontSize:HLFontSizeTitleSmalle];
}
- (void)appendTitle:(NSString *)title value:(NSString *)value valueOffset:(NSInteger)offset fontSize:(HLFontSize)fontSize
{
// 1.设置对齐方式
[self setAlignment:HLTextAlignmentLeft];
// 2.设置字号
[self setFontSize:fontSize];
// 3.设置标题内容
[self setText:title];
// 4.设置内容偏移量
[self setOffset:offset];
// 5.设置实际值
[self setText:value];
// 6.换行
[self appendNewLine];
if (fontSize != HLFontSizeTitleSmalle) {
[self appendNewLine];
}
}
- (void)appendLeftText:(NSString *)left middleText:(NSString *)middle rightText:(NSString *)right isTitle:(BOOL)isTitle
{
[self setAlignment:HLTextAlignmentLeft];
[self setFontSize:HLFontSizeTitleSmalle];
NSInteger offset = 0;
if (!isTitle) {
offset = 10;
}
if (left) {
[self setText:left maxChar:10];
}
if (middle) {
[self setOffset:150 + offset];
[self setText:middle];
}
if (right) {
[self setOffset:300 + offset];
[self setText:right];
}
[self appendNewLine];
}
#pragma mark 图片
- (void)appendImage:(UIImage *)image alignment:(HLTextAlignment)alignment maxWidth:(CGFloat)maxWidth
{
if (!image) {
return;
}
// 1.设置图片对齐方式
[self setAlignment:alignment];
// 2.设置图片
UIImage *newImage = [image imageWithscaleMaxWidth:maxWidth];
NSData *imageData = [newImage bitmapData];
[_printerData appendData:imageData];
// 3.换行
[self appendNewLine];
// 4.打印图片后,恢复文字的行间距
Byte lineSpace[] = {0x1B,0x32};
[_printerData appendBytes:lineSpace length:sizeof(lineSpace)];
}
- (void)appendBarCodeWithInfo:(NSString *)info
{
[self appendBarCodeWithInfo:info alignment:HLTextAlignmentCenter maxWidth:300];
}
- (void)appendBarCodeWithInfo:(NSString *)info alignment:(HLTextAlignment)alignment maxWidth:(CGFloat)maxWidth
{
UIImage *barImage = [UIImage barCodeImageWithInfo:info];
[self appendImage:barImage alignment:alignment maxWidth:maxWidth];
}
- (void)appendQRCodeWithInfo:(NSString *)info size:(NSInteger)size
{
[self appendQRCodeWithInfo:info size:size alignment:HLTextAlignmentCenter];
}
- (void)appendQRCodeWithInfo:(NSString *)info size:(NSInteger)size alignment:(HLTextAlignment)alignment
{
[self setAlignment:alignment];
[self setQRCodeSize:size];
[self setQRCodeErrorCorrection:48];
[self setQRCodeInfo:info];
[self printStoredQRData];
[self appendNewLine];
}
- (void)appendQRCodeWithInfo:(NSString *)info
{
[self appendQRCodeWithInfo:info centerImage:nil alignment:HLTextAlignmentCenter maxWidth:250];
}
- (void)appendQRCodeWithInfo:(NSString *)info centerImage:(UIImage *)centerImage alignment:(HLTextAlignment)alignment maxWidth:(CGFloat )maxWidth
{
UIImage *QRImage = [UIImage qrCodeImageWithInfo:info centerImage:centerImage width:maxWidth];
[self appendImage:QRImage alignment:alignment maxWidth:maxWidth];
}
#pragma mark 其他
- (void)appendSeperatorLine
{
// 1.设置分割线居中
[self setAlignment:HLTextAlignmentCenter];
// 2.设置字号
[self setFontSize:HLFontSizeTitleSmalle];
// 3.添加分割线
NSString *line = @"- - - - - - - - - - - - - - - -";
NSStringEncoding enc = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
NSData *data = [line dataUsingEncoding:enc];
[_printerData appendData:data];
// 4.换行
[self appendNewLine];
}
- (void)appendFooter:(NSString *)footerInfo
{
[self appendSeperatorLine];
if (!footerInfo) {
footerInfo = @"谢谢惠顾,欢迎下次光临!";
}
[self appendText:footerInfo alignment:HLTextAlignmentCenter];
}
- (NSData *)getFinalData
{
return _printerData;
}
@end
控制器中使用方法如下:
#import "ViewController.h"
#import "JWBluetoothManage.h"
#define WeakSelf __block __weak typeof(self)weakSelf = self;
@interface ViewController () <UITableViewDataSource,UITableViewDelegate>{
JWBluetoothManage * manage;
}
@property (nonatomic, strong) UITableView * tableView;
@property (nonatomic, strong) NSMutableArray * dataSource; //设备列表
@property (nonatomic, strong) NSMutableArray * rssisArray; //信号强度 可选择性使用
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"蓝牙列表";
self.dataSource = @[].mutableCopy;
self.rssisArray = @[].mutableCopy;
[self _createTableView];
manage = [JWBluetoothManage sharedInstance];
WeakSelf
[manage beginScanPerpheralSuccess:^(NSArray<CBPeripheral *> *peripherals, NSArray<NSNumber *> *rssis) {
weakSelf.dataSource = [NSMutableArray arrayWithArray:peripherals];
weakSelf.rssisArray = [NSMutableArray arrayWithArray:rssis];
[weakSelf.tableView reloadData];
} failure:^(CBManagerState status) {
[ProgressShow alertView:self.view Message:[ProgressShow getBluetoothErrorInfo:status] cb:nil];
}];
manage.disConnectBlock = ^(CBPeripheral *perpheral, NSError *error) {
NSLog(@"设备已经断开连接!");
weakSelf.title = @"蓝牙列表";
};
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]initWithTitle:@"打印" style:UIBarButtonItemStylePlain target:self action:@selector(printe)];
self.view.backgroundColor = [UIColor cyanColor];
}
- (void)printe{
if (manage.stage != JWScanStageCharacteristics) {
[ProgressShow alertView:self.view Message:@"打印机正在准备中..." cb:nil];
return;
}
JWPrinter *printer = [[JWPrinter alloc] init];
NSString *str1 = @"=============测试支付=============";
[printer appendText:str1 alignment:HLTextAlignmentCenter];
[printer appendTitle:@"商户名称:" value:@"这是测试啊啊啊啊啊啊"];
[printer appendTitle:@"商户编号:" value:@"00000000000"];
[printer appendTitle:@"订单编号:" value:@"LLLLLLLLLLL"];
[printer appendTitle:@"交易类型:" value:@"这是测试的支付支付"];
[printer appendTitle:@"交易时间:" value:@"2018-09-13"];
[printer appendTitle:@"金 额:" value:@"10000000000000元"];
[printer appendFooter:@"欢迎使用测试支付!"];
[printer appendNewLine];
NSData *mainData = [printer getFinalData];
[[JWBluetoothManage sharedInstance] sendPrintData:mainData completion:^(BOOL completion, CBPeripheral *connectPerpheral,NSString *error) {
if (completion) {
NSLog(@"打印成功");
}else{
NSLog(@"写入错误---:%@",error);
}
}];
}
-(void)viewWillAppear:(BOOL)animated{
WeakSelf
[super viewWillAppear:animated];
[manage autoConnectLastPeripheralCompletion:^(CBPeripheral *perpheral, NSError *error) {
if (!error) {
[ProgressShow alertView:self.view Message:@"连接成功!" cb:nil];
weakSelf.title = [NSString stringWithFormat:@"已连接-%@",perpheral.name];
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf.tableView reloadData];
});
}else{
[ProgressShow alertView:self.view Message:error.domain cb:nil];
}
}];
}
#pragma mark tableview medthod
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.dataSource.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = @"identifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier];
}
CBPeripheral *peripherral = [self.dataSource objectAtIndex:indexPath.row];
if (peripherral.state == CBPeripheralStateConnected) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
cell.textLabel.text = [NSString stringWithFormat:@"名称:%@",peripherral.name];
NSNumber * rssis = self.rssisArray[indexPath.row];
cell.detailTextLabel.text = [NSString stringWithFormat:@"强度:%@",rssis];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
CBPeripheral *peripheral = [self.dataSource objectAtIndex:indexPath.row];
[manage connectPeripheral:peripheral completion:^(CBPeripheral *perpheral, NSError *error) {
if (!error) {
[ProgressShow alertView:self.view Message:@"连接成功!" cb:nil];
self.title = [NSString stringWithFormat:@"已连接-%@",perpheral.name];
dispatch_async(dispatch_get_main_queue(), ^{
[tableView reloadData];
});
}else{
[ProgressShow alertView:self.view Message:error.domain cb:nil];
}
}];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
- (void) _createTableView{
if (!_tableView) {
_tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - 64) style:UITableViewStylePlain];
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
_tableView.tableFooterView = [UIView new];
if ([_tableView respondsToSelector:@selector(setSeparatorInset:)]) {
[_tableView setSeparatorInset:UIEdgeInsetsZero];
}
if ([_tableView respondsToSelector:@selector(setLayoutMargins:)]) {
[_tableView setLayoutMargins:UIEdgeInsetsZero];
}
}
if (![self.view.subviews containsObject:_tableView]) {
[self.view addSubview:_tableView];
}else{
[_tableView reloadData];
}
}
@end