iOS端实现类CTS的GATT服务器同步Accu-Chek Instant设备时间的异常问题求助
各位开发者朋友好,我现在在开发一款iOS应用,核心需求是让Accu-Chek Instant血糖仪同步iPhone的系统时间。我原本计划通过实现**Current Time Service(CTS,标准UUID 1805)和Current Time特征(标准UUID 2A2B)**的GATT服务器,让血糖仪主动读取或订阅时间数据,但过程中遇到了两个棘手的问题,想请大家帮忙排查。
问题1:使用16位标准UUID添加服务失败
一开始我直接用16位标准UUID创建服务和特征,调用peripheralManager.add(service)时立刻报错:
Failed to add service: Error Domain=CBErrorDomain Code=8 "The specified UUID is not allowed for this operation."
换成标准128位UUID格式(比如CTS的128位UUID为00001805-0000-1000-8000-00805F9B34FB)后,服务能成功添加,也能正常启动广播,但新的问题又来了。
问题2:设备连接后,GATT服务器代理方法完全不触发
Accu-Chek设备成功连接到我的GATT服务器后,didReceiveRead、didSubscribeToCharacteristic这些关键代理方法从未被触发——看起来设备根本没有尝试访问我提供的Current Time特征。
我做的排查工作
为了定位原因,我扫描了Accu-Chek Instant设备自身暴露的服务,发现它并没有使用标准CTS服务,而是包含以下几个服务:
SERVICE: Glucose
- Characteristic UUID: 2A18 — Properties: 16
- Characteristic UUID: 2A51 — Properties: 2
- Characteristic UUID: 2A52 — Properties: 40
- Characteristic UUID: 2A08 — Properties: 2
SERVICE: Device Information
- Characteristic UUID: 2A23 — Properties: 2
- Characteristic UUID: 2A24 — Properties: 2
- Characteristic UUID: 2A25 — Properties: 2
- Characteristic UUID: 2A26 — Properties: 2
- Characteristic UUID: 2A29 — Properties: 2
- Characteristic UUID: 2A2A — Properties: 2
- Characteristic UUID: 2A50 — Properties: 2
SERVICE: 00000000-0000-1000-1000-000000000000
- Characteristic UUID: 00000000-0000-1000-1000-000000000011 — Properties: 40
其中最后一个自定义服务里的00000000-0000-1000-1000-000000000011特征是专门用于写入时间的,我之前直接调用peripheral.writeValue(timeData, for: dateTimeCharacteristic, type: .withResponse)能成功完成时间同步,但这种方式是客户端主动推送,我更希望通过模拟CTS服务让设备主动拉取时间。
我的GATT服务器实现代码
以下是我当前的核心实现代码,采用标准128位UUID:
import CoreBluetooth class TimeGATTServer: NSObject { var peripheralManager: CBPeripheralManager! // 标准128位UUID格式的CTS服务与特征 let timeServiceUUID = CBUUID(string: "00001805-0000-1000-8000-00805F9B34FB") let currentTimeCharacteristicUUID = CBUUID(string: "00002A2B-0000-1000-8000-00805F9B34FB") private var timeService: CBMutableService! var currentTimeCharacteristic: CBMutableCharacteristic! // 广播配置 let deviceName = "AccuCheckTimeServer" var connectedCentral: CBCentral? override init() { super.init() let options: [String: Any] = [ CBPeripheralManagerOptionShowPowerAlertKey: true, CBPeripheralManagerOptionRestoreIdentifierKey: "com.clario.accucheckserver", ] peripheralManager = CBPeripheralManager(delegate: self, queue: nil, options: options) } // MARK: - 服务初始化 func setupService() { // 移除已有服务 if let service = timeService { peripheralManager.remove(service) } timeService = CBMutableService(type: timeServiceUUID, primary: true) currentTimeCharacteristic = CBMutableCharacteristic( type: currentTimeCharacteristicUUID, properties: [.read, .indicate, .notify], value: nil, permissions: [.readable, .writeable] ) timeService.characteristics = [currentTimeCharacteristic] peripheralManager.add(timeService) } // MARK: - 广播控制 func startAdvertising() { peripheralManager.stopAdvertising() let advertisementData: [String: Any] = [ CBAdvertisementDataServiceUUIDsKey: [timeServiceUUID], CBAdvertisementDataLocalNameKey: deviceName, CBAdvertisementDataManufacturerDataKey: Data([0x00, 0x01]) // 模拟厂商ID ] peripheralManager.startAdvertising(advertisementData) } func stopAdvertising() { peripheralManager.stopAdvertising() print("Stopped advertising") } } // MARK: - CBPeripheralManagerDelegate extension TimeGATTServer: CBPeripheralManagerDelegate { func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) { switch peripheral.state { case .poweredOn: print("蓝牙已开启 - 初始化服务") setupService() case .poweredOff: print("蓝牙已关闭") stopAdvertising() default: print("蓝牙状态变更: \(peripheral.state.rawValue)") } } func peripheralManager(_ peripheral: CBPeripheralManager, didAdd service: CBService, error: Error?) { if let error = error { print("添加服务失败: \(error)") return } print("服务添加成功 - 开始广播") DispatchQueue.global().asyncAfter(deadline: .now() + 1.0) { self.startAdvertising() } } func peripheralManagerDidStartAdvertising(_ peripheral: CBPeripheralManager, error: Error?) { if let error = error { print("广播失败: \(error)") } else { print("正在广播") } } // 以下两个代理方法从未被触发 func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveRead request: CBATTRequest) { print("收到读取请求: \(request.characteristic.uuid)") // 读取逻辑待实现 } func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didSubscribeTo characteristic: CBCharacteristic) { print("中心设备订阅特征: \(characteristic.uuid)") // 订阅逻辑待实现 } }
想请教的问题
- 为什么使用16位标准CTS UUID会报错“不允许该操作”?iOS对标准GATT服务的使用有什么特殊限制吗?
- 换成128位标准UUID后,设备能连接但不触发代理方法,是不是Accu-Chek Instant设备根本不会识别标准CTS服务,只会和它自身的自定义时间特征交互?如果是这样,我是不是只能放弃模拟CTS,转而实现匹配它自定义服务的GATT服务器?
- 我的GATT服务器实现有没有明显的错误,导致连接后无法触发代理方法?
麻烦各位帮忙分析一下,非常感谢!
内容来源于stack exchange

