标准升级流程
标准升级流程(Normal/Standard OTA Upgrade)是 JL_OTALib 中基于 JL_OTAManager 的常规固件升级链路:设备在正常模式下通过 BLE 连接,完成特性查询、固件分包下发、进度上报、单备份回连与重启收尾,是整个 OTA SDK 最基础、使用最广泛的升级方式。
目的与范围
本文档详细说明「标准升级流程」这一目录项所对应的完整能力:JL_OTAManager 及其代理协议 JL_OTAManagerDelegate、全部状态/结果枚举、标准升级的分步控制流、数据收发机制、配置属性、API 参考以及失败处理。
本文档不涉及以下属于兄弟页面的能力:
- 4G 升级流程:由
JL4GUpgradeManager(cmdStartUpgrade4G:Data:)实现的蜂窝网络升级,见 JL4GUpgradeManager.h。 - 强制升级:本文只覆盖
JL_OtaStatusNormal的正常升级;JL_OtaStatusForce、耳机单备份强制升级(JL_OtaHeadsetYES)、手表资源强制升级(JL_OtaWatchYES)涉及额外的前置条件与回连逻辑,仅在相关枚举处提及。 - BLE 连接管理:
JLBleManager负责扫描/连接/认证,本文只将其作为升级流程的底层通道引用。 - 文件系统与 Flash 操作:
JL_FileManager、JL_FlashOperateManager属于独立能力。
概述
OTA(Over-The-Air)升级是蓝牙设备(耳机、音箱、手表等)固件更新的核心能力。JL_OTAManager 是 SDK 提供给上层应用的升级编排器(Orchestrator):它本身不直接持有 BLE 连接,而是通过两个方向与业务层协作:
- 上行:业务层把设备回传的数据通过
cmdOtaDataReceive:喂给管理器; - 下行:管理器通过必选代理方法
otaDataSend:把待发送指令/固件分包交给业务层,由业务层经 BLE 发出。
这种「管理器-代理」的解耦设计,使得 SDK 不依赖具体蓝牙框架(CoreBluetooth 或厂商私有封装),业务层可以自由控制连接生命周期,同时 SDK 内部专注于升级协议状态机:查询特性 → 判定升级类型 → 分包下发 → 校验 → 单备份回连 → 重启。
标准升级流程的典型触发场景:
- App 检测到设备固件版本(
versionFirmware)低于服务器下发版本; - 用户在设备详情页点击「立即升级」;
- 设备从普通工作模式进入升级流程(区别于强制升级/4G 升级)。
架构
flowchart TD
subgraph sg_App["App 应用层"]
Demo["业务层 / Demo"]
BleMgr["JLBleManager(BLE 连接与收发)"]
end
subgraph sg_OTASDK["JL_OTALib SDK 层"]
OtaMgr["JL_OTAManager(单例)"]
Delegate["JL_OTAManagerDelegate 回调"]
end
subgraph sg_Device["设备端"]
Device["蓝牙设备(耳机 / 音箱 / 手表)"]
end
Demo -->|"配置 UUID/名称/delegate"| OtaMgr
Demo --> BleMgr
BleMgr -->|"noteEntityConnected / cmdOtaDataReceive"| OtaMgr
OtaMgr -->|"otaDataSend 待发送数据"| BleMgr
OtaMgr --> Delegate
BleMgr -->|"BLE 读写通道"| Device
Device -->|"ACK / 状态 / 回连"| BleMgr
架构说明:
- 业务层负责 BLE 连接管理(
JLBleManager)与升级 UI/业务编排,它既是JL_OTAManager的配置方,也是其代理回调的接收方。 JL_OTAManager是单例(getOTAManager),内部维护升级状态机、分包序号(mCmdSN)、已传字节数(otaSent)与总长度(otaLength)。- 代理回调中
otaDataSend:为必选方法,是 SDK 输出数据的唯一出口;otaUpgradeResult:Progress:、otaFeatureResult:、otaCancel为可选方法,用于向 UI 层汇报进度与结果。 - 设备端与 App 之间始终是 BLE 链路;标准升级中可能发生「断开 → 按 UUID/MAC 回连」以切换至升级模式。
核心组件与关键枚举
JL_OTAManager(升级管理对象)
JL_OTAManager 对外暴露的属性可分为三类:
| 类别 | 属性 | 说明 |
|---|---|---|
| 设备标识 | mBLE_UUID / mBLE_NAME | 需要开发者填入的设备 UUID 与名称 |
| 设备能力 | bleOnly / bleAddr | 是否仅支持 BLE、蓝牙地址 |
| 升级参数 | otaStatus / otaHeadset / otaWatch / otaPartition / bootloaderType | 升级类型、耳机单备份、手表资源、单/双备份、是否需要 BootLoader |
| 回连配置 | otaReconnectType | UUID 回连或 MAC 地址回连 |
| 传输统计 | otaLength(只读)/ otaSent(只读) | 设备通知的升级内容总大小 / 已传输大小 |
| 协议状态 | mCmdSN / version / versionFirmware | 指令序号、设备版本号、设备版本信息 |
设计意图:设备能力属性(otaPartition、otaStatus 等)不是开发者凭空填写的,而是由 cmdTargetFeature 查询后 SDK 自动填充——这是「先查询、后升级」安全模型的基础,避免对设备实际能力做任何假设。
JL_OTAManagerDelegate(升级回调代理)
/// OTA 升级管理对象回调
@protocol JL_OTAManagerDelegate <NSObject>
/// 即将被发送的数据
/// @param data 数据内容
- (void)otaDataSend:(NSData *_Nonnull)data;
@optional
/// 回调设备状态信息
/// @param manager 对象状态
- (void)otaFeatureResult:(JL_OTAManager *_Nonnull)manager;
/// 回调升级状态以及进度等
/// @param result 状态以及进度信息
/// @param progress 进度信息
- (void)otaUpgradeResult:(JL_OTAResult)result Progress:(float)progress;
/// 取消OTA升级
- (void)otaCancel;
@end
Source: JL_OTAManager.h
设计意图:otaDataSend: 被声明为 @required,因为 SDK 的所有下行数据(特性查询指令、固件分包、重启指令)都必须经由业务层转发到 BLE 通道;缺少该实现,升级链路将完全无法工作。其余三个方法均为可选,业务层按需实现即可。
标准升级核心流程
标准升级在 SDK 视角是一条明确的协议状态机。以下时序图展示了从连接、查询到完成重启的完整链路(以单备份升级为例,双备份设备会跳过回连阶段):
sequenceDiagram
participant App as App 业务层
participant Mgr as JL_OTAManager
participant BLE as BLE 通道
participant Dev as 设备
App->>Mgr: getOTAManager 获取单例
App->>Mgr: 配置 mBLE_UUID / mBLE_NAME / delegate
BLE-->>Mgr: 连接成功(认证完成)
App->>Mgr: noteEntityConnected
App->>Mgr: cmdTargetFeature(连上后第一步)
Mgr->>BLE: 下发特性查询指令
BLE-->>Mgr: 设备特性数据(cmdOtaDataReceive)
Mgr-->>App: otaFeatureResult(填充 otaStatus/otaPartition 等)
App->>Mgr: cmdOTAData:Result:(标准升级数据)
loop 分包传输
Mgr->>App: otaDataSend(业务层经 BLE 发出)
BLE-->>Mgr: 设备 ACK / 数据(cmdOtaDataReceive)
Mgr-->>App: otaUpgradeResult:Progress:(进度上报)
end
alt 单备份(JL_PartitionSingle)
Mgr-->>App: JL_OTAResultReconnect / ReconnectWithMacAddr
App->>Mgr: cmdOtaDataIIResult(回连成功后再次发起)
end
Mgr-->>App: otaUpgradeResult JL_OTAResultSuccess
App->>Mgr: cmdRebootDevice
阶段一:初始化与连接
- 通过
[JL_OTAManager getOTAManager]获取单例(头文件明确标注init已废弃,见 JL_OTAManager.h); - 填入
mBLE_UUID、mBLE_NAME,设置delegate,并按需调用maxLostCount:(默认丢包上限为 2 次); - 设备完成 BLE 认证后,调用
noteEntityConnected告知 SDK 连接就绪。
阶段二:特性查询(强制前置步骤)
头文件注释明确规定:cmdTargetFeature 所有情况下都需要执行,而且是在连上后(认证完成)第一步执行(JL_OTAManager.h)。
该查询决定后续升级路径:
otaStatus→ 正常升级(JL_OtaStatusNormal)还是强制升级(JL_OtaStatusForce);otaPartition→ 单备份(JL_PartitionSingle,需回连)还是双备份(JL_PartitionDouble);otaHeadset/otaWatch→ 耳机、手表资源是否强制升级;bootloaderType→ 是否需要先下载 BootLoader;otaReconnectType→ 回连方式按 UUID 还是 MAC 地址。
查询结果通过可选代理 otaFeatureResult: 回调,业务层在该回调中决定是否具备升级条件(例如电量、版本比较)。
阶段三:发起升级与分包传输
调用 cmdOTAData:Result: 传入升级数据(固件文件内容),SDK 内部:
- 解析固件信息,校验与设备版本/SN 的匹配性;
- 若校验失败,通过
JL_OTA_RT回调返回JL_OTAResultFailVerification、JL_OTAResultFailSameSN或JL_OTAResultFailKey等错误; - 校验通过后进入分包下发循环:每一包数据经必选代理
otaDataSend:交给业务层发送,业务层收到设备回包后调用cmdOtaDataReceive:喂回 SDK; - 进度通过
otaUpgradeResult:Progress:持续上报(progress为 0.0 ~ 1.0 的浮点值)。
传输过程中 otaSent(已传输字节)与 otaLength(总大小)属性可随时读取,用于 UI 展示。
阶段四:单备份回连(可选分支)
- 双备份设备:直接进入完成阶段;
- 单备份设备:SDK 会先通知
JL_OTAResultReconnect(UUID 回连)或JL_OTAResultReconnectWithMacAddr(MAC 回连),设备断开并重启进入升级模式;业务层完成重连后,调用cmdOtaDataIIResult:(头文件注明「单备份升级特有!!!」)再次发起升级,该接口可在回连成功后复用已缓存的升级数据(JL_OTAManager.h)。可用cmdOtaIsRelinking查询是否正在回连。
阶段五:完成与重启
收到 JL_OTAResultSuccess 后,调用 cmdRebootDevice 让设备重启到新固件;若设备卡死可调用 cmdRebootForceDevice 强制重启。一次完整的升级会话结束后,调用 resetOTAManager 清理内部状态,为下一次升级做准备。
状态机总览
stateDiagram-v2
[*] --> Idle: 初始化 getOTAManager
Idle --> Connected: noteEntityConnected
Connected --> FeatureQuery: cmdTargetFeature
FeatureQuery --> Ready: otaFeatureResult
Ready --> Upgrading: cmdOTAData
Upgrading --> Relinking: 单备份 需回连
Relinking --> Upgrading: cmdOtaDataIIResult
Upgrading --> Success: JL_OTAResultSuccess
Success --> Reboot: cmdRebootDevice
Upgrading --> Failed: JL_OTAResult 失败码
Failed --> Idle: resetOTAManager
Reboot --> Idle
数据收发机制
SDK 与 BLE 通道之间的数据交换是理解整个升级流程的关键:
- 下行(SDK → 设备):
JL_OTAManagerDelegate.otaDataSend:(必选)。业务层在实现中应调用蓝牙写入接口(如JLBleManager的写特征方法)将data发出。 - 上行(设备 → SDK):
cmdOtaDataReceive:。业务层在蓝牙特征回调中收到数据后,原样传给管理器;管理器内部按协议解析 ACK、状态与升级模式切换通知。 - 日志开关:
logSendData:可打印 SDK 发送的数据内容,便于联调;logSDKVersion(类方法)返回 SDK 版本号,排查问题时用于对齐版本。
使用示例
以下示例均取自 JL_OTAManager.h 的真实接口声明,并按其文档语义组织为标准升级的典型调用序列。
初始化与配置
/// 获取 OTA 升级对象
+ (JL_OTAManager *)getOTAManager;
/// 设备UUID(需要开发者填入)
@property(strong, nonatomic) NSString *mBLE_UUID;
/// 设备名称(需要开发者填入)
@property(strong, nonatomic) NSString *mBLE_NAME;
/// 设备交互回调代理
@property(weak, nonatomic) id<JL_OTAManagerDelegate> delegate;
/// 当BLE连接上时告知SDK
- (void)noteEntityConnected;
Source: JL_OTAManager.h
特性查询 → 发起标准升级
/// 查询设备OTA信息
/// 所有情况下都需要执行,而且是在连上后(认证完成)第一步执行
- (void)cmdTargetFeature;
/// 开始OTA升级
/// @param data 升级数据
/// @param result 升级结果
- (void)cmdOTAData:(NSData *)data
Result:(JL_OTA_RT __nullable)result;
/// OTA升级II
/// 单备份升级特有!!!!
/// 此接口可用于 OTA 回连成功后,再次发起升级使用
/// @param result 升级结果回调
- (void)cmdOtaDataIIResult:(JL_OTA_RT __nullable)result;
/// 重启设备
- (void)cmdRebootDevice;
Source: JL_OTAManager.h
实现代理回调
@protocol JL_OTAManagerDelegate <NSObject>
/// 即将被发送的数据
/// @param data 数据内容
- (void)otaDataSend:(NSData *_Nonnull)data;
@optional
/// 回调设备状态信息
/// @param manager 对象状态
- (void)otaFeatureResult:(JL_OTAManager *_Nonnull)manager;
/// 回调升级状态以及进度等
/// @param result 状态以及进度信息
/// @param progress 进度信息
- (void)otaUpgradeResult:(JL_OTAResult)result Progress:(float)progress;
/// 取消OTA升级
- (void)otaCancel;
@end
Source: JL_OTAManager.h
调用语义:otaDataSend: 中把 data 写入 BLE 特征;otaUpgradeResult:Progress: 中根据 result 更新进度条或展示失败原因(JL_OTAResult 枚举见下文失败模式表);otaFeatureResult: 中检查 manager.otaStatus、manager.otaPartition 等属性决定升级策略。
配置选项
JL_OTAManager 的属性即升级流程的全部可配置项(无独立配置文件):
| 属性 | 类型 | 默认/初始值 | 说明 |
|---|---|---|---|
mBLE_UUID | NSString | nil(需填入) | 设备 UUID,开发者必须填写 |
mBLE_NAME | NSString | nil(需填入) | 设备名称,开发者必须填写 |
bleOnly | BOOL | NO | 是否仅支持 BLE |
bleAddr | NSString | nil | 蓝牙 MAC 地址 |
mCmdSN | uint8_t | 0 | 指令序号(SDK 内部自增维护) |
version | uint16_t | 0 | 设备版本号 |
versionFirmware | NSString | nil | 设备版本信息 |
otaStatus | JL_OtaStatus | JL_OtaStatusNormal | 正常/强制升级,由特性查询填充 |
otaHeadset | JL_OtaHeadset | JL_OtaHeadsetNO | 耳机单备份是否强制升级 |
otaWatch | JL_OtaWatch | JL_OtaWatchNO | 手表资源是否强制升级 |
otaPartition | JL_Partition | JL_PartitionSingle | 单/双备份,决定是否回连 |
bootloaderType | JL_BootLoader | JL_BootLoaderNO | 是否需要下载 BootLoader |
otaReconnectType | JL_OTAReconnectType | JL_OTAReconnectTypeUUID | 回连方式(UUID / MAC) |
otaLength | int64_t(只读) | 0 | 设备通知的升级内容总大小 |
otaSent | uint32_t(只读) | 0 | 已传输的数据大小 |
delegate | id<JL_OTAManagerDelegate> | nil | 交互回调代理 |
方法级配置:maxLostCount: 设置最大丢包次数(默认 2);logSendData: 开关发送数据打印(默认关闭)。
API 参考
+ (JL_OTAManager *)getOTAManager
获取全局唯一的 OTA 升级管理对象。init 已被标记为废弃(deprecated("Please use getOTAManager instead.")),禁止自行创建实例。
- (void)noteEntityConnected
BLE 连接并认证完成后调用,告知 SDK 连接就绪。
- (void)noteEntityDisconnected
BLE 断开时调用,告知 SDK 连接已断开(SDK 据此处理 JL_OTAResultDisconnect 等状态)。
- (void)cmdTargetFeature
必选第一步。查询设备 OTA 信息(升级类型、单/双备份、BootLoader 需求、回连方式),结果经 otaFeatureResult: 回调。
- (void)cmdSystemFunction
仅当设备需要挂载外置 Flash 才能正常升级时执行,其他情况无需调用。
- (void)cmdOTAData:(NSData *)data Result:(JL_OTA_RT)result
发起标准 OTA 升级。data 为升级固件数据;result 为升级结果回调块,参数为 (JL_OTAResult result, float progress)。
- (void)cmdOtaDataIIResult:(JL_OTA_RT)result
单备份升级特有。回连成功后再次发起升级(复用已缓存升级数据)。
- (BOOL)cmdOtaIsRelinking
查询 OTA 单备份是否正在回连。
- (void)cmdOTACancelResult:(JL_OTA_RESULT)result
取消升级,result 回调中 status 为 0x00 表示取消成功;取消后 SDK 可能回调 JL_OTAResultCancel。
- (void)cmdRebootDevice / - (void)cmdRebootForceDevice
正常/强制重启设备,用于升级完成后的收尾。
- (void)resetOTAManager
重置 OTA 管理器内部状态,一次完整升级会话结束后调用。
- (void)cmdOtaDataReceive:(NSData *)data
设备端数据入口,业务层收到 BLE 特征数据后原样传入。
- (void)maxLostCount:(int)count
设置最大丢包次数(默认 2),用于弱网场景下的重传策略。
- (void)logSendData:(BOOL)status / + (NSString *)logSDKVersion
调试辅助:打印发送数据、获取 SDK 版本号。
回调块类型:JL_OTA_RT = void (^)(JL_OTAResult result, float progress);JL_OTA_RESULT = void (^)(uint8_t status, uint8_t sn, NSData *data)。
失败模式与边界情况
JL_OTAResult 枚举(JL_OTAManager.h)完整定义了标准升级中可能出现的全部结果码,业务层应逐项映射为 UI 提示:
| 结果码 | 值 | 含义 | 处理建议 |
|---|---|---|---|
JL_OTAResultSuccess | 0x00 | 升级成功 | 调用 cmdRebootDevice 收尾 |
JL_OTAResultFail | 0x01 | 升级失败 | 展示失败,resetOTAManager |
JL_OTAResultDataIsNull | 0x02 | 升级数据为空 | 检查固件文件读取 |
JL_OTAResultCommandFail | 0x03 | 指令失败 | 重试或检查设备状态 |
JL_OTAResultSeekFail | 0x04 | 标示偏移查找失败 | 检查固件包合法性 |
JL_OTAResultInfoFail | 0x05 | 固件信息错误 | 检查固件包与设备型号匹配 |
JL_OTAResultLowPower | 0x06 | 设备电压低 | 提示用户充电后再升级 |
JL_OTAResultEnterFail | 0x07 | 未能进入升级模式 | 重新连接后重试 |
JL_OTAResultUpgrading | 0x08 | 升级中 | 等待完成 |
JL_OTAResultReconnect | 0x09 | 需重连(UUID 方式) | 单备份回连触发,等待重连 |
JL_OTAResultReboot | 0x0a | 需设备重启 | 等待重启 |
JL_OTAResultPreparing | 0x0b | 准备中 | 等待 |
JL_OTAResultPrepared | 0x0f | 准备完成 | 可发起升级 |
JL_OTAResultStatusIsUpdating | 0x10 | 设备已在升级中 | 避免重复发起 |
JL_OTAResultFailedConnectMore | 0x11 | 多台设备连接 | 提示用户断开其他设备 |
JL_OTAResultFailSameSN | 0xe0 | SN 多次重复校验失败 | 检查固件/设备 SN |
JL_OTAResultCancel | 0xe1 | 升级取消 | 用户主动取消 |
JL_OTAResultFailVerification | 0xf1 | 升级数据校验失败 | 重新获取固件 |
JL_OTAResultFailCompletely | 0xf2 | 升级失败 | 重试 |
JL_OTAResultFailKey | 0xf3 | 加密 Key 不对 | 检查固件加密配置 |
JL_OTAResultFailErrorFile | 0xf4 | 升级文件出错 | 检查固件包完整性 |
JL_OTAResultFailUboot | 0xf5 | uboot 不匹配 | 检查 BootLoader 配置 |
JL_OTAResultFailLenght | 0xf6 | 长度出错 | 检查固件包 |
JL_OTAResultFailFlash | 0xf7 | Flash 读写失败 | 设备硬件问题 |
JL_OTAResultFailCmdTimeout | 0xf8 | 指令超时 | 结合 maxLostCount: 重试 |
JL_OTAResultFailSameVersion | 0xf9 | 相同版本 | 提示用户已是最新版本 |
JL_OTAResultFailTWSDisconnect | 0xfa | TWS 耳机未连接 | 提示连接双耳 |
JL_OTAResultFailNotInBin | 0xfb | 耳机未在充电仓 | 提示放入充电仓 |
JL_OTAResultReconnectWithMacAddr | 0xfc | 需重连(MAC 方式) | 按 MAC 回连 |
JL_OTAResultDisconnect | 0xfd | 设备断开 | 检查连接 |
JL_OTAResultUnknown | 0xfe | 未知错误 | 兜底处理 |
典型边界场景:
- 单备份回连失败:
JL_OTAResultReconnect之后设备未按时出现,业务层应结合noteEntityDisconnected与超时机制提示用户重新靠近设备。 - 重复升级:设备已在升级中(
JL_OTAResultStatusIsUpdating)时再次调用cmdOTAData:会被拒绝,应等待当前会话结束。 - 多设备并发连接:
JL_OTAResultFailedConnectMore明确要求用户手动断开另一台设备,标准流程不支持多设备同时升级。 - 低电量保护:
JL_OTAResultLowPower表明设备端主动拒绝升级,属于安全设计,避免升级中途断电变砖。
并发与状态一致性
- 单例模型:
JL_OTAManager通过getOTAManager保证全局唯一,天然规避多实例并发升级;但这也意味着同一时刻只能有一个设备处于升级流程。 - 指令序号:
mCmdSN由 SDK 内部管理,保证请求/应答配对;业务层不应手动修改。 - 数据喂入顺序:
cmdOtaDataReceive:必须在收到 BLE 数据后及时调用,乱序或丢失会导致校验失败或指令超时(JL_OTAResultFailCmdTimeout)。 - 状态清理:升级完成或失败后务必调用
resetOTAManager,否则残留状态可能影响下一次cmdTargetFeature的结果判断。
性能与运维建议
- 丢包控制:
maxLostCount:默认 2 次;弱网环境可适当调大,但过大会放大传输时延,需按产品场景权衡。 - 进度上报:
otaUpgradeResult:Progress:的progress与otaSent/otaLength均可用于进度条;为避免 UI 频繁刷新,建议业务层做节流(例如每 1% 刷新一次)。 - 日志:联调阶段开启
logSendData:(发送数据打印)与logSDKVersion(版本核对),可快速定位是协议问题还是 BLE 通道问题;上线版本建议关闭发送日志以降低开销。 - 升级时长:大固件(如手表资源)分包传输时间长,期间应保持 BLE 连接稳定、屏幕常亮,必要时提示用户保持 App 在前台。
扩展点
- 代理协议扩展:
JL_OTAManagerDelegate是唯一的业务扩展接口;新增可选方法不影响现有实现(Objective-C 协议可选方法特性)。 - 升级类型切换:通过
otaStatus/otaHeadset/otaWatch可在查询后切换至强制升级等变体流程,标准升级的「查询 → 下发 → 回连 → 重启」骨架对变体同样适用。 - BootLoader 支持:
bootloaderType = JL_BootLoaderYES时,流程会插入 BootLoader 下载阶段,开发者无需感知细节,仅需在查询结果后按 SDK 指示推进。