You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS端实现类CTS的GATT服务器同步Accu-Chek Instant设备时间的异常问题求助

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)")
        // 订阅逻辑待实现
    }
}

想请教的问题

  1. 为什么使用16位标准CTS UUID会报错“不允许该操作”?iOS对标准GATT服务的使用有什么特殊限制吗?
  2. 换成128位标准UUID后,设备能连接但不触发代理方法,是不是Accu-Chek Instant设备根本不会识别标准CTS服务,只会和它自身的自定义时间特征交互?如果是这样,我是不是只能放弃模拟CTS,转而实现匹配它自定义服务的GATT服务器?
  3. 我的GATT服务器实现有没有明显的错误,导致连接后无法触发代理方法?

麻烦各位帮忙分析一下,非常感谢!

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 12:14:32