JL_OTALib 固件升级
JL_OTALib 是杰理科技(JieLi)面向 iOS/macOS 平台的蓝牙设备固件升级(OTA)库,封装了从固件文件解析、OTA 能力查询、数据分片传输、断线回连到升级结果回调的完整升级流程。开发者只需通过 JL_OTAManager 单例与几个命令方法即可为耳机、音箱、手表等杰理蓝牙设备实现稳定可靠的固件升级能力。
Purpose and Scope
本页面向 iOS/macOS 开发者,完整说明 JL_OTALib 框架(JL_OTALib.xcframework)在固件升级场景中的职责、架构、核心 API、升级状态机与典型接入方式。内容包括:
- 框架组成与公开头文件(
JL_OTAManager.h、jl_ufw.h、JLOTAFile.h、JLOtaReConnectOption.h、JLOtaCustom.h)的定位; JL_OTAManager单例对象模型、JL_OTAManagerDelegate回调协议与全部枚举定义;- 从连接、查询特性、发起升级、回连续传、进度回调到完成的端到端升级流程;
- 全部
JL_OTAResult错误码、配置项与 API 参考。
不在本页范围:底层 BLE 扫描/连接/认证与 RCSP 数据通道由 JL_BLEKit 负责(详见 JL_BLEKit 相关页面);固件文件的生成与签名属于杰理上位机工具链,本页只涉及文件数据的解析与传输。JL_OTALib 为二进制 XCFramework 分发,本页所有代码示例均摘自其公开头文件。
Overview
库的本质:把"升级协议"封装成对象
JL_OTALib 并不是一个 UI 库,而是一个协议状态机库。它把杰理设备 OTA 升级所涉及的 RCSP 命令交互(查询特性、下发升级指令、数据分片、应答与重传、回连续传、重启设备)全部封装在 JL_OTAManager 内部,对外暴露的是一组"命令"方法与一个"进度/结果"回调。开发者不需要关心底层包格式与分片窗口,只需要:
- BLE 连接成功后,把 UUID、设备名等喂给
JL_OTAManager; - 调用
cmdTargetFeature查询设备 OTA 能力; - 传入固件数据(
.ufw/.dfu文件内容)调用cmdOTAData或cmdUpgrade发起升级; - 在 delegate 回调中接收状态与进度,处理"需要回连""低电压""TWS 未连接"等事件。
关键设计概念
| 概念 | 说明 |
|---|---|
单备份 / 双备份(JL_Partition) | 双备份设备升级失败可自动回滚;单备份设备升级过程需先进入 Boot 模式并回连才能继续传输 |
回连(JL_OTAReconnectType) | 单备份升级时设备会断开并切换广播,SDK 支持按 UUID 或 MAC 地址自动重连 |
BootLoader(JL_BootLoader) | 部分设备需要先下载 BootLoader 才能进入升级态 |
资源升级(JLOtaSourcesExtendMode) | 支持仅升级固件、仅升级资源(UI 音效等)或普通升级三种扩展模式 |
强制升级(JL_OtaStatus / JL_OtaHeadset) | 耳机单备份等场景下,相同版本或特殊设备需要"强制"标志才能升级 |
复用空间 OTA(isSupportReuseSpaceOTA) | 设备是否支持复用存储空间进行 OTA,影响升级数据大小与策略 |
框架分发形态
JL_OTALib.xcframework 包含三个平台切片(来自仓库文件结构):ios-arm64(真机)、ios-arm64_x86_64-simulator(模拟器)、macos-arm64_x86_64(Mac Catalyst/桌面),可在同一工程内同时支持 iOS 与 macOS 目标。框架对外头文件共 5 个,主头文件统一导出:
#import <JL_OTALib/JL_OTAManager.h>
#import <JL_OTALib/jl_ufw.h>
#import <JL_OTALib/JLOTAFile.h>
#import <JL_OTALib/JLOtaReConnectOption.h>
#import <JL_OTALib/JLOtaCustom.h>
Source: JL_OTALib.h
其中 JL_OTAManager.h 是升级核心(本文档重点),jl_ufw.h/JLOTAFile.h 负责解析杰理固件文件格式(JL_UFW 头/分区信息),JLOtaReConnectOption.h 提供回连参数,JLOtaCustom.h 提供自定义升级策略扩展。
Architecture
flowchart TD
subgraph sg_App["应用层(开发者代码)"]
AppUI["业务 App / 升级界面"]
end
subgraph sg_OTALib["JL_OTALib.framework"]
Manager["JL_OTAManager(单例状态机)"]
Delegate["JL_OTAManagerDelegate 回调协议"]
FileParser["JLOTAFile / jl_ufw 固件解析"]
Reconnect["JLOtaReConnectOption 回连参数"]
Custom["JLOtaCustom 自定义升级策略"]
end
subgraph sg_BLE["底层依赖(外部)"]
BLEKit["JL_BLEKit(BLE 连接 / RCSP 通道)"]
LogHelper["JLLogHelper(日志)"]
end
Device["杰理蓝牙设备(耳机 / 音箱 / 手表)"]
AppUI -->|"调用命令方法"| Manager
AppUI -->|"实现并设置"| Delegate
Manager -->|"进度 / 状态回调"| Delegate
Manager --> FileParser
Manager --> Reconnect
Manager -.->|"可配置扩展"| Custom
Manager -->|"RCSP 数据收发"| BLEKit
BLEKit -->|"BLE GATT 读写 / 广播回连"| Device
LogHelper -.->|"日志输出"| Manager
架构说明:JL_OTAManager 是唯一入口与状态机载体,开发者通过单例与之交互;数据通路经由 JL_BLEKit 提供的 RCSP 通道与设备通信;升级结果与进度通过 delegate 异步回抛。JLOTAFile/jl_ufw 在升级前把固件文件解析为 SDK 可用的数据格式;JLOtaReConnectOption 供单备份回连场景定制连接参数;JLOtaCustom 是面向特殊设备的扩展钩子。
核心枚举:升级结果与设备能力
JL_OTAResult(UInt16)——升级状态/结果码
这是整个库最重要的枚举,贯穿 delegate 回调 otaUpgradeResult:Progress: 与各命令的 Result 回调。定义于 JL_OTAManager.h L15-L80:
| 枚举值 | 值 | 含义 |
|---|---|---|
JL_OTAResultSuccess | 0x00 | OTA 升级成功 |
JL_OTAResultFail | 0x01 | OTA 升级失败(通用) |
JL_OTAResultDataIsNull | 0x02 | 升级数据为空 |
JL_OTAResultCommandFail | 0x03 | OTA 指令失败 |
JL_OTAResultSeekFail | 0x04 | OTA 标示偏移查找失败 |
JL_OTAResultInfoFail | 0x05 | 固件信息错误 |
JL_OTAResultLowPower | 0x06 | 设备电压低,拒绝升级 |
JL_OTAResultEnterFail | 0x07 | 未能进入 OTA 升级模式 |
JL_OTAResultUpgrading | 0x08 | OTA 升级中 |
JL_OTAResultReconnect | 0x09 | 需要重连设备(UUID 方式) |
JL_OTAResultReboot | 0x0a | 需要设备重启 |
JL_OTAResultPreparing | 0x0b | OTA 准备中 |
JL_OTAResultPrepared | 0x0f | OTA 准备完成 |
JL_OTAResultStatusIsUpdating | 0x10 | 设备已在升级中 |
JL_OTAResultFailedConnectMore | 0x11 | 多台设备连接,需手动断开另一台 |
JL_OTAResultFailSameSN | 0xe0 | 升级数据校验失败,SN 多次重复 |
JL_OTAResultCancel | 0xe1 | 升级已取消 |
JL_OTAResultFailVerification | 0xf1 | 升级数据校验失败 |
JL_OTAResultFailCompletely | 0xf2 | 升级完全失败 |
JL_OTAResultFailKey | 0xf3 | 加密 Key 不对 |
JL_OTAResultFailErrorFile | 0xf4 | 升级文件出错 |
JL_OTAResultFailUboot | 0xf5 | uboot 不匹配 |
JL_OTAResultFailLenght | 0xf6 | 升级过程长度出错 |
JL_OTAResultFailFlash | 0xf7 | 升级过程 flash 读写失败 |
JL_OTAResultFailCmdTimeout | 0xf8 | 升级过程指令超时 |
JL_OTAResultFailSameVersion | 0xf9 | 固件相同版本 |
JL_OTAResultFailTWSDisconnect | 0xfa | TWS 耳机未连接 |
JL_OTAResultFailNotInBin | 0xfb | 耳机未在充电仓 |
JL_OTAResultReconnectWithMacAddr | 0xfc | 需要重连设备(MAC 方式) |
JL_OTAResultDisconnect | 0xfd | OTA 设备断开 |
JL_OTAResultReconnectUpdateSource | 0xfe | 需要重连设备(更新资源) |
JL_OTAResultUnknown | 0xff | 未知错误 |
设计意图:错误码覆盖了协议层错误(0x01~0x07)、流程状态(0x08~0x11)与数据/设备侧错误(0xe0~0xfe)三组。其中 0x09/0xfc/0xfe 三个"需重连"码是单备份升级回连机制的关键信号,开发者收到后应停止传输、等待 SDK 内部或自行按 UUID/MAC 重连。
设备能力与升级模式枚举
typedef NS_ENUM(UInt8, JL_OTAReconnectType) {
JL_OTAReconnectTypeUUID = 0x00, // OTA升级回连使用uuid
JL_OTAReconnectTypeMACAddr = 0x01, // OTA升级回连使用mac地址
};
typedef NS_ENUM(UInt8, JL_OtaStatus) {
JL_OtaStatusNormal = 0, // 正常升级
JL_OtaStatusForce = 1, // 强制升级
};
typedef NS_ENUM(UInt8, JLOtaSourcesExtendMode) {
JLSourcesExtendModeDisable = 0, // 不启用
JLSourcesExtendModeNormal = 1, // 启用普通资源升级模式
JLSourcesExtendModeSourceOnly = 2, // 启用只升级资源的模式
JLSourcesExtendModeFirmwareOnly = 3, // 启用只升级固件程序的模式
};
typedef NS_ENUM(UInt8, JL_BootLoader) {
JL_BootLoaderNO = 0, // 不需要下载Bootloader
JL_BootLoaderYES = 1, // 需要下载BootLoader
};
typedef NS_ENUM(UInt8, JL_Partition) {
JL_PartitionSingle = 0, // 固件单备份
JL_PartitionDouble = 1, // 固件双备份
};
Source: JL_OTAManager.h
其中 JL_OtaWatch 与 otaWatch 属性已被 __attribute__((deprecated)) 标记废弃,统一改用 JLOtaSourcesExtendMode(otaSourceMode)表达资源升级模式——这反映了库的演进方向:把"手表资源升级"这一单一场景抽象为通用的"固件/资源分离升级"能力。
回调 Block 类型
typedef void (^JL_OTA_RT)(JL_OTAResult result, float progress);
typedef void (^JL_OTA_RESULT)(uint8_t status, uint8_t sn, NSData *__nullable data);
Source: JL_OTAManager.h
JL_OTA_RT:升级进度回调,progress为 0.0~1.0 浮点进度;JL_OTA_RESULT:命令应答回调(主要给取消升级等命令使用),携带命令序号sn与原始应答data。
JL_OTAManager 对象模型
单例获取
/// 获取 OTA 升级对象
+ (JL_OTAManager *)getOTAManager;
/// 不建议使用自行初始化
/// 推荐获取 getOTAManager
- (instancetype)init __attribute__((deprecated("Please use getOTAManager instead.")));
Source: JL_OTAManager.h
getOTAManager 是唯一推荐的获取方式。设计意图:OTA 状态机必须与设备连接生命周期一一对应,单例保证整个 App 内只有一份升级上下文,避免多实例各自维护状态导致指令串扰。
开发者必须填写的属性
| 属性 | 类型 | 说明 |
|---|---|---|
mBLE_UUID | NSString * | 设备 UUID,开发者填入 |
mBLE_NAME | NSString * | 设备名称,开发者填入 |
delegate | id<JL_OTAManagerDelegate> | 交互回调代理 |
由设备特性查询结果填充的属性
| 属性 | 类型 | 说明 |
|---|---|---|
bleOnly | BOOL | 是否仅支持 BLE(不支持经典蓝牙) |
bleAddr | NSString * | BLE 蓝牙地址 |
mCmdSN | uint8_t | SN 值(命令序号) |
version | uint16_t | 设备版本号 |
versionFirmware | NSString * | 设备版本信息字符串 |
otaStatus | JL_OtaStatus | 设备 OTA 状态(正常/强制) |
otaHeadset | JL_OtaHeadset | 耳机单备份是否需要强制升级 |
isSupportReuseSpaceOTA | BOOL | 是否支持复用空间 OTA |
isSupportExpand | BOOL | 是否支持 OTA 拓展功能 |
otaSourceMode | JLOtaSourcesExtendMode | 资源升级模式 |
otaPartition | JL_Partition | 单/双备份 |
bootloaderType | JL_BootLoader | 是否需要下载 BootLoader |
otaReconnectType | JL_OTAReconnectType | 回连方式(UUID/MAC) |
只读进度属性
/// OTA升级内容大小(设备通知的)
@property(assign, nonatomic, readonly) int64_t otaLength;
/// 已传输的数据大小
@property(assign, nonatomic, readonly) uint32_t otaSent;
Source: JL_OTAManager.h
otaLength/otaSent 由设备通知与 SDK 内部计数维护,可用来做 UI 进度条的自定义计算。
JL_OTAManagerDelegate 回调协议
@protocol JL_OTAManagerDelegate <NSObject>
/// 即将被发送的数据
/// @param data 数据内容
- (void)otaDataSend:(NSData *_Nonnull)data;
@optional
/// 回调设备状态信息
- (void)otaFeatureResult:(JL_OTAManager *_Nonnull)manager;
/// 回调升级状态以及进度等
- (void)otaUpgradeResult:(JL_OTAResult)result Progress:(float)progress;
/// 取消OTA升级
- (void)otaCancel;
@end
Source: JL_OTAManager.h
otaDataSend:是唯一必选回调:SDK 将要发送的 RCSP 数据交还给上层,由上层(JL_BLEKit 通道)真正写入 BLE。这是把"协议生成"与"物理发送"解耦的关键设计——库本身不持有蓝牙连接。otaFeatureResult::cmdTargetFeature查询完成后触发,此时可读取设备能力属性并决定升级策略;otaUpgradeResult:Progress::升级过程的主回调,携带JL_OTAResult与 0~1 进度;otaCancel:SDK 收到取消指令后的确认回调。
核心升级流程
端到端时序
sequenceDiagram
participant App as App 开发者
participant M as JL_OTAManager
participant B as JL_BLEKit 通道
participant D as 杰理设备
App->>M: getOTAManager + 填写 mBLE_UUID/mBLE_NAME
App->>M: noteEntityConnected(BLE 已连接并认证完成)
App->>M: cmdTargetFeature(第一步,查询OTA能力)
M->>B: 发送 RCSP 特性查询命令
B->>D: GATT 写入
D-->>B: 特性应答
B-->>M: cmdOtaDataReceive: 数据
M-->>App: otaFeatureResult(属性已填充)
alt 设备需挂载外置 Flash
App->>M: cmdSystemFunction(查询系统状态)
end
App->>M: cmdOTAData:固件数据 Result:^(result, progress)
M->>D: 升级指令 + 数据分片
alt 双备份或无需回连
loop 传输中
M->>D: 固件数据包
D-->>M: 应答 / 进度
M-->>App: otaUpgradeResult(Upgrading, progress)
end
else 单备份需回连
D-->>M: JL_OTAResultReconnect / ReconnectWithMacAddr
M-->>App: 通知需回连
M->>B: 断开并按 UUID/MAC 回连设备
B-->>M: 回连成功
M->>D: cmdOtaDataIIResult 继续传输(或 cmdUpgrade 内部处理)
loop 传输中
M->>D: 固件数据包
D-->>M: 应答 / 进度
M-->>App: otaUpgradeResult(progress)
end
end
D-->>M: 传输完成,设备重启
M-->>App: otaUpgradeResult(JL_OTAResultSuccess, 1.0)
升级流程状态机(逐步走查)
连接与登记:BLE 连接成功后(JL_BLEKit 侧认证完成),开发者调用
noteEntityConnected告知 SDK,并确保mBLE_UUID/mBLE_NAME已填写。设备断开时调用noteEntityDisconnected,SDK 据此复位内部传输状态。查询特性(必须第一步):调用
cmdTargetFeature查询设备 OTA 能力。SDK 根据应答填充otaPartition、bootloaderType、otaReconnectType、otaSourceMode等属性,随后触发otaFeatureResult:。设计意图:不同设备(单/双备份、是否需要 BootLoader、回连方式)升级路径差异很大,必须先拿到能力再决定策略,否则可能出现"双备份设备被当作单备份处理"等错误。(可选)查询系统功能:
cmdSystemFunction仅在设备需要挂载外置 Flash 才能升级时执行。发起升级:将固件文件(由
JLOTAFile/jl_ufw解析后的数据)通过cmdOTAData:Result:传入。SDK 内部进入"准备→传输"状态,JL_OTAResultPreparing→JL_OTAResultPrepared→JL_OTAResultUpgrading依次上报。回连分支(单备份特有):单备份设备升级时,设备会断开进入 Boot 广播。SDK 通过
JL_OTAResultReconnect(UUID 方式)或JL_OTAResultReconnectWithMacAddr(MAC 方式)通知上层;开发者可用cmdOtaIsRelinking查询是否正在回连。回连成功后可调用cmdOtaDataIIResult:再次发起升级(针对已断开的传输上下文),或直接使用cmdUpgrade:Option:Result:让 SDK 内部完成回连与续传(此接口免去外层回连策略,但要求使用 Result 回调而非 delegate 回调)。进度与完成:传输期间
otaUpgradeResult:Progress:持续回调进度;完成后设备重启,SDK 回调JL_OTAResultSuccess。若需要,可调用cmdRebootDevice/cmdRebootForceDevice主动重启设备。中断与清理:
cmdOTACancelResult:取消升级(SDK 回调otaCancel确认);升级会话结束后调用resetOTAManager复位状态机,准备下一次升级。
数据接收入口
设备端(经 JL_BLEKit 通道)返回的任何 RCSP 数据都必须喂给 SDK:
/// Receive data from rcsp
/// 设备端过来的数据
/// - Parameter data: data
- (void)cmdOtaDataReceive:(NSData *)data;
Source: JL_OTAManager.h
这是"数据回灌"入口,与 otaDataSend: 形成闭环:SDK 生成数据 → 上层发送 → 设备应答 → 上层回灌给 SDK。若此入口漏接,升级将永远停留在等待应答状态并最终超时。
使用示例
以下示例均摘自 JL_OTAManager.h 公开接口,展示标准接入模式(Objective-C)。
示例 1:获取单例并配置升级上下文
连接设备后,填充设备标识、设置代理并告知 SDK 连接已就绪:
// 获取 OTA 升级对象
JL_OTAManager *manager = [JL_OTAManager getOTAManager];
/// 设备UUID(需要开发者填入)
manager.mBLE_UUID = deviceUUID;
/// 设备名称(需要开发者填入)
manager.mBLE_NAME = deviceName;
/// 设备交互回调代理
manager.delegate = self;
// 当BLE连接上时告知SDK
[manager noteEntityConnected];
// 当BLE断开时告知SDK
[manager noteEntityDisconnected];
Source: JL_OTAManager.h
示例 2:连接后第一步——查询 OTA 能力
/// 查询设备OTA信息
/// 所有情况下都需要执行,而且是在连上后(认证完成)第一步执行
[manager cmdTargetFeature];
/// 查询设备系统状态
/// 当设备需要挂载外置flash才能正常升级时需要执行,其他情况则无需执行
[manager cmdSystemFunction];
Source: JL_OTAManager.h
查询完成后在 otaFeatureResult: 回调中读取 otaPartition、bootloaderType、otaReconnectType 等属性,即可判断走普通升级还是回连升级。
示例 3:发起升级(标准方式)
/// 开始OTA升级
/// @param data 升级数据
/// @param result 升级结果
[manager cmdOTAData:otaData Result:^(JL_OTAResult result, float progress) {
// 处理升级结果与进度
dispatch_async(dispatch_get_main_queue(), ^{
if (result == JL_OTAResultUpgrading) {
progressView.progress = progress;
} else if (result == JL_OTAResultSuccess) {
// 升级成功
} else if (result == JL_OTAResultLowPower) {
// 提示用户充电
}
});
}];
Source: JL_OTAManager.h
示例 4:一键升级(内部回连,单备份推荐)
/// OTA升级III
/// 单备份升级特有!!!
/// 此接口免去了公版 OTA 的外边回连策略,内部实现回连
/// ⚠️使用此方法时不可使用 delegate 的回调信息,要使用 Result 的回调信息
/// @param data OTA数据
/// @param option 回连选项
/// @param result 回复
[manager cmdUpgrade:otaData
Option:reconnectOption
Result:^(JL_OTAResult result, float progress) {
// 唯一的进度/结果来源
}];
Source: JL_OTAManager.h
注意:cmdUpgrade:Option:Result: 与 delegate 回调互斥(头文件明确标注"不可使用 delegate 的回调信息"),因为内部回连会重新走连接流程,delegate 状态与 Result 回调可能不一致。选其一即可。
示例 5:取消与复位
// OTA升级取消
[manager cmdOTACancelResult:^(uint8_t status, uint8_t sn, NSData *data) {
// 取消应答
}];
// 重置OTA manager(升级会话结束后清理状态)
[manager resetOTAManager];
Source: JL_OTAManager.h
配置选项
以下为 JL_OTAManager 提供的行为配置(默认值以头文件注释为准):
| 配置项 | 方法/属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|---|
| 最大丢包次数 | maxLostCount: | int | 10 | 传输层丢包重传上限,超过则判定升级失败 |
| 指令超时时间 | cmdTimeOut: | int | 5(秒) | 单条 RCSP 命令等待应答的超时时间 |
| 回连方式 | otaReconnectType | JL_OTAReconnectType | 由 cmdTargetFeature 查询结果决定 | UUID 或 MAC 地址回连 |
| 资源升级模式 | otaSourceMode | JLOtaSourcesExtendMode | JLSourcesExtendModeDisable | 普通/仅资源/仅固件升级 |
| 单双备份 | otaPartition | JL_Partition | 由设备查询决定 | 影响是否需要回连续传 |
| BootLoader | bootloaderType | JL_BootLoader | 由设备查询决定 | 是否先下载 BootLoader |
| 耳机强制升级 | otaHeadset | JL_OtaHeadset | JL_OtaHeadsetNO | 耳机单备份场景强制升级开关 |
| 仅 BLE | bleOnly | BOOL | NO | 设备是否仅支持 BLE |
| 发送日志 | logSendData: | BOOL | NO | 打印 OTA 发送的数据内容(调试用) |
| 回连开关 | setOTARelink: | BOOL | — | 已废弃,禁止外部使用(状态机内部管理) |
Source: JL_OTAManager.h
API 参考
+ (JL_OTAManager *)getOTAManager
获取 OTA 升级单例对象。推荐唯一获取方式;init 已废弃。
Returns:JL_OTAManager * 全局单例。
- (void)noteEntityConnected / - (void)noteEntityDisconnected
告知 SDK 设备 BLE 连接/断开事件。必须在连接建立与断开时准确调用,是状态机对设备生命周期感知的输入。
- (void)cmdOtaDataReceive:(NSData *)data
接收设备端回灌的 RCSP 数据。必须将 JL_BLEKit 通道收到的所有数据透传至此方法,否则 SDK 无法解析应答。
参数:data —— 设备返回的原始数据包。
- (void)cmdTargetFeature
查询设备 OTA 能力信息。连接认证完成后第一步必须执行;完成后触发 otaFeatureResult:。
- (void)cmdSystemFunction
查询设备系统状态。仅当设备需挂载外置 Flash 才能升级时执行。
- (void)cmdOTAData:(NSData *)data Result:(JL_OTA_RT __nullable)result
发起标准 OTA 升级。
参数:
data:升级数据(固件文件解析后的内容);result:升级结果/进度回调(JL_OTAResult, float progress),可为 nil(此时依赖 delegate)。
- (void)cmdOtaDataIIResult:(JL_OTA_RT __nullable)result
OTA 升级 II,单备份升级特有。用于回连成功后再次发起升级,续传此前中断的升级上下文。
- (void)cmdUpgrade:(NSData *)data Option:(JLOtaReConnectOption *__nullable)option Result:(JL_OTA_RT __nonnull)result
OTA 升级 III,单备份升级特有。SDK 内部实现回连,免去外层回连策略。
参数:
data:OTA 数据;option:回连选项(JLOtaReConnectOption),可为 nil;result:结果回调(非空,且此时不应使用 delegate 回调)。
- (void)cmdOTACancelResult:(JL_OTA_RESULT __nullable)result
取消 OTA 升级,通过 JL_OTA_RESULT 回调返回命令应答(status/sn/data)。
- (void)cmdRebootDevice / - (void)cmdRebootForceDevice
请求设备重启 / 强制重启(升级完成后清理设备状态时使用)。
- (BOOL)cmdOtaIsRelinking
查询单备份升级当前是否正处于回连阶段。Returns:BOOL,正在回连返回 YES。
- (void)resetOTAManager
重置 OTA 管理器内部状态,升级会话结束后调用,为下一次升级做准备。
+ (NSString *)logSDKVersion
打印/获取 OTA SDK 版本号。Returns:版本字符串。
- (void)maxLostCount:(int)count / - (void)cmdTimeOut:(int)timeOut
配置传输可靠性参数:最大丢包次数(默认 10)与命令超时秒数(默认 5)。弱信号环境可适当调大丢包上限,避免误判失败。
失败模式、边界情况与并发
升级失败分类与处置建议
依据 JL_OTAResult 枚举(JL_OTAManager.h L15-L80),可将失败归纳为四类:
| 类别 | 错误码 | 处置建议 |
|---|---|---|
| 用户/环境问题 | LowPower(0x06)、FailTWSDisconnect(0xfa)、FailNotInBin(0xfb)、FailedConnectMore(0x11) | 提示用户充电、连接 TWS 副耳、放入充电仓、断开多余设备后重试 |
| 数据/固件问题 | DataIsNull(0x02)、InfoFail(0x05)、FailSameSN(0xe0)、FailVerification(0xf1)、FailKey(0xf3)、FailErrorFile(0xf4)、FailUboot(0xf5)、FailSameVersion(0xf9) | 校验固件文件与设备型号/加密 Key/版本是否匹配,重新获取固件 |
| 传输/设备故障 | SeekFail(0x04)、FailLenght(0xf6)、FailFlash(0xf7)、FailCmdTimeout(0xf8)、Disconnect(0xfd)、Fail(0x01) | 检查信号强度与距离,适当调大 maxLostCount/cmdTimeOut,重试升级 |
| 流程状态信号 | Reconnect(0x09)、ReconnectWithMacAddr(0xfc)、ReconnectUpdateSource(0xfe)、Reboot(0x0a)、Preparing(0x0b)、Prepared(0x0f)、Upgrading(0x08)、StatusIsUpdating(0x10) | 这些不是错误,是状态机推进信号,按流程处理(回连、等待、续传)即可 |
回连机制的边界情况
- 回连是单备份升级的必经之路:设备进入 Boot 模式后会断开原连接,此时若上层未及时处理
JL_OTAResultReconnect/JL_OTAResultReconnectWithMacAddr,SDK 会停留在等待回连状态,直至cmdTimeOut超时。cmdOtaIsRelinking可用于 UI 层显示"正在回连"。 - UUID 与 MAC 回连的差异:UUID 方式(0x09)适用于 iOS 端连接过的设备(CoreBluetooth 缓存的 UUID);MAC 方式(0xfc)适用于需要按蓝牙 MAC 精确回连的场景(如多设备环境)。
cmdUpgrade:Option:Result:与 delegate 互斥:使用内部回连接口时,delegate 的otaUpgradeResult:不再可靠,必须全部依赖 Result 回调,否则会出现双重处理或漏处理。
并发与多设备
- 单例约束:
JL_OTAManager为单例,同一时刻只维护一份升级上下文。若 App 同时连接多台杰理设备,只允许对其中一台执行升级;JL_OTAResultFailedConnectMore(0x11)正是设备侧检测到多连接时给出的保护信号——必须手动断开另一台设备后才能继续。 - 数据回灌串行性:
cmdOtaDataReceive:应在蓝牙接收回调的串行队列上按序调用,避免多线程并发回灌导致分片乱序。发送侧otaDataSend:也应保持串行写特征。 - 主线程 UI 更新:delegate 与 Block 回调可能不在主线程触发,示例代码中使用
dispatch_async(dispatch_get_main_queue(), ...)更新进度条是推荐做法。
传输可靠性
- 丢包重传由 SDK 内部管理,
maxLostCount:(默认 10)控制最大连续丢包次数;cmdTimeOut:(默认 5 秒)控制单命令等待超时。两者共同构成"超时即失败"的保护网,防止升级过程无限挂起。 - 设备电量不足(
LowPower)时升级会被设备侧直接拒绝——这是保护性设计:OTA 写 Flash 期间断电会导致设备变砖,宁可拒绝也不要冒险。
性能与运维注意事项
- 升级耗时的决定因素:固件大小、BLE MTU/分片窗口、丢包重传。
otaLength(设备通知的升级内容大小)与otaSent(已传输字节数)可计算实时吞吐,便于展示 ETA。 - 日志:
logSendData:可打印 SDK 发送的每一条数据,是排查"设备不应答/指令错误"的首选工具;logSDKVersion可在反馈问题时附带 SDK 版本号。 - 升级期间的行为约束:升级过程中应避免主动断开 BLE、切换后台过度频繁或触发系统级蓝牙重置;设备侧正在写 Flash 时强杀 App 不会损坏设备(双备份可回滚),但单备份设备可能进入 Boot 待升级状态,需要重新走回连升级。
- 分发形态:XCFramework 已包含 ios-arm64 / ios-arm64_x86_64-simulator / macos-arm64_x86_64 三个切片,无需按目标平台拆分引用;注意真机调试时选择
ios-arm64切片,模拟器调试时选择ios-arm64_x86_64-simulator。
扩展点
JL_OTAManagerDelegate协议:通过实现otaFeatureResult:、otaUpgradeResult:Progress:、otaCancel自定义升级流程的 UI 与业务编排,而无需改动库内部逻辑。JLOtaReConnectOption:为cmdUpgrade:Option:Result:提供回连参数(UUID/名称/地址等),可针对特殊设备定制回连行为。JLOtaCustom:面向特殊设备的自定义升级策略入口(公开头文件之一),适合对标准升级流程不满足的定制项目。jl_ufw/JLOTAFile:固件文件解析层,负责从.ufw/.dfu文件提取升级数据与校验信息;如需对接自有文件格式,可在此层之外先转换为 SDK 期望的数据后直接调用cmdOTAData:。JLOtaSourcesExtendMode:资源/固件分离升级模式(SourceOnly/FirmwareOnly),适合需要单独推送 UI 资源或语音资源的场景,无需走完整固件升级流程。
Related Links
- JL_OTALib.h(框架主头文件)
- JL_OTAManager.h(OTA 管理核心 API)
- 框架其他公开头文件:
jl_ufw.h、JLOTAFile.h、JLOtaReConnectOption.h、JLOtaCustom.h(同目录) - 底层蓝牙连接与 RCSP 数据通道:见 JL_BLEKit 相关页面
- 演示工程接入示例:见
code/JieLi_Home_Demo与code/SDKTestHelper