博客> IOS蓝牙打印概述
IOS蓝牙打印概述
2017-10-17 09:10 评论:1 阅读:1520 wesinlove
ios swift bluetooth print

ps:近来公司有个ios调用蓝牙打印机打印小票的功能,网上资料也有,ESC/POS打印指令集也有,以前刚毕业有做过winform调用网络小票打印机的功能,指令集反正都是差不多的。只是攻略不是很详细,这里把详细步骤和遇到的问题以及解决方法详细的记录下,已供后来人参考。这里建议大家还是使用ESC/POS指令来实现打印功能,大多数给力的打印机厂商都会兼容这套指令。吐槽下近来遇到的不支持该指令集的打印机,然后提供个sdk。我就呵呵 闲话不多说,经验教程如下: ps:我使用的是swift开发

蓝牙连接 蓝牙框架引入 import CoreBluetooth

创建蓝牙管理类 lazy var blueManager:CBCentralManager? = CBCentralManager(delegate: self, queue: dispatch_get_main_queue())

扫描可连接蓝牙 blueManager?.scanForPeripheralsWithServices(nil, options: [CBCentralManagerScanOptionAllowDuplicatesKey:true])

蓝牙处理代理类 蓝牙设置开关的代理

func centralManagerDidUpdateState(central: CBCentralManager) {
    switch (central.state)
    {
    case CBCentralManagerState.PoweredOn:
        //当蓝牙打开时,自动扫描对应的外设
            blueManager?.scanForPeripheralsWithServices(nil, options: [CBCentralManagerScanOptionAllowDuplicatesKey:true])
        }
        break
    default:
        NSLog("Central Manager did change state")
        break;
    }
}

扫描监听代理,当扫描到蓝牙设备时,这里会接受到通知

func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber) {
    let uuid = peripheral.identifier.UUIDString
            print("发现设备")
            print(uuid)
            print(peripheral.name, advertisementData)
    print("------------------------------------------")
    /**
    * 不包含服务功能
    */
    if advertisementData["kCBAdvDataServiceUUIDs"] == nil {
        return
    }
    //这里是把扫描到的不同设备保存起来,devices是自己定义的一个蓝牙设备数组
    if devices.find({$0.peripheral?.identifier.UUIDString == uuid}) == -1 {
        let serviceID = (advertisementData["kCBAdvDataServiceUUIDs"] as? (String,String))?.1 ?? ""
        devices.append(Device(name: peripheral.name ?? LS("unnamed"), peripheral: peripheral, serviceUUID:serviceID)) //"未命名"
    }

}

从打印机数组里面确定需要选择的打印机 调用连接代码,弱水三千,取一瓢而饮之。

func connectDevice(device:Device) {
    blueManager?.stopScan()
    currentDevice = device
    blueManager?.connectPeripheral(device.peripheral!, options: nil)
}

连接打印机后,系统继续调用代理,告诉你连接结果 顾名思义,连不上T0T

func centralManager(central: CBCentralManager, didFailToConnectPeripheral peripheral: CBPeripheral, error: NSError?) {
    MessageShow.ShareInstance.errorMessage = error?.localizedFailureReason ?? ""
    printDelegate?.selectPrinter()
}

连上了~,~

func centralManager(central: CBCentralManager, didConnectPeripheral peripheral: CBPeripheral) {
    noConnectedTimer?.invalidate()
    disConnectTimer?.invalidate()
    peripheral.delegate = self
    peripheral.discoverServices(nil)
}

这是分手(断开连接)后的通知

func centralManager(central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: NSError?) {
}

连接上peripheral后需要连接对应的服务才能算真正连上

func peripheral(peripheral: CBPeripheral, didDiscoverServices error: NSError?) {
    if error != nil {
        MessageShow.ShareInstance.errorMessage = error?.localizedFailureReason ?? LS("notfindprintservice") //"该设备找不到对应的打印服务"
        return
    }
    for service in peripheral.services! {
        //正常打印机的打印服务就是这个uuid
        if service.UUID == CBUUID(string: "E7810A71-73AE-499D-8C15-FAA9AEF0C3F2") {
            currentDevice?.service = service
            //是的,你没看错,连上服务还得再连所谓的特性
            peripheral.discoverCharacteristics(nil, forService: service)
        }
    }
    if currentDevice?.service == nil {
        MessageShow.ShareInstance.errorMessage = LS("notfindprintservice") //"该设备找不到对应的打印服务"
        currentDevice = nil
    }
}

连接characteristics(翻译:特性)

func peripheral(peripheral: CBPeripheral, didDiscoverCharacteristicsForService service: CBService, error: NSError?) {
    if error != nil {
        MessageShow.ShareInstance.errorMessage = error?.localizedFailureReason ?? LS("notfindprintservice") //"该设备找不到对应的打印服务"
        return
    }

    if service.characteristics != nil {
        for characteristic in service.characteristics! {
            if characteristic.UUID == CBUUID(string: "BEF8D6C9-9C21-4C9E-B632-BD58C1009F9F") {
                currentDevice?.characteristic = characteristic
                peripheral.setNotifyValue(true, forCharacteristic: characteristic)
                //打印机连上了,后面就可以对他发指令打印了
                //printDelegate?.doPrintBill()
            }
        }
    }
}

