美文网首页OC-开发案例收集
swift 连接 BLE 蓝牙打印机

swift 连接 BLE 蓝牙打印机

作者: 做人要简单 | 来源:发表于2017-09-13 10:13 被阅读868次

    swift 蓝牙连接

    项目简介

    最近公司要用到便携式蓝牙打印机进行打印
    打印机使用的ECS/POS指令集
    ios使用的BLE方案,安卓则是因为设备的原因只能选择普通蓝牙的连接方案
    BLE蓝牙相关的概念性东西我这里就不说了 大家可以自己去搜索下
    有个mac的蓝牙开发工具LightBlue,很好用,mac app store 自己下就好了,这个很方便你理解BLE的蓝牙相关
    device(central/peripheral)->services->characteristics

    屏幕快照 2017-09-08 下午3.39.04.png

    这里可以看到,有一个mobike,有兴趣的同学可以研究下mobike的蓝牙连接 ☺
    说笑一下,人家肯定有安全性校验的

    语言选型

    最近在学习ios开发,因为我是android出身,学习ios开发的时候swift3已经出现很久了,所以我这里使用的swift进行开发

    坑1

    最初我使用了厂家提供的ios sdk进行开发,其中封装了很多常用的方法,让我自己以为很简单就能完成,但是事实上是我太天真了,首先厂家提供的是.a的库,只有一个.h文件暴露在外,我的项目是纯swift项目,这就不可避免的使用到了swift到oc的桥接

    坑2

    满以为桥接完了调SDK方法就行,谁知道调用的时候根本就没反应,没办法,只能摸石头过河进行开发了,最初使用的是oc的corebluetooth方案,因为实在是没找到swift的相关说法,baidu没搜到,没办法,oc毕竟也算是入门了,直接开干了

    坑3

    开发完oc的连接demo,强迫症发作,决定一定要用纯swift开发,毕竟我们还是要跟随时代脚步的嘛

    找文档

    都说苹果的官方文档写的很好,那么我就上去看看吧,这里要吐槽一点,文档的方法,类描述确实很不错,看起来很清晰,但是但是..怎么没有告诉我import什么

    UIKit里不包含Bluetooth相关的类,而官方中将这个定义在System体系的Core Bluetooth 中

    使用

    import CoreBluetooth
    

    这样CBCentralManager终于可以用了

    正式开发

    折腾了半天,终于可以开始开发了...

    macos模拟器蓝牙central

    这里要吐槽下公司,没有ios测试机,我自己又是安卓手机,没办法,这里有一招,建一个macos的项目,将UIKit换成Cocoa,或者Foundation,然后其他语法中macos和ios的蓝牙部分代码几乎一样,这样就能连接上打印机了,我这里又是模块开发,将数据部分的代码copy一份到macos的demo上,就能模拟真机的mac了
    上面说几乎一样的原因是,cm.isScanning在mac开发中用不了,ios中可以

    当时记得苹果说simulator可以用mac的蓝牙开发,结果短短的一个版本以后就干掉了相关功能,真是狗

    帮助类的代码

    
    //
    //  BluetoothHelper.swift
    //  SwiftBluetoothScanDemo1
    //
    //  Created by caijinglong on 2017/9/9.
    //
    
    import Foundation
    import CoreBluetooth
    
    protocol BluetoothHelperDelegate {
        
        func bluetoothHelperIndex()->Int
        
        func bluetoothHelperNotifyConnected(isConnected:Bool)
        
        func bluetoothHelperAutoStopScan()
    }
    
    class BluetoothHelper :NSObject,CBCentralManagerDelegate,CBPeripheralDelegate{
    
        static let shared = BluetoothHelper()
    
        private var cm:CBCentralManager! = nil
        private var peripheral: CBPeripheral! = nil
        private var service:CBService! = nil
    
        private var characteristic:CBCharacteristic! = nil
        
        private var delegateDict = Dictionary<Int,BluetoothHelperDelegate>()
        
        public func registerDelegate(delegate:BluetoothHelperDelegate){
            delegateDict[delegate.bluetoothHelperIndex()] = delegate
        }
        
        public func unregisterDelegate(delegate:BluetoothHelperDelegate){
            delegateDict.removeValue(forKey: delegate.bluetoothHelperIndex())
        }
        
        private override init(){
            super.init()
            self.cm = CBCentralManager(delegate: self, queue: nil)
        }
        
        /// 被连接的打印机的名字
        var connectDeviceName:String? = ""
        
        /// 是否连接了打印机
        var isConnected:Bool = false{
            didSet{
                if(!isConnected){
                    peripheral = nil
                    service = nil
                    characteristic = nil
                    connectDeviceName = nil
                    
                    delegateDict.forEach({ (key,delegate) in
                        
                    })
                }else{
                    connectDeviceName = self.name
                }
            }
        }
        
        /// 蓝牙开关是否打开
        var btOpen = false
        private var name = "QSPrinter"
    
        // 后面是代理方法
        func centralManagerDidUpdateState(_ central: CBCentralManager) {
            NSLog("状态变化")
            if(central.state.rawValue == 5){
                btOpen = true
            }else{
                btOpen = false
                isConnected = false
            }
        }
        
        /// 开始扫描设备
        func startScan(name:String){
            self.name = name
            self.cm.stopScan()
            self.cm.scanForPeripherals(withServices: nil, options: nil)
            runDelay(5) { 
                self.delegateDict.forEach({ (_,delegate) in
                    self.cm.stopScan()
                    delegate.bluetoothHelperAutoStopScan()
                })
            }
        }
        
        /// 停止扫描设备
        func stopScan(){
            self.cm.stopScan()
        }
        
        /// 关闭连接设备
        func disconnect(){
            if(peripheral != nil){
                self.cm.cancelPeripheralConnection(peripheral)
            }
        }
    
        func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) {
            NSLog("\(String(describing: peripheral.name)) is discovered")
            if(peripheral.name?.uppercased() == name.uppercased()){
                self.peripheral = peripheral
                peripheral.delegate = self
                cm.connect(peripheral)
                cm.stopScan()
            }
        }
    
        func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
            NSLog("\(String(describing: peripheral.name)) 连接成功")
            let uuid = CBUUID(string: "18F0")
            peripheral.discoverServices([uuid])
        }
    
        func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
            NSLog("\(String(describing: peripheral.name)) 连接断开")
            isConnected = false
        }
    
        func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
            if let service = peripheral.services?[0]{
                let uuid = CBUUID(string: "2AF1")
                peripheral.discoverCharacteristics([uuid], for: service)
                self.service = service
            }
        }
        
        func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
            if let characteristic = service.characteristics?[0]{
                NSLog("characteristic is prepared")
                isConnected = true
                self.characteristic = characteristic
            }
        }
    
        /// 输出字符串
        func writeText(text:String)throws{
            let enc = CFStringConvertEncodingToNSStringEncoding(CFStringEncoding(CFStringEncodings.GB_18030_2000.rawValue))
    
            if let data = text.data(using: String.Encoding(rawValue: enc)){
                do {
                   try self.writeData(data: data)
                } catch  {
                    throw error
                }
            }
        }
        
        
        private var datas = [Data]()
        
        /// 写入数据
        func writeData(data:Data) throws {
            if(isConnected){
                datas.append(data)
            }else{
                throw BtError.NoConnectError
            }
        }
        
        /// 真实的打印方法
        func print(){
            for index in 0 ... datas.count - 1  {
                let item = datas[index]
                runDelay(0.02 * Double(index), {
                    self.peripheral.writeValue(item, for: self.characteristic, type: CBCharacteristicWriteType.withoutResponse)
                })
            }
            self.datas.removeAll()
        }
    
    }
    
    enum BtError :Error{
        case NoConnectError
    }
    
    

    分析下代码
    这里使用单例的方案管理连接,实际上BLE支持同时连接多个外设,我这里是因为目前没有这样的需求,所以考虑使用单例的模式,看官请根据自己的需求来

    centralManagerDidUpdateState这个代理方法很重要,是唯一一个必须实现的方法,用于监听蓝牙的状态,是一个Int类型的枚举值,这里因为ios10有一个过期相关的提示,替换了state相关的类由CBCentralManagerState替换到CBManagerState,值没有变化,就是由oc的枚举方式替换到了swift的枚举,这里我直接使用5来进行判断,ios11也没看见修改这个数值,短时间内直接用5就行,后续有bug再说
    这里用一个property来储存蓝牙状态

    startScan其中是开始扫描的方法

        func startScan(name:String){
            self.name = name
            self.cm.stopScan()
            self.cm.scanForPeripherals(withServices: nil, options: nil)
            runDelay(5) { 
                self.delegateDict.forEach({ (_,delegate) in
                    self.cm.stopScan()
                    delegate.bluetoothHelperAutoStopScan()
                })
            }
        }
    

    先停止扫描,然后开始扫描,记录一下name,后续会用到,5秒后停止扫描,并代理通知

    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) {
            NSLog("\(String(describing: peripheral.name)) is discovered")
            if(peripheral.name?.uppercased() == name.uppercased()){
                self.peripheral = peripheral
                peripheral.delegate = self
                cm.connect(peripheral)
                cm.stopScan()
            }
        }
    
        func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
            NSLog("\(String(describing: peripheral.name)) 连接成功")
            let uuid = CBUUID(string: "18F0")
            peripheral.discoverServices([uuid])
        }
    

    这两个方法,第一个是扫描到了设备,这里我忽视大小写进行匹配,然后如果名字匹配则调用cm.connect(peripheral)进行连接,并且停止扫描
    第二个方法是连接成功,这里18F0是service的名称,就是扫描UUID为18F0的services

        func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
            if let service = peripheral.services?[0]{
                let uuid = CBUUID(string: "2AF1")
                peripheral.discoverCharacteristics([uuid], for: service)
                self.service = service
            }
        }
    

    这里是在扫描到services后的代理,然后扫描uuid为2AF1的Characteristics
    这里service保持引用

    func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
            if let characteristic = service.characteristics?[0]{
                NSLog("characteristic is prepared")
                isConnected = true
                self.characteristic = characteristic
            }
        }
    

    这里是扫描到Characteristics后的操作,这里我记录了一个连接状态 和 characteristic的引用

    self.peripheral.writeValue(item, for: self.characteristic, type: CBCharacteristicWriteType.withoutResponse)//item是Data
    

    这个是真实的输出方法,这个输出方法使用了了之前的peripheralcharacteristic
    这里之所以要持有所有'中间'产物的引用是因为之前用oc写这个代码的时候因为没有持有peripheral的引用报错,导致代理获取不到数据

    详细分析写数据

    这里我使用了一个方案来写

       /// 输出字符串
        func writeText(text:String)throws{
            let enc = CFStringConvertEncodingToNSStringEncoding(CFStringEncoding(CFStringEncodings.GB_18030_2000.rawValue))
    
            if let data = text.data(using: String.Encoding(rawValue: enc)){
                do {
                   try self.writeData(data: data)
                } catch  {
                    throw error
                }
            }
        }
        
        
        private var datas = [Data]()
        
        /// 写入数据
        func writeData(data:Data) throws {
            if(isConnected){
                datas.append(data)
            }else{
                throw BtError.NoConnectError
            }
        }
        
        /// 真实的打印方法
        func print(){
            for index in 0 ... datas.count - 1  {
                let item = datas[index]
                runDelay(0.02 * Double(index), {
                    self.peripheral.writeValue(item, for: self.characteristic, type: CBCharacteristicWriteType.withoutResponse)
                })
            }
            self.datas.removeAll()
        }
    
    func runDelay(_ delay:TimeInterval,_ block:@escaping () -> ()){
        let queue = DispatchQueue.main
        
        let delayTime = DispatchTime.now() + delay
        
        queue.asyncAfter(deadline: delayTime) {
            block()
        }
    }
    

    这里的思路大概是:
    首先一个容器用于储存顺序存入的数据,然后在调用print的时候将所有数据进行输出,并且延迟一定的时间,每个输出时间间隔0.02s
    之所以这么做的原因是:我当时直接调用writeValue方法写数据,没有间隔时间,发现会出现样式错误,输出顺序错误的情况发生
    这个时候我凭感觉认为是发生了writeValue和实际通讯的到达顺序不一致的问题,我查了下,BLE主打的是低延迟,但是对应的数据通讯的数据量就有了限制,所以采用这个方案

    当然我也试过使用一个Data储存所有字节数据的方案,发现打印机无法打印,具体原因没有深究

    打印相关

    编码问题

    一般的蓝牙打印机中文使用的是GBK编码,ios中是GB_18030_2000,而ios默认是utf8编码,所以这里需要显示指定

    关于二维码

    打印二维码使用的是ESC/POS的指令集,这个在指令集的说明文档中可以找到
    这里的moduleSize是二维码的大小,具体参数可以参考说明文档,一般对接的打印机厂商都会提供

    一般的打印机中文都是GBK编码的,而扫码一般是UTF8编码,这个编码转换很麻烦,所以尽量不要出现中文

    打印机发送指令

    //
    //  PrinterHelper.swift
    //  SwiftBluetoothScanDemo1
    //
    //  Created by Caijinglong on 2017/9/11.
    //
    
    import Foundation
    
    /// printer helper
    ///
    /// single instance
    class PrinterHelper{
        
        static var shared:PrinterHelper = PrinterHelper()
        
        var helper : BluetoothHelper!
        
        //    var devices = [Printer]()
        
        private init(){
            helper = BluetoothHelper.shared
        }
    
        func registerDelegate(delegate: BluetoothHelperDelegate){
            helper.registerDelegate(delegate: delegate)
        }
        
        func unregisterDelegate(delegate: BluetoothHelperDelegate){
            helper.unregisterDelegate(delegate: delegate)
        }
        
        var index = 0
        
        let DIVIDER = "-----------------------------------------------"
        let ESC: Byte = 27//换码
        let FS: Byte = 28//文本分隔符
        let GS: Byte = 29//组分隔符
        let DLE: Byte = 16//数据连接换码
        let EOT: Byte = 4//传输结束
        let ENQ: Byte = 5//询问字符
        let SP: Byte = 32//空格
        let HT: Byte = 9//横向列表
        let LF: Byte = 10//打印并换行(水平定位)
        let CR: Byte = 13//归位键
        let FF: Byte = 12//走纸控制(打印并回到标准模式(在页模式下)
        let CAN: Byte = 24//作废(页模式下取消打印数据 )
        
        func conn(deviceName:String){
            helper.startScan(name: deviceName)
        }
        
        func disconnect(){
            helper.disconnect()
        }
        
        func sendMsg(msg:String) -> Self{
            try? helper.writeText(text: msg)
            return self
        }
        
        func sendBytes(bytes:[Byte]) -> Self{
            try? helper.writeData(data: Data.bytesArray(byteArray: bytes))
            return self
        }
        
        func sendHex(int:Int) -> Self {
            return self.sendHexs(hexInt: int)
        }
        
        func sendHexs(hexInt ints:Int...) -> Self{
            var data = Data()
            ints.forEach { (int) in
                data.append(UInt8(int))
            }
            try? helper.writeData(data: data)
            return self
        }
        
        func sendBytes(bytes:Byte...) -> Self{
            return sendBytes(bytes: bytes)
        }
        
        func alignLeft()-> Self{
            return sendBytes(bytes: ESC,97,0)
        }
        
        func alignCenter() -> Self {
            return sendBytes(bytes: ESC,97,1)
        }
        
        func alignRight() -> Self{
            return sendBytes(bytes: ESC,97,2)
        }
        
        func printDivider() -> Self {
            return sendMsg(msg: DIVIDER)
        }
        
        
        func startPrint(){
            helper.print()
        }
        
        func setFontSize(size:Int)  -> Self{
            var realSize: Byte = 0
            
            if(size <= 7){
                realSize = Byte(size * 17)
            }
            
            var result = [Byte]()
            result.append(0x1D)
            result.append(0x21)
            result.append(realSize)
            print("size = \(size)  realSize = \(realSize)")
            return sendBytes(bytes: result)
        }
        
        func newLine(lines:Int = 1) -> Self{
            for _ in 0...lines - 1{
                _ = sendHex(int: 0x0A)
            }
            return self
        }
        
        /**
         * 选择加粗模式
         
         * @return
         */
        func boldOn() -> Self {
            var result = [Byte]()
            result.append(ESC)
            result.append(69)
            result.append(0xF)
            return sendBytes(bytes: result)
        }
        
        
        /**
         * 取消加粗模式
         
         * @return
         */
        func boldOff() -> Self {
            var result = [Byte]()
            result.append(ESC)
            result.append(69)
            result.append(0)
            return sendBytes(bytes: result)
        }
        
        func subTitle(_ title:String) -> Self{
            return
                self.newLine()
                    .setFontSize(size: 1)
                    .boldOn()
                    .alignCenter()
                    .sendMsg(msg: title)
                    .setFontSize(size: 0)
                    .boldOff()
        }
        
        func sendQrcode(qrcode:String) -> Self{
            let moduleSize:Byte = 8
            var list = [Byte]()
            
            if let data = Data.gbkData(text: qrcode){
                
                //打印二维码矩阵
                list.append(0x1D)// init
                list.append(40) // adjust height of barcode
                list.append(107)// adjust height of barcode
                list.append(Byte(data.count + 3)) // pl
                list.append(0) // ph
                list.append(49) // cn
                list.append(80) // fn
                list.append(48) //
    
                data.forEach({ (char) in
                    list.append(char)
                })
                
                list.append(0x1D)
                list.append(40)// list.append("(k")
                list.append(107)// list.append("(k")
                list.append(3)
                list.append(0)
                list.append(49)
                list.append(69)
                list.append(48)
                
                list.append(0x1D)
                list.append(40)// list.append("(k")
                list.append(107)// list.append("(k")
                list.append(3)
                list.append(0)
                list.append(49)
                list.append(67)
                list.append(moduleSize)
                
                list.append(0x1D)
                list.append(40)// list.append("(k")
                list.append(107)// list.append("(k")
                list.append(3) // pl
                list.append(0) // ph
                list.append(49) // cn
                list.append(81) // fn
                list.append(48) // m
            }
            
            return
                alignCenter()
                .sendBytes(bytes: list)
        }
    }
    
    

    蓝牙连接的类

    //
    //  BluetoothHelper.swift
    //  SwiftBluetoothScanDemo1
    //
    //  Created by caijinglong on 2017/9/9.
    //  Copyright © 2017 sxw. All rights reserved.
    //
    
    import Foundation
    import CoreBluetooth
    
    protocol BluetoothHelperDelegate:NSObjectProtocol {
        
        func bluetoothHelperIndex()->Int
        
        func bluetoothHelperNotifyConnected(isConnected:Bool)
        
        func bluetoothHelperAutoStopScan()
        
        func bluetoothHelperFindDevices(name:String)
    }
    
    extension BluetoothHelperDelegate{
        func bluetoothHelperFindDevices(name:String){
        }
    }
    
    protocol BluetoothHelperScanDeviceDelegate {
        func bluetoothScan(peripheral: CBPeripheral)
        
        func bluetoothHelperIndex()->Int
        
        func bluetoothConnected(name:String)
        
        func bluetoothDisconnect(name:String)
    }
    
    extension BluetoothHelperScanDeviceDelegate{
        func bluetoothConnected(name:String){}
        
        func bluetoothDisconnect(name:String){}
    }
    
    class BluetoothHelper :NSObject,CBCentralManagerDelegate,CBPeripheralDelegate{
    
        static let shared = BluetoothHelper()
    
        private var cm:CBCentralManager! = nil
        private var peripheral: CBPeripheral! = nil
        private var service:CBService! = nil
    
        private var characteristic:CBCharacteristic! = nil
        
        private var delegateDict = Dictionary<Int,BluetoothHelperDelegate>()
        
        private var scanDelegateDict = Dictionary<Int,BluetoothHelperScanDeviceDelegate>()
        
        public func registerDelegate(delegate:BluetoothHelperDelegate){
            delegateDict[delegate.bluetoothHelperIndex()] = delegate
        }
        
        public func unregisterDelegate(delegate:BluetoothHelperDelegate){
            delegateDict.removeValue(forKey: delegate.bluetoothHelperIndex())
        }
        
        public func registerScanDelegate(delegate:BluetoothHelperScanDeviceDelegate){
            scanDelegateDict[delegate.bluetoothHelperIndex()] = delegate
        }
        
        public func unregisterScanDelegate(delegate:BluetoothHelperScanDeviceDelegate){
            delegateDict.removeValue(forKey: delegate.bluetoothHelperIndex())
        }
    
        private override init(){
            super.init()
            self.cm = CBCentralManager(delegate: self, queue: nil)
        }
        
        /// 被连接的打印机的名字
        var connectDeviceName:String? = ""
        
        /// 是否连接了打印机
        var isConnected:Bool = false{
            didSet{
                if(!isConnected){
                    peripheral = nil
                    service = nil
                    characteristic = nil
                    
                    delegateDict.forEach({ (key,delegate) in
                        delegate.bluetoothHelperNotifyConnected(isConnected: false)
                    })
                    connectDeviceName = nil
                }else{
                    connectDeviceName = self.name
                    
                    delegateDict.forEach({ (key,delegate) in
                        delegate.bluetoothHelperNotifyConnected(isConnected: true)
                    })
                }
            }
        }
        
        /// 蓝牙开关是否打开
        var btOpen = false
        private var name = "QSPrinter"
    
        // 后面是代理方法
        func centralManagerDidUpdateState(_ central: CBCentralManager) {
            NSLog("状态变化: state = \(central.state.rawValue)")
            if(central.state.rawValue == 5){
                btOpen = true
            }else{
                btOpen = false
                isConnected = false
            }
        }
        
        /// 仅扫描
        func startScan(){
            self.name = ""
            self.cm.stopScan()
            self.cm.scanForPeripherals(withServices: nil, options: nil)
            runDelay(5) { 
                self.delegateDict.forEach({ (_,delegate) in
                    delegate.bluetoothHelperAutoStopScan()
                })
            }
        }
        
        /// 开始扫描设备
        func startScan(name:String){
            self.name = name
            self.cm.stopScan()
            self.cm.scanForPeripherals(withServices: nil, options: nil)
            runDelay(5) { 
                self.delegateDict.forEach({ (_,delegate) in
                    self.cm.stopScan()
                    delegate.bluetoothHelperAutoStopScan()
                })
            }
        }
        
        /// 停止扫描设备
        func stopScan(){
            self.cm.stopScan()
        }
        
        /// 关闭连接设备
        func disconnect(){
            if(peripheral != nil){
                self.cm.cancelPeripheralConnection(peripheral)
            }
        }
    
        /// 扫描到设备
        func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) {
            NSLog("\(String(describing: peripheral.name)) is discovered")
            if(peripheral.name == nil){
                return
            }
            
            scanDelegateDict.forEach { (_,delegate) in
                delegate.bluetoothScan(peripheral: peripheral)
            }
            
            
            if(self.name.isEmpty){
                return
            }
            
            if(peripheral.name?.uppercased() == name.uppercased()){
                self.connect(peripheral: peripheral)
            }
        }
    
        /// 连接peripheral
        func connect(peripheral:CBPeripheral){
            self.peripheral = peripheral
            peripheral.delegate = self
            cm.connect(peripheral)
            cm.stopScan()
        }
        
        /// 连接成功后
        func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
            NSLog("\(String(describing: peripheral.name)) 连接成功")
            let uuid = CBUUID(string: "18F0")
            peripheral.discoverServices([uuid])
            
            scanDelegateDict.forEach { (_,delegate) in
                delegate.bluetoothConnected(name: name)
            }
        }
    
        /// 断开连接后
        func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
            NSLog("\(String(describing: peripheral.name)) 连接断开")
            scanDelegateDict.forEach { (_,delegate) in
                delegate.bluetoothDisconnect(name: name)
            }
            isConnected = false
        }
    
        /// 扫描设备的services
        func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
            if let service = peripheral.services?[0]{
                let uuid = CBUUID(string: "2AF1")
                peripheral.discoverCharacteristics([uuid], for: service)
                self.service = service
            }
        }
        
        /// 扫描service的characteristics
        func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
            if let characteristic = service.characteristics?[0]{
                NSLog("characteristic is prepared")
                isConnected = true
                self.characteristic = characteristic
            }
        }
    
        /// 输出字符串
        func writeText(text:String)throws{
            let enc = CFStringConvertEncodingToNSStringEncoding(CFStringEncoding(CFStringEncodings.GB_18030_2000.rawValue))
    
            if let data = text.data(using: String.Encoding(rawValue: enc)){
                do {
                   try self.writeData(data: data)
                } catch  {
                    throw error
                }
            }
        }
        
        /// 输出二进制
        func writeBytes(){
            
        }
        
        private var lock = NSLock()
        private var isWritering = false
        
        private var tempData = Data()
        
        private var datas = [Data]()
        
        /// 写入数据
        func writeData(data:Data) throws {
            if(isConnected){
    //            lock.lock(before: Date())
                tempData.append(data)
                datas.append(data)
            }else{
                throw BtError.NoConnectError
            }
        }
        
        /// 真实的打印方法
        func print(){
    //        NSLog("printdata : \(tempData)")
            for index in 0 ... datas.count - 1  {
                let item = datas[index]
                runDelay(0.02 * Double(index), {
                    self.peripheral.writeValue(item, for: self.characteristic, type: CBCharacteristicWriteType.withoutResponse)
                })
            }
            self.datas.removeAll()
        }
        
        private func _realWriterData(data:Data) {
            if(isConnected){
                NSLog("real write data : \(data)")
                self.peripheral.writeValue(data, for: self.characteristic, type: CBCharacteristicWriteType.withoutResponse)
            }else{
                
            }
        }
    }
    
    enum BtError :Error{
        case NoConnectError
    }
    
    

    后记

    这里的代码是我测试项目中使用的,因为是我独立开发,所以有的代码比较乱,敬请见谅

    蓝牙打印机连接本身不算什么高深的操作,只是其中的回调比较复杂,看起来麻烦,这里我也没讲什么概念性的东西,主要就是讲解下代码和实现步骤啥的
    搞清楚了蓝牙外设提供的服务有什么,如何连接,另外需要注意的是CBCharacteristicWriteType.withoutResponse,还有一个有回应的是,这里就看蓝牙设备本身如何设定的了
    这里读取暂时没涉及到,有需要的同学自己研究下吧
    最后祝大家都能顺利的完成自己的蓝牙连接!!

    相关文章

      网友评论

        本文标题:swift 连接 BLE 蓝牙打印机

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