美文网首页good
iOS 打印小票

iOS 打印小票

作者: 高乔人 | 来源:发表于2018-09-13 11:49 被阅读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
    

    相关文章

      网友评论

        本文标题:iOS 打印小票

        本文链接:https://www.haomeiwen.com/subject/sgcwgftx.html