再来个断开连接的代码 blueManager?.cancelPeripheralConnection(currentDevice!.peripheral!)

再开始打印指令的教程前,免不得先说说遇到坑吧。 1、ios对打印机的指令发送是必须要有长度限度的,不同打印机的长度不一样。当你发现打印一个长长的字符串发现打一半卡死时,就得考虑下长度截取的问题了。 2、大多数打印机没有交互功能,也就是只能对牛弹琴了。so断开打印机的时机也是个问题。当然一对一永远连接的就不用断开了。 3、打印条码,建议还是需要打印功能比较好的打印机。

下面大致写下常用的打印指令: 初始化打印机

func initPrint() {
    sendCode([0x1b, 0x40], boolEnd: true)
}

打印字符串 打印字符串的位置一般自己调吧,align表示这行(注意行,这个不能拆分)的打印靠左靠右

func printText(text: String, align: NSTextAlignment) {
    self.align(align)
    //中文字符打印需要转码
    let encode =  CFStringConvertEncodingToNSStringEncoding(UInt32(CFStringEncoding(CFStringEncodings.GB_18030_2000.rawValue)))
    var printStr = text
    //兼容某些渣渣打印机设置长度限制,好点的打印机1000也没什么问题
    while printStr.charLength() > 60 {
        let nowStr = printStr.substringToIndex(32)
        let tmpData = NSString(string: nowStr).dataUsingEncoding(encode, allowLossyConversion: false)!
        sendMsg(tmpData)
        printStr = printStr.substringFromIndex(32)
    }
    if printStr.characters.count > 0 {
        let tmpData = NSString(string: printStr).dataUsingEncoding(encode, allowLossyConversion: false)!
        sendMsg(tmpData)
    }
}

/**
 text 对齐

 - parameter align: .
 */
func align(align:NSTextAlignment) -> NSMutableData {
    if align == currentAlign {
        return NSMutableData()
    }
    currentAlign = align
    var bytes:[UInt8] = [0x1b, 0x61]
    switch align {
    case .Center:
        bytes.append(0x01)
    case .Right:
        bytes.append(0x02)
    default:
        bytes.append(0x00)
    }
    sendCode(bytes)
    return NSMutableData()
}

//加粗

func bold(enable:Bool) {
    var bytes:[UInt8] = [0x1b, 0x45]
    bytes.append(enable ? 0x01 : 0x00)
    sendCode(bytes)
}

//打开钱箱    

func openBox() {
    let bytes:[UInt8] = [27,112, 0, 200,200]
    sendCode(bytes)
}

/**
 结束走纸 最后表示走几行纸
 */
func endPrint() {
    sendCode([0x1b, 0x64, 0x05] as [UInt8])
    cutPaper()
}

/**
 切纸
 */
func cutPaper() {
    //半切01,全切00
    sendCode([0x1d, 0x56, 0x00] as [UInt8], boolEnd: true)
}

加载图片,图片方式打印条码用的。这里用了ZXingObjC库转码,可以在打印的开头先预存图片,再打印,注意渣打印机是打印不了的,甚至会卡死打印机

func loadImage(code:String) {
    let writer = ZXMultiFormatWriter()
    do {
        let result = try writer.encode(code, format: kBarcodeFormatCode128, width: 20, height: 44)
        let hehe = result.descriptionWithSetString("1", unsetString: "0")
        let haha = hehe.componentsSeparatedByString("\n")[0]
        let x = haha.characters.count
        let y:UInt8 = 5
        //打印指令解释有点难理解,大致解释下,0x1d, 0x2a 为指令, x/8=条码长度/8 y:高度 适应条码宽度而已 >1 即可 
        var barcodes:[UInt8] = [0x1D, 0x2A, UInt8(x / 8), y]
        for index in haha.characters.indices {
            if haha[index] == "0" {
                for _ in 0..<y {
                    barcodes.append(0x00)
                }
            } else {
                for _ in 0..<y {
                    barcodes.append(255)
                }
            }
        }
        //发送定义位图的指令
        sendCode(barcodes)
    } catch {
        print(error)
    }
}

打印预存的图片

func printBarcode() {
    sendCode([0x1d, 0x2f, 0x03])
}

func sendCode(bytes:[UInt8], boolEnd:Bool = false) {
    let data = NSData(bytes: bytes, length: bytes.count)
    sendMsg(data, boolEnd: boolEnd)
}

func sendMsg(data:NSData, boolEnd:Bool = false) {
    print(data.length)
    peripheral?.writeValue(data, forCharacteristic: characteristic!, type: .WithoutResponse)
}

ps:还有一种直接条码打印的方式,手里打印机有限,一个渣,另外一只居然不能接受条码指令,渣打印机打不出来,所以就不写出来了。大致就是获取字符串的unicode,在指令后一起传入。没有成功~,~如果有知道的也可以补充下。 最后推荐下指令集比较完整的文档: http://www.docin.com/p-676248934.html

收藏
0
sina weixin mail 回到顶部