STM32 blueNRG蓝牙设备名称更新后iOS端显示异常问题咨询
为什么iOS设备必须连接断开蓝牙设备后才会显示更新后的名称?
这个问题我之前帮朋友排查过类似的,本质是iOS系统层面的蓝牙缓存机制,再加上你当前设备端的名称更新逻辑没做全导致的,我来拆解清楚:
核心原因:iOS的蓝牙广告数据缓存
iOS的CoreBluetooth框架会在系统级别缓存它发现的蓝牙设备的关键信息——包括广播包(Advertisement Data)里的设备名称、设备UUID等。这个缓存不是跟着APP走的,是存在系统蓝牙服务里的:
- 当你的设备第一次被iPhone发现时,iOS会把当时广播的
oldName存进缓存; - 哪怕你后续更新了设备的GATT名称特征,只要设备广播包没同步更新新名称,iOS在扫描时还是会优先用缓存里的旧名称,不会主动去校验广播包的新内容;
- 只有当iPhone与设备建立连接后,CoreBluetooth会从GATT服务里获取到最新的设备名称,这时候系统才会更新缓存里的名称数据,下次扫描时就会显示新名称了。
你的实验场景也完全贴合这个逻辑:
- iPhone1连接断开后,系统缓存更新为
newName,所以后续扫描能看到新名称; - iPhone2从未连接过,系统一直用第一次缓存的
oldName,直到连接后才触发缓存更新。
你设备端的遗漏:只更新了GATT特征,没更新广播包名称
你现在只通过aci_gatt_update_char_value更新了GATT服务里的设备名称特征,但蓝牙设备的广播包和GATT特征是两个独立的名称来源:
- iOS扫描时优先读取广播包里的
Local Name字段; - 只有当广播包里没有这个字段,或者连接后,才会读取GATT里的设备名称特征。
所以要解决这个问题,你需要在设备端同时更新两个地方的名称:
1. 保留现有GATT特征更新逻辑(已实现)
继续使用你当前的代码更新GATT设备名称特征:
aci_gatt_update_char_value(service_handle, dev_name_char_handle, 0, strlen(name), (uint8_t *)name);
2. 同步更新广播包的本地名称
在blueNRG固件里,需要调用对应API更新广播数据中的本地名称,比如用aci_gap_update_advertising_data或者重新设置可发现模式时传入新名称:
// 假设name是你要设置的新名称 uint8_t adv_data[31]; uint8_t adv_len = 0; // 构造包含本地名称的广播数据 adv_data[adv_len++] = 1 + strlen(name); adv_data[adv_len++] = 0x09; // 标识这是本地名称的AD类型 memcpy(&adv_data[adv_len], name, strlen(name)); adv_len += strlen(name); // 更新广播数据 aci_gap_update_advertising_data(adv_len, adv_data); // 或者重新设置可发现模式,确保广播时携带新名称 aci_gap_set_discoverable(ADV_IND, 0, 0, PUBLIC_ADDR, NO_WHITE_LIST_USE, adv_len, adv_data, 0, NULL, 0, 0);
这样设备重启后,广播包会直接发送新名称,iOS扫描时就能直接获取到newName,不需要先连接断开了。
额外说明:iOS缓存的特殊情况
如果遇到缓存顽固不更新的极端情况,用户可以在iPhone的「设置-蓝牙」里找到设备,点击「忽略此设备」,再重新扫描就能获取最新的广播数据,但这是用户端的操作,我们作为设备开发者,还是应该通过同步更新广播和GATT名称来从根源解决问题。
内容的提问来源于stack exchange,提问作者Vitaly
相关产品推荐
相关产品推荐

