iOS 通信协议—— 蓝牙通信

编程入门 行业动态 更新时间:2024-10-24 14:25:16

iOS 通信协议—— <a href=https://www.elefans.com/category/jswz/34/1768306.html style=蓝牙通信"/>

iOS 通信协议—— 蓝牙通信

这几天小伙伴又给我提了一个新需求,要求给他们的项目提供一个iOS端的蓝牙通信App,虽然iOS也做过一些,Objective C和Swift多少也知道一些,不过并没有深入的研究过iOS的开发,为了节省工期囫囵吞枣的看了一些资料,像之前那篇文章一样,我这里就不舞大刀,我把我参考的资料就放在下面这里,你如果需要可以去看看。

《[iOS/swift]蓝牙连接》

Github代码仓库:MichaelLynx/BleDemo

《Swift CoreBluetooth 蓝牙库》

我参考这些资料和代码的基础上,重写了其中一部分代码,并且做了一定的封装,你可以直接复制黏贴,并且在自己的工程里使用。版本为Swift的,不使用Objective C是因为觉得写起来比较浪费时间,而且如果遇到了需要和底层数据打交到的地方,我依然可以用Objective C做封装就好了。

首先是这个BluetoothLowEnergy类的实现。

//
//  BluetoothLowEnergyHandler.swift
//  PetoiSerialSwift
//
//  Created by Orlando Chen on 2021/3/23.
//import Foundation
import CoreBluetoothclass BluetoothLowEnergy: NSObject {// 一个蓝牙设备当中可能包含多个信道,一个UUID就是一个信道标记var uuids: [CBCharacteristic] = []// 中心对象var central : CBCentralManager!// 把中心设备扫描的外置设备保存起来var deviceList: [CBPeripheral] = []// 接收到的数据var peripheralData: Data?// MARK: 0. 初始化override init() {super.init()// 初始化中心设备管理器// 它的delegate函数为centralManagerDidUpdateState// 其回调消息处理函数为:centralManagerself.central = CBCentralManager.init(delegate:self, queue:nil, options:[CBCentralManagerOptionShowPowerAlertKey:false])// 初始化设备列表self.deviceList = []}// MARK: 1. 扫描设备func startScanPeripheral(serviceUUIDS: [CBUUID]?,options: [String: AnyObject]?) {// 清空列表deviceList = []  // 清空设备列表uuids = [] // 清空信道列表// 开始进行扫描self.central?.scanForPeripherals(withServices: serviceUUIDS, options: options)}// MARK: 2. 停止扫描func stopScanPeripheral() {self.central?.stopScan()}// MARK: 3.1. 获取搜索到的外接设备func getPeripheralList()-> [CBPeripheral] {return deviceList}// MARK: 3.2. 获取到当前蓝牙设备可用的消息信道func getCharacteristic() -> [CBCharacteristic] {return uuids}// MARK: 3.3. 指定监听信道func setNotifyCharacteristic(peripheral: CBPeripheral, notify: CBCharacteristic) {peripheral.setNotifyValue(true, for: notify)}// MARK: 4.1. 连结设备// 连接设备之前要先设置代理,正常情况,当第一次获取外设peripheral的时候就会同时设置代理func connect(peripheral: CBPeripheral) {if (peripheral.state != CBPeripheralState.connected) {central?.connect(peripheral , options: nil)// 将外接设备的回掉函数连结到self// 回掉消息处理函数为:peripheralperipheral.delegate = self}}// MARK: 4.2. 检测是否建立了连结func isConnected(peripheral: CBPeripheral) -> Bool {return peripheral.state == CBPeripheralState.connected}// MARK: 5.1. 发送数据func sendData(data: Data, peripheral: CBPeripheral, characteristic: CBCharacteristic,type: CBCharacteristicWriteType = CBCharacteristicWriteType.withResponse) {let step = 20for index in stride(from: 0, to: data.count, by: step) {var len = data.count - indexif len > step {len = step}let pData: Data = (data as NSData).subdata(with: NSRange(location: index, length: len))peripheral.writeValue(pData, for: characteristic, type: type)}}// MARK: 5.2. 接收数据func recvData() -> Data {return peripheralData ?? Data([0x00])}// MARK: 6. 断开连结func disconnect(peripheral: CBPeripheral) {central?.cancelPeripheralConnection(peripheral)}
}extension BluetoothLowEnergy: CBCentralManagerDelegate {// MARK: 检查运行这个App的设备是不是支持BLE。func centralManagerDidUpdateState(_ central: CBCentralManager) {switch central.state {case .poweredOn:NSLog("BLE poweredOn")case .poweredOff:NSLog("BLE powered off")case .unknown:NSLog("BLE unknown")case .resetting:NSLog("BLE ressetting")case .unsupported:NSLog("BLE unsupported")case .unauthorized:NSLog("BLE unauthorized")@unknown default:NSLog("BLE default")}}// MARK: 以ANCS协议请求的端,授权状态发生改变func centralManager(_ central: CBCentralManager, didUpdateANCSAuthorizationFor peripheral: CBPeripheral) {
//        NSLog("\(#file) \(#line) \(#function)\n central:\(central)\n peripheral:\(peripheral)")// TODO}// MARK: 状态的保存或者恢复func centralManager(_ central: CBCentralManager, willRestoreState dict: [String : Any]) {
//        NSLog("\(#file) \(#line) \(#function)\n central:\(central)\n peripheral:\(dict)")// TODO}// MARK:func centralManager(_ central: CBCentralManager, connectionEventDidOccur event: CBConnectionEvent, for peripheral: CBPeripheral) {
//        NSLog("\(#file) \(#line) \(#function)\n central:\(central)\n  peripheral:\(peripheral)")// TODO}// 开始扫描之后会扫描到蓝牙设备,扫描到之后走到这个代理方法// MARK: 中心管理器扫描到了设备func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {//        NSLog("\(#file) \(#line) \(#function)\n central:\(central)\n peripheral:\(peripheral)")guard !deviceList.contains(peripheral), let deviceName = peripheral.name, deviceName.count > 0 else {return}// 把设备加入到列表中deviceList.append(peripheral)// TODO}// MARK: 连接外设成功,开始发现服务func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
//        NSLog("\(#file) \(#line) \(#function)\n central:\(central)\n peripheral:\(peripheral)")// 设置代理peripheral.delegate = self// 开始发现服务peripheral.discoverServices(nil)}// MARK: 连接外设失败func centralManager(_ central: CBCentralManager, didFailToConnect peripheral:CBPeripheral, error: Error?) {
//        NSLog("\(#file) \(#line) \(#function)\n central:\(central)\n peripheral:\(String(describing: peripheral.name))\n error:\(String(describing: error))")// TODO}// MARK: 连接丢失func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {//        NSLog("\(#file) \(#line) \(#function)\n central:\(central)\n peripheral:\(String(describing: peripheral.name))\n  error:\(String(describing: error))")// TODO}
}// MARK: 外置设备被绑定后的事件响应
extension BluetoothLowEnergy: CBPeripheralDelegate {// MARK: 匹配对应服务UUIDfunc peripheral(_ peripheral: CBPeripheral,didDiscoverServices error: Error?) {if error != nil { // failed
//            NSLog("\(#file) \(#line) \(#function)\n peripheral:\(String(describing: peripheral.name))\n error:\(String(describing: error))")return}//        NSLog("\(#file) \(#line) \(#function)\n peripheral:\(String(describing: peripheral.name))")for service in peripheral.services ?? [] {peripheral.discoverCharacteristics(nil, for: service)}}// MARK: 服务下的特征func peripheral(_ peripheral: CBPeripheral,didDiscoverCharacteristicsFor service:CBService, error: Error?) {if error != nil { // failed
//            NSLog("\(#file) \(#line) \(#function)\n peripheral:\(String(describing: peripheral.name))\n service:\(String(describing: service))\n error:\(String(describing: error))")return}//        NSLog("\(#file) \(#line) \(#function)\n peripheral:\(String(describing: peripheral.name))\n service:\(String(describing: service))")for characteristic in service.characteristics ?? [] {uuids.append(characteristic)}}// MARK: 获取外设发来的数据// 注意,所有的,不管是 read , notify 的特征的值都是在这里读取func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {if error != nil {
//            NSLog("\(#file) \(#line) \(#function)\n peripheral:\(String(describing: peripheral.name))\n characteristic:\(String(describing: characteristic.description))\n error:\(String(describing: error))")return}//        NSLog("\(#file) \(#line) \(#function)\n peripheral:\(String(describing: peripheral.name))\n characteristic:\(String(describing: characteristic.description))")if let data = characteristic.value {self.peripheralData = data}}//MARK: 检测中心向外设写数据是否成功func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {if let error = error {
//            NSLog("\(#file) \(#line) \(#function)\n peripheral:\(String(describing: peripheral.name))\n characteristic:\(String(describing: characteristic.description))\n error:\(String(describing: error))")}// TODO}
}

