Swift连接BLE蓝牙打印机
文章目录
swift 蓝牙连接
项目简介
最近公司要用到便携式蓝牙打印机进行打印
打印机使用的 ECS/POS 指令集
ios 使用的 BLE 方案,安卓则是因为设备的原因只能选择普通蓝牙的连接方案
BLE 蓝牙相关的概念性东西我这里就不说了 大家可以自己去搜索下
有个 mac 的蓝牙开发工具 LightBlue,很好用,mac app store 自己下就好了,这个很方便你理解 BLE 的蓝牙相关
device(central/peripheral)->services->characteristics
这里可以看到,有一个 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 中
使用
1import CoreBluetooth
这样CBCentralManager
终于可以用了
正式开发
折腾了半天,终于可以开始开发了...
macos 模拟器蓝牙 central
这里要吐槽下公司,没有 ios 测试机,我自己又是安卓手机,没办法,这里有一招,建一个 macos 的项目,将UIKit
换成Cocoa
,或者Foundation
,然后其他语法中 macos 和 ios 的蓝牙部分代码几乎一样,这样就能连接上打印机了,我这里又是模块开发,将数据部分的代码 copy 一份到 macos 的 demo 上,就能模拟真机的 mac 了
上面说几乎一样的原因是,cm.isScanning
在 mac 开发中用不了,ios 中可以
当时记得苹果说 simulator 可以用 mac 的蓝牙开发,结果短短的一个版本以后就干掉了相关功能,真是狗
帮助类的代码
1
2//
3// BluetoothHelper.swift
4// SwiftBluetoothScanDemo1
5//
6// Created by caijinglong on 2017/9/9.
7//
8
9import Foundation
10import CoreBluetooth
11
12protocol BluetoothHelperDelegate {
13
14 func bluetoothHelperIndex()->Int
15
16 func bluetoothHelperNotifyConnected(isConnected:Bool)
17
18 func bluetoothHelperAutoStopScan()
19}
20
21class BluetoothHelper :NSObject,CBCentralManagerDelegate,CBPeripheralDelegate{
22
23 static let shared = BluetoothHelper()
24
25 private var cm:CBCentralManager! = nil
26 private var peripheral: CBPeripheral! = nil
27 private var service:CBService! = nil
28
29 private var characteristic:CBCharacteristic! = nil
30
31 private var delegateDict = Dictionary<Int,BluetoothHelperDelegate>()
32
33 public func registerDelegate(delegate:BluetoothHelperDelegate){
34 delegateDict[delegate.bluetoothHelperIndex()] = delegate
35 }
36
37 public func unregisterDelegate(delegate:BluetoothHelperDelegate){
38 delegateDict.removeValue(forKey: delegate.bluetoothHelperIndex())
39 }
40
41 private override init(){
42 super.init()
43 self.cm = CBCentralManager(delegate: self, queue: nil)
44 }
45
46 /// 被连接的打印机的名字
47 var connectDeviceName:String? = ""
48
49 /// 是否连接了打印机
50 var isConnected:Bool = false{
51 didSet{
52 if(!isConnected){
53 peripheral = nil
54 service = nil
55 characteristic = nil
56 connectDeviceName = nil
57
58 delegateDict.forEach({ (key,delegate) in
59
60 })
61 }else{
62 connectDeviceName = self.name
63 }
64 }
65 }
66
67 /// 蓝牙开关是否打开
68 var btOpen = false
69 private var name = "QSPrinter"
70
71 // 后面是代理方法
72 func centralManagerDidUpdateState(_ central: CBCentralManager) {
73 NSLog("状态变化")
74 if(central.state.rawValue == 5){
75 btOpen = true
76 }else{
77 btOpen = false
78 isConnected = false
79 }
80 }
81
82 /// 开始扫描设备
83 func startScan(name:String){
84 self.name = name
85 self.cm.stopScan()
86 self.cm.scanForPeripherals(withServices: nil, options: nil)
87 runDelay(5) {
88 self.delegateDict.forEach({ (_,delegate) in
89 self.cm.stopScan()
90 delegate.bluetoothHelperAutoStopScan()
91 })
92 }
93 }
94
95 /// 停止扫描设备
96 func stopScan(){
97 self.cm.stopScan()
98 }
99
100 /// 关闭连接设备
101 func disconnect(){
102 if(peripheral != nil){
103 self.cm.cancelPeripheralConnection(peripheral)
104 }
105 }
106
107 func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) {
108 NSLog("\(String(describing: peripheral.name)) is discovered")
109 if(peripheral.name?.uppercased() == name.uppercased()){
110 self.peripheral = peripheral
111 peripheral.delegate = self
112 cm.connect(peripheral)
113 cm.stopScan()
114 }
115 }
116
117 func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
118 NSLog("\(String(describing: peripheral.name)) 连接成功")
119 let uuid = CBUUID(string: "18F0")
120 peripheral.discoverServices([uuid])
121 }
122
123 func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
124 NSLog("\(String(describing: peripheral.name)) 连接断开")
125 isConnected = false
126 }
127
128 func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
129 if let service = peripheral.services?[0]{
130 let uuid = CBUUID(string: "2AF1")
131 peripheral.discoverCharacteristics([uuid], for: service)
132 self.service = service
133 }
134 }
135
136 func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
137 if let characteristic = service.characteristics?[0]{
138 NSLog("characteristic is prepared")
139 isConnected = true
140 self.characteristic = characteristic
141 }
142 }
143
144 /// 输出字符串
145 func writeText(text:String)throws{
146 let enc = CFStringConvertEncodingToNSStringEncoding(CFStringEncoding(CFStringEncodings.GB_18030_2000.rawValue))
147
148 if let data = text.data(using: String.Encoding(rawValue: enc)){
149 do {
150 try self.writeData(data: data)
151 } catch {
152 throw error
153 }
154 }
155 }
156
157
158 private var datas = [Data]()
159
160 /// 写入数据
161 func writeData(data:Data) throws {
162 if(isConnected){
163 datas.append(data)
164 }else{
165 throw BtError.NoConnectError
166 }
167 }
168
169 /// 真实的打印方法
170 func print(){
171 for index in 0 ... datas.count - 1 {
172 let item = datas[index]
173 runDelay(0.02 * Double(index), {
174 self.peripheral.writeValue(item, for: self.characteristic, type: CBCharacteristicWriteType.withoutResponse)
175 })
176 }
177 self.datas.removeAll()
178 }
179
180}
181
182enum BtError :Error{
183 case NoConnectError
184}
分析下代码 这里使用单例的方案管理连接,实际上 BLE 支持同时连接多个外设,我这里是因为目前没有这样的需求,所以考虑使用单例的模式,看官请根据自己的需求来
centralManagerDidUpdateState
这个代理方法很重要,是唯一一个必须实现的方法,用于监听蓝牙的状态,是一个 Int 类型的枚举值,这里因为 ios10 有一个过期相关的提示,替换了 state 相关的类由CBCentralManagerState
替换到CBManagerState
,值没有变化,就是由 oc 的枚举方式替换到了 swift 的枚举,这里我直接使用 5 来进行判断,ios11 也没看见修改这个数值,短时间内直接用 5 就行,后续有 bug 再说
这里用一个 property 来储存蓝牙状态
startScan
其中是开始扫描的方法
1 func startScan(name:String){
2 self.name = name
3 self.cm.stopScan()
4 self.cm.scanForPeripherals(withServices: nil, options: nil)
5 runDelay(5) {
6 self.delegateDict.forEach({ (_,delegate) in
7 self.cm.stopScan()
8 delegate.bluetoothHelperAutoStopScan()
9 })
10 }
11 }
先停止扫描,然后开始扫描,记录一下 name,后续会用到,5 秒后停止扫描,并代理通知
1func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) {
2 NSLog("\(String(describing: peripheral.name)) is discovered")
3 if(peripheral.name?.uppercased() == name.uppercased()){
4 self.peripheral = peripheral
5 peripheral.delegate = self
6 cm.connect(peripheral)
7 cm.stopScan()
8 }
9 }
10
11 func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
12 NSLog("\(String(describing: peripheral.name)) 连接成功")
13 let uuid = CBUUID(string: "18F0")
14 peripheral.discoverServices([uuid])
15 }
这两个方法,第一个是扫描到了设备,这里我忽视大小写进行匹配,然后如果名字匹配则调用cm.connect(peripheral)
进行连接,并且停止扫描
第二个方法是连接成功,这里 18F0 是 service 的名称,就是扫描 UUID 为 18F0 的 services
1 func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
2 if let service = peripheral.services?[0]{
3 let uuid = CBUUID(string: "2AF1")
4 peripheral.discoverCharacteristics([uuid], for: service)
5 self.service = service
6 }
7 }
这里是在扫描到 services 后的代理,然后扫描 uuid 为2AF1
的 Characteristics
这里 service 保持引用
1func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
2 if let characteristic = service.characteristics?[0]{
3 NSLog("characteristic is prepared")
4 isConnected = true
5 self.characteristic = characteristic
6 }
7 }
这里是扫描到 Characteristics 后的操作,这里我记录了一个连接状态 和 characteristic 的引用
1self.peripheral.writeValue(item, for: self.characteristic, type: CBCharacteristicWriteType.withoutResponse)//item是Data
这个是真实的输出方法,这个输出方法使用了了之前的peripheral
和characteristic
这里之所以要持有所有'中间'产物的引用是因为之前用 oc 写这个代码的时候因为没有持有 peripheral 的引用报错,导致代理获取不到数据
详细分析写数据
这里我使用了一个方案来写
1 /// 输出字符串
2 func writeText(text:String)throws{
3 let enc = CFStringConvertEncodingToNSStringEncoding(CFStringEncoding(CFStringEncodings.GB_18030_2000.rawValue))
4
5 if let data = text.data(using: String.Encoding(rawValue: enc)){
6 do {
7 try self.writeData(data: data)
8 } catch {
9 throw error
10 }
11 }
12 }
13
14
15 private var datas = [Data]()
16
17 /// 写入数据
18 func writeData(data:Data) throws {
19 if(isConnected){
20 datas.append(data)
21 }else{
22 throw BtError.NoConnectError
23 }
24 }
25
26 /// 真实的打印方法
27 func print(){
28 for index in 0 ... datas.count - 1 {
29 let item = datas[index]
30 runDelay(0.02 * Double(index), {
31 self.peripheral.writeValue(item, for: self.characteristic, type: CBCharacteristicWriteType.withoutResponse)
32 })
33 }
34 self.datas.removeAll()
35 }
1func runDelay(_ delay:TimeInterval,_ block:@escaping () -> ()){
2 let queue = DispatchQueue.main
3
4 let delayTime = DispatchTime.now() + delay
5
6 queue.asyncAfter(deadline: delayTime) {
7 block()
8 }
9}
这里的思路大概是:
首先一个容器用于储存顺序存入的数据,然后在调用print
的时候将所有数据进行输出,并且延迟一定的时间,每个输出时间间隔 0.02s
之所以这么做的原因是:我当时直接调用writeValue
方法写数据,没有间隔时间,发现会出现样式错误,输出顺序错误的情况发生
这个时候我凭感觉认为是发生了writeValue
和实际通讯的到达顺序不一致的问题,我查了下,BLE 主打的是低延迟,但是对应的数据通讯的数据量就有了限制,所以采用这个方案
当然我也试过使用一个 Data 储存所有字节数据的方案,发现打印机无法打印,具体原因没有深究
打印相关
编码问题
一般的蓝牙打印机中文使用的是 GBK 编码,ios 中是 GB_18030_2000,而 ios 默认是 utf8 编码,所以这里需要显示指定
关于二维码
打印二维码使用的是 ESC/POS 的指令集,这个在指令集的说明文档中可以找到
这里的 moduleSize 是二维码的大小,具体参数可以参考说明文档,一般对接的打印机厂商都会提供
一般的打印机中文都是 GBK 编码的,而扫码一般是 UTF8 编码,这个编码转换很麻烦,所以尽量不要出现中文
打印机发送指令
1//
2// PrinterHelper.swift
3// SwiftBluetoothScanDemo1
4//
5// Created by Caijinglong on 2017/9/11.
6//
7
8import Foundation
9
10/// printer helper
11///
12/// single instance
13class PrinterHelper{
14
15 static var shared:PrinterHelper = PrinterHelper()
16
17 var helper : BluetoothHelper!
18
19 // var devices = [Printer]()
20
21 private init(){
22 helper = BluetoothHelper.shared
23 }
24
25 func registerDelegate(delegate: BluetoothHelperDelegate){
26 helper.registerDelegate(delegate: delegate)
27 }
28
29 func unregisterDelegate(delegate: BluetoothHelperDelegate){
30 helper.unregisterDelegate(delegate: delegate)
31 }
32
33 var index = 0
34
35 let DIVIDER = "-----------------------------------------------"
36 let ESC: Byte = 27//换码
37 let FS: Byte = 28//文本分隔符
38 let GS: Byte = 29//组分隔符
39 let DLE: Byte = 16//数据连接换码
40 let EOT: Byte = 4//传输结束
41 let ENQ: Byte = 5//询问字符
42 let SP: Byte = 32//空格
43 let HT: Byte = 9//横向列表
44 let LF: Byte = 10//打印并换行(水平定位)
45 let CR: Byte = 13//归位键
46 let FF: Byte = 12//走纸控制(打印并回到标准模式(在页模式下)
47 let CAN: Byte = 24//作废(页模式下取消打印数据 )
48
49 func conn(deviceName:String){
50 helper.startScan(name: deviceName)
51 }
52
53 func disconnect(){
54 helper.disconnect()
55 }
56
57 func sendMsg(msg:String) -> Self{
58 try? helper.writeText(text: msg)
59 return self
60 }
61
62 func sendBytes(bytes:[Byte]) -> Self{
63 try? helper.writeData(data: Data.bytesArray(byteArray: bytes))
64 return self
65 }
66
67 func sendHex(int:Int) -> Self {
68 return self.sendHexs(hexInt: int)
69 }
70
71 func sendHexs(hexInt ints:Int...) -> Self{
72 var data = Data()
73 ints.forEach { (int) in
74 data.append(UInt8(int))
75 }
76 try? helper.writeData(data: data)
77 return self
78 }
79
80 func sendBytes(bytes:Byte...) -> Self{
81 return sendBytes(bytes: bytes)
82 }
83
84 func alignLeft()-> Self{
85 return sendBytes(bytes: ESC,97,0)
86 }
87
88 func alignCenter() -> Self {
89 return sendBytes(bytes: ESC,97,1)
90 }
91
92 func alignRight() -> Self{
93 return sendBytes(bytes: ESC,97,2)
94 }
95
96 func printDivider() -> Self {
97 return sendMsg(msg: DIVIDER)
98 }
99
100
101 func startPrint(){
102 helper.print()
103 }
104
105 func setFontSize(size:Int) -> Self{
106 var realSize: Byte = 0
107
108 if(size <= 7){
109 realSize = Byte(size * 17)
110 }
111
112 var result = [Byte]()
113 result.append(0x1D)
114 result.append(0x21)
115 result.append(realSize)
116 print("size = \(size) realSize = \(realSize)")
117 return sendBytes(bytes: result)
118 }
119
120 func newLine(lines:Int = 1) -> Self{
121 for _ in 0...lines - 1{
122 _ = sendHex(int: 0x0A)
123 }
124 return self
125 }
126
127 /**
128 * 选择加粗模式
129
130 * @return
131 */
132 func boldOn() -> Self {
133 var result = [Byte]()
134 result.append(ESC)
135 result.append(69)
136 result.append(0xF)
137 return sendBytes(bytes: result)
138 }
139
140
141 /**
142 * 取消加粗模式
143
144 * @return
145 */
146 func boldOff() -> Self {
147 var result = [Byte]()
148 result.append(ESC)
149 result.append(69)
150 result.append(0)
151 return sendBytes(bytes: result)
152 }
153
154 func subTitle(_ title:String) -> Self{
155 return
156 self.newLine()
157 .setFontSize(size: 1)
158 .boldOn()
159 .alignCenter()
160 .sendMsg(msg: title)
161 .setFontSize(size: 0)
162 .boldOff()
163 }
164
165 func sendQrcode(qrcode:String) -> Self{
166 let moduleSize:Byte = 8
167 var list = [Byte]()
168
169 if let data = Data.gbkData(text: qrcode){
170
171 //打印二维码矩阵
172 list.append(0x1D)// init
173 list.append(40) // adjust height of barcode
174 list.append(107)// adjust height of barcode
175 list.append(Byte(data.count + 3)) // pl
176 list.append(0) // ph
177 list.append(49) // cn
178 list.append(80) // fn
179 list.append(48) //
180
181 data.forEach({ (char) in
182 list.append(char)
183 })
184
185 list.append(0x1D)
186 list.append(40)// list.append("(k")
187 list.append(107)// list.append("(k")
188 list.append(3)
189 list.append(0)
190 list.append(49)
191 list.append(69)
192 list.append(48)
193
194 list.append(0x1D)
195 list.append(40)// list.append("(k")
196 list.append(107)// list.append("(k")
197 list.append(3)
198 list.append(0)
199 list.append(49)
200 list.append(67)
201 list.append(moduleSize)
202
203 list.append(0x1D)
204 list.append(40)// list.append("(k")
205 list.append(107)// list.append("(k")
206 list.append(3) // pl
207 list.append(0) // ph
208 list.append(49) // cn
209 list.append(81) // fn
210 list.append(48) // m
211 }
212
213 return
214 alignCenter()
215 .sendBytes(bytes: list)
216 }
217}
蓝牙连接的类
1//
2// BluetoothHelper.swift
3// SwiftBluetoothScanDemo1
4//
5// Created by caijinglong on 2017/9/9.
6// Copyright © 2017 sxw. All rights reserved.
7//
8
9import Foundation
10import CoreBluetooth
11
12protocol BluetoothHelperDelegate:NSObjectProtocol {
13
14 func bluetoothHelperIndex()->Int
15
16 func bluetoothHelperNotifyConnected(isConnected:Bool)
17
18 func bluetoothHelperAutoStopScan()
19
20 func bluetoothHelperFindDevices(name:String)
21}
22
23extension BluetoothHelperDelegate{
24 func bluetoothHelperFindDevices(name:String){
25 }
26}
27
28protocol BluetoothHelperScanDeviceDelegate {
29 func bluetoothScan(peripheral: CBPeripheral)
30
31 func bluetoothHelperIndex()->Int
32
33 func bluetoothConnected(name:String)
34
35 func bluetoothDisconnect(name:String)
36}
37
38extension BluetoothHelperScanDeviceDelegate{
39 func bluetoothConnected(name:String){}
40
41 func bluetoothDisconnect(name:String){}
42}
43
44class BluetoothHelper :NSObject,CBCentralManagerDelegate,CBPeripheralDelegate{
45
46 static let shared = BluetoothHelper()
47
48 private var cm:CBCentralManager! = nil
49 private var peripheral: CBPeripheral! = nil
50 private var service:CBService! = nil
51
52 private var characteristic:CBCharacteristic! = nil
53
54 private var delegateDict = Dictionary<Int,BluetoothHelperDelegate>()
55
56 private var scanDelegateDict = Dictionary<Int,BluetoothHelperScanDeviceDelegate>()
57
58 public func registerDelegate(delegate:BluetoothHelperDelegate){
59 delegateDict[delegate.bluetoothHelperIndex()] = delegate
60 }
61
62 public func unregisterDelegate(delegate:BluetoothHelperDelegate){
63 delegateDict.removeValue(forKey: delegate.bluetoothHelperIndex())
64 }
65
66 public func registerScanDelegate(delegate:BluetoothHelperScanDeviceDelegate){
67 scanDelegateDict[delegate.bluetoothHelperIndex()] = delegate
68 }
69
70 public func unregisterScanDelegate(delegate:BluetoothHelperScanDeviceDelegate){
71 delegateDict.removeValue(forKey: delegate.bluetoothHelperIndex())
72 }
73
74 private override init(){
75 super.init()
76 self.cm = CBCentralManager(delegate: self, queue: nil)
77 }
78
79 /// 被连接的打印机的名字
80 var connectDeviceName:String? = ""
81
82 /// 是否连接了打印机
83 var isConnected:Bool = false{
84 didSet{
85 if(!isConnected){
86 peripheral = nil
87 service = nil
88 characteristic = nil
89
90 delegateDict.forEach({ (key,delegate) in
91 delegate.bluetoothHelperNotifyConnected(isConnected: false)
92 })
93 connectDeviceName = nil
94 }else{
95 connectDeviceName = self.name
96
97 delegateDict.forEach({ (key,delegate) in
98 delegate.bluetoothHelperNotifyConnected(isConnected: true)
99 })
100 }
101 }
102 }
103
104 /// 蓝牙开关是否打开
105 var btOpen = false
106 private var name = "QSPrinter"
107
108 // 后面是代理方法
109 func centralManagerDidUpdateState(_ central: CBCentralManager) {
110 NSLog("状态变化: state = \(central.state.rawValue)")
111 if(central.state.rawValue == 5){
112 btOpen = true
113 }else{
114 btOpen = false
115 isConnected = false
116 }
117 }
118
119 /// 仅扫描
120 func startScan(){
121 self.name = ""
122 self.cm.stopScan()
123 self.cm.scanForPeripherals(withServices: nil, options: nil)
124 runDelay(5) {
125 self.delegateDict.forEach({ (_,delegate) in
126 delegate.bluetoothHelperAutoStopScan()
127 })
128 }
129 }
130
131 /// 开始扫描设备
132 func startScan(name:String){
133 self.name = name
134 self.cm.stopScan()
135 self.cm.scanForPeripherals(withServices: nil, options: nil)
136 runDelay(5) {
137 self.delegateDict.forEach({ (_,delegate) in
138 self.cm.stopScan()
139 delegate.bluetoothHelperAutoStopScan()
140 })
141 }
142 }
143
144 /// 停止扫描设备
145 func stopScan(){
146 self.cm.stopScan()
147 }
148
149 /// 关闭连接设备
150 func disconnect(){
151 if(peripheral != nil){
152 self.cm.cancelPeripheralConnection(peripheral)
153 }
154 }
155
156 /// 扫描到设备
157 func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) {
158 NSLog("\(String(describing: peripheral.name)) is discovered")
159 if(peripheral.name == nil){
160 return
161 }
162
163 scanDelegateDict.forEach { (_,delegate) in
164 delegate.bluetoothScan(peripheral: peripheral)
165 }
166
167
168 if(self.name.isEmpty){
169 return
170 }
171
172 if(peripheral.name?.uppercased() == name.uppercased()){
173 self.connect(peripheral: peripheral)
174 }
175 }
176
177 /// 连接peripheral
178 func connect(peripheral:CBPeripheral){
179 self.peripheral = peripheral
180 peripheral.delegate = self
181 cm.connect(peripheral)
182 cm.stopScan()
183 }
184
185 /// 连接成功后
186 func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
187 NSLog("\(String(describing: peripheral.name)) 连接成功")
188 let uuid = CBUUID(string: "18F0")
189 peripheral.discoverServices([uuid])
190
191 scanDelegateDict.forEach { (_,delegate) in
192 delegate.bluetoothConnected(name: name)
193 }
194 }
195
196 /// 断开连接后
197 func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
198 NSLog("\(String(describing: peripheral.name)) 连接断开")
199 scanDelegateDict.forEach { (_,delegate) in
200 delegate.bluetoothDisconnect(name: name)
201 }
202 isConnected = false
203 }
204
205 /// 扫描设备的services
206 func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
207 if let service = peripheral.services?[0]{
208 let uuid = CBUUID(string: "2AF1")
209 peripheral.discoverCharacteristics([uuid], for: service)
210 self.service = service
211 }
212 }
213
214 /// 扫描service的characteristics
215 func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
216 if let characteristic = service.characteristics?[0]{
217 NSLog("characteristic is prepared")
218 isConnected = true
219 self.characteristic = characteristic
220 }
221 }
222
223 /// 输出字符串
224 func writeText(text:String)throws{
225 let enc = CFStringConvertEncodingToNSStringEncoding(CFStringEncoding(CFStringEncodings.GB_18030_2000.rawValue))
226
227 if let data = text.data(using: String.Encoding(rawValue: enc)){
228 do {
229 try self.writeData(data: data)
230 } catch {
231 throw error
232 }
233 }
234 }
235
236 /// 输出二进制
237 func writeBytes(){
238
239 }
240
241 private var lock = NSLock()
242 private var isWritering = false
243
244 private var tempData = Data()
245
246 private var datas = [Data]()
247
248 /// 写入数据
249 func writeData(data:Data) throws {
250 if(isConnected){
251// lock.lock(before: Date())
252 tempData.append(data)
253 datas.append(data)
254 }else{
255 throw BtError.NoConnectError
256 }
257 }
258
259 /// 真实的打印方法
260 func print(){
261// NSLog("printdata : \(tempData)")
262 for index in 0 ... datas.count - 1 {
263 let item = datas[index]
264 runDelay(0.02 * Double(index), {
265 self.peripheral.writeValue(item, for: self.characteristic, type: CBCharacteristicWriteType.withoutResponse)
266 })
267 }
268 self.datas.removeAll()
269 }
270
271 private func _realWriterData(data:Data) {
272 if(isConnected){
273 NSLog("real write data : \(data)")
274 self.peripheral.writeValue(data, for: self.characteristic, type: CBCharacteristicWriteType.withoutResponse)
275 }else{
276
277 }
278 }
279}
280
281enum BtError :Error{
282 case NoConnectError
283}
## 后记 这里的代码是我测试项目中使用的,因为是我独立开发,所以有的代码比较乱,敬请见谅
蓝牙打印机连接本身不算什么高深的操作,只是其中的回调比较复杂,看起来麻烦,这里我也没讲什么概念性的东西,主要就是讲解下代码和实现步骤啥的
搞清楚了蓝牙外设提供的服务有什么,如何连接,另外需要注意的是 CBCharacteristicWriteType.withoutResponse,还有一个有回应的是,这里就看蓝牙设备本身如何设定的了
这里读取暂时没涉及到,有需要的同学自己研究下吧
最后祝大家都能顺利的完成自己的蓝牙连接!!