所有的NSlog都是可以根据需要打开,方便调试使用的。TODO部分是你可以在上面进一步扩展的地方,当然修改原代码也是可以的。

至于如何使用?

首先,在iOS工程需要先在plist增加

Privacy - Bluetooth Always Usage Description

然后在某个类里实例化这个BLE类,如果是全局都需要进行蓝牙数据传输,那么就把这个类实例在AppDelegate文件里,并且设置为静态,这样就可以全局使用了。

用户需要具体调用的几个函数如下:

// MARK: 1. 扫描设备
func startScanPeripheral(serviceUUIDS: [CBUUID]?, options: [String: AnyObject]?) // MARK: 2. 停止扫描
func stopScanPeripheral()// MARK: 3. 获取搜索到的外接设备
func getPeripheralList()-> [CBPeripheral] // MARK: 4.1. 连结设备
func connect(peripheral: CBPeripheral)// MARK: 4.2. 检测是否建立了连结
func isConnected(peripheral: CBPeripheral) -> Bool// MARK: 4.3. 获取到当前蓝牙设备可用的消息信道
func getCharacteristic() -> [CBCharacteristic]// MARK: 4.4. 指定监听信道
func setNotifyCharacteristic(peripheral: CBPeripheral, notify: CBCharacteristic)// MARK: 5.1. 发送数据
func sendData(data: Data, peripheral: CBPeripheral, characteristic: CBCharacteristic, type: CBCharacteristicWriteType = CBCharacteristicWriteType.withResponse) // MARK: 5.2. 接收数据
func recvData() -> Data // MARK: 6. 断开连结
func disconnect(peripheral: CBPeripheral)

由于蓝牙设备的通信过程是一个异步过程,等价于创建了一个后台线程对数据服务进行监听,所以如果对于音频流这一类实时会接受大量数据的应用,你可能需要增加一个标记或者其他方式以便处理,具体处理函数为

func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?)

只不对对于文本数据,这个代码已经足够使用了,比较简单的一种处理方法,就是用个定时器,每隔几十毫秒查询一次数据;而比较实时的处理方法,就是做一个回调函数,不过这些都由你自己决定怎么做吧,好运!

更多推荐

iOS 通信协议—— 蓝牙通信

本文发布于:2024-02-26 17:11:10,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1703275.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:蓝牙   通信协议   通信   iOS

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!