工程结构与运行环境
本文档介绍 iOS-JL_OTA 仓库的整体工程结构、目录组织方式、依赖库体系,以及运行该 SDK 与示例工程所需的环境要求,帮助开发者快速定位代码、理解模块边界并正确搭建开发环境。
Purpose and Scope
本页面覆盖以下内容:
- 仓库顶层目录结构(
code/、libs/、doc/)及各目录职责 - 运行环境要求(iOS 版本、Xcode、硬件固件、开发语言)
- 核心 SDK 依赖库(XCFramework)体系与职责划分
- 示例工程中三种蓝牙连接方式的架构对比与选择指南
- OTA 集成的核心调用流程、权限与日志配置
- SDK 版本历史与许可证信息
以下主题属于其他页面范畴,不在本页展开:具体 OTA 升级流程的字节级分包细节、广播包解析协议字段、Hash 配对认证的密码学实现、以及完整示例 APP 的 UI 交互设计。
Overview
iOS-JL_OTA 是珠海市杰理科技股份有限公司为杰理蓝牙设备提供的 OTA 升级开发平台,基于 RCSP 协议(远程控制系统协议) 实现。该仓库同时包含三部分内容:以 XCFramework 格式发布的预编译 SDK 核心库、覆盖三种蓝牙连接方式的 iOS 示例工程源码、以及 HTML 格式的开发文档。
SDK 支持的应用场景覆盖三类典型产品:
| 应用类型 | 典型产品 |
|---|---|
| 数传设备 | AC695X、AC608N、AC897、AD697N、AD698N、AC630N、AC632N |
| 手表设备 | AC695X、JL701N、AC707N |
| 音箱设备 | JL701N、AC897、AD697N、AD698N、700N |
SDK 提供的核心能力包括:BLE 单备份/双备份 OTA 升级(含强制升级与回连机制)、Hash 配对设备认证、杰理蓝牙广播包自动解析、多种蓝牙连接方式(原生 CoreBluetooth、JL_BLEKit、JL_Assist 自定义连接),以及 v2.5.0 起新增的 GATT Over BR/EDR 经典蓝牙 OTA 升级支持。
理解工程结构的关键在于把握"业务库与连接层解耦"的设计意图:OTA 升级业务(JL_OTALib)不依赖任何特定蓝牙实现,而是通过统一的连接抽象接入三种不同的蓝牙方案,这使得开发者可以沿用已有的蓝牙管理代码,无需重写即可获得 OTA 能力。
Architecture
下图展示了仓库的整体架构与模块依赖关系:
flowchart TD
subgraph sg_Repo["iOS-JL_OTA 仓库"]
subgraph sg_Code["code/ 示例工程"]
MiniDemo["MiniDemo 迷你示例"]
JLOTA["JL_OTA 完整示例"]
MiniSingle["MiniSingleDemo<br/>原生 CoreBluetooth"]
JLBleKitDemo["JLBleKitOTADemo<br/>JL_BLEKit 连接"]
JLAssistDemo["JLAssistOTADemo<br/>JL_Assist 连接"]
BleManager["BleManager"]
BleByAssist["BleByAssist"]
SDKBleManager["SDKBleManager"]
Views["Views UI 视图"]
end
subgraph sg_Libs["libs/ 核心 SDK (XCFramework)"]
OTALib["JL_OTALib<br/>OTA 升级业务库"]
AdvParse["JL_AdvParse<br/>广播包解析库"]
HashPair["JL_HashPair<br/>设备认证库"]
BLEKit["JL_BLEKit<br/>蓝牙连接核心库(可选)"]
LogHelper["JLLogHelper<br/>日志辅助库"]
end
subgraph sg_Doc["doc/ 文档资源"]
ReleaseDoc["Release_V2.5.0 文档"]
end
end
MiniDemo --> MiniSingle
MiniDemo --> JLBleKitDemo
MiniDemo --> JLAssistDemo
JLOTA --> BleManager
JLOTA --> BleByAssist
JLOTA --> SDKBleManager
JLOTA --> Views
MiniSingle --> OTALib
JLBleKitDemo --> OTALib
JLAssistDemo --> OTALib
BleManager --> OTALib
BleByAssist --> OTALib
SDKBleManager --> OTALib
OTALib --> AdvParse
OTALib --> HashPair
OTALib --> LogHelper
OTALib -.-> BLEKit
JLBleKitDemo --> BLEKit
SDKBleManager --> BLEKit
架构分层说明:
libs/(核心 SDK 层):所有能力以 XCFramework 形式提供。JL_OTALib是唯一的 OTA 业务入口,内部依赖JL_AdvParse(广播解析)与JL_HashPair(Hash 认证);JLLogHelper自 v2.3.1 起被分离为独立日志模块,被各库共用;JL_BLEKit是可选蓝牙连接核心库,仅在开发者选择"SDK 蓝牙连接"方式时导入。code/(示例应用层):分为迷你示例(每种连接方式一个独立工程)与完整示例(一个工程内同时包含三种蓝牙管理实现,通过BleManager、BleByAssist、SDKBleManager三个模块分别对应原生、Assist、BLEKit 连接)。所有示例都只面向JL_OTALib编程,连接层差异被隔离在各自的 Manager 中。doc/(文档层):存放随版本发布的 HTML 开发文档,Release_V2.5.0为当前最新版本。
这样的分层设计意图在于:业务(OTA)与传输(BLE)彻底解耦。OTA 升级逻辑不关心数据是通过 CoreBluetooth、杰理蓝牙库还是外部蓝牙桥接发送的,只要连接层遵循统一的命令/回调契约即可工作;同时将广播解析、设备认证、日志三个横切关注点独立成库,使各库可以独立演进与复用。
工程结构详解
仓库的目录树定义如下(摘自 README 的工程结构章节):
iOS-JL_OTA/
├── code/ # 示例程序源码
│ ├── MiniDemo/ # 迷你示例工程
│ │ ├── MiniSingleDemo/ # 原生 CoreBluetooth 连接示例
│ │ ├── JLBleKitOTADemo/ # JL_BLEKit 连接示例
│ │ └── JLAssistOTADemo/ # JL_Assist 自定义连接示例
│ └── JL_OTA/ # 完整 OTA 应用示例
│ ├── BleManager/ # 自定义蓝牙连接实现
│ ├── BleByAssist/ # JL_Assist 蓝牙连接实现
│ ├── SDKBleManager/ # JL_BLEKit 蓝牙连接实现
│ └── Views/ # UI 视图
├── libs/ # 核心 SDK 库 (XCFramework 格式)
│ ├── JL_OTALib.xcframework # OTA 升级业务库
│ ├── JL_AdvParse.xcframework # 广播包解析库
│ ├── JL_HashPair.xcframework # 设备认证库
│ ├── JL_BLEKit.xcframework # 蓝牙连接核心库(可选)
│ └── JLLogHelper.xcframework # 日志辅助库
└── doc/ # 文档资源
└── Release_V2.5.0/ # 最新版本文档
Source: README.md
关键目录职责
| 目录 | 作用 |
|---|---|
code/MiniDemo/ | 迷你示例:三种连接方式各自独立的示例工程,适合对照学习单一连接方案 |
code/JL_OTA/ | 完整示例:包含完整 UI 与蓝牙管理的 OTA 应用,三个 Manager 模块并存的参考工程 |
libs/ | 核心 SDK:XCFramework 格式的预编译 OTA 升级库,使用 Embed & Sign 方式集成 |
doc/ | 开发文档:随版本发布的 HTML 文档与 API 说明 |
示例工程内部模块
code/JL_OTA/ 完整示例的四个子模块体现了连接抽象的设计:
BleManager/:基于原生 CoreBluetooth 的自定义连接实现,开发者完全掌控 BLE 扫描、连接、服务发现与分包发送;BleByAssist/:JL_Assist 自定义连接实现,适用于已有外部蓝牙管控、或需要将 OTA 桥接到既有蓝牙层的场景;SDKBleManager/:基于JL_BLEKit的连接实现,由 SDK 封装蓝牙细节,集成成本最低;Views/:与蓝牙无关的纯 UI 层,通过统一的 Manager 接口与底层交互。
这一划分说明完整示例把"连接策略"作为可替换组件:切换连接方式时只需替换 Manager 实现,Views/ 与 OTA 业务代码无需改动。
运行环境要求
SDK 及示例工程的运行环境要求如下:
| 类别 | 要求 | 说明 |
|---|---|---|
| iOS 系统 | iOS 12.0+ | 最低支持版本,BLE 功能依赖 |
| Xcode 版本 | 14.0+ | 建议使用最新版本 |
| 硬件要求 | 支持 RCSP 协议的固件 | AC695X、AC697X、AC695X 等 SDK |
| 语言支持 | Objective-C / Swift | 提供完整的 API 支持 |
| 许可证 | Apache 2.0 | 开源协议,版权归珠海市杰理科技股份有限公司 |
Source: README.md
选择 Xcode 14.0+ 的原因在于 XCFramework 的构建与签名机制依赖较新的 Xcode 工具链;iOS 12.0+ 的下限则覆盖了绝大多数支持 BLE 的存量设备,同时保证 Swift/ObjC 混编 API 的可用性。
克隆与集成
git clone https://github.com/Jieli-Tech/iOS-JL_OTA.git
cd iOS-JL_OTA
Source: README.md
集成 SDK 的标准步骤为:
- 导入框架:将
libs/目录下的 XCFramework 添加到项目中,并设置Embed & Sign; - 配置权限:在
Info.plist中添加蓝牙使用权限描述; - 初始化 SDK:参考示例工程的初始化代码进行集成;
- 开始开发:使用 SDK 提供的 API 进行 OTA 升级功能开发。
依赖库体系
libs/ 下的五个 XCFramework 构成了完整的 SDK 依赖体系,按"必须/可选"分类如下。
必须导入的库
| 库名 | 说明 |
|---|---|
JL_OTALib.xcframework | OTA 升级业务库,核心 API 入口 |
JL_AdvParse.xcframework | 杰理蓝牙设备广播包解析库 |
JL_HashPair.xcframework | 设备认证业务库(Hash 配对) |
JLLogHelper.xcframework | 日志打印收集库 |
可选导入的库
| 库名 | 说明 |
|---|---|
JL_BLEKit.xcframework | 蓝牙连接核心库,仅在需要使用杰理集成的蓝牙库时导入 |
Source: README.md
为什么广播解析与认证是"必须"的? 因为 OTA 升级流程强依赖这两个环节:JL_AdvParse 负责在扫描阶段识别杰理设备广播并提取连接参数,JL_HashPair 负责建立安全连接前的设备认证。二者从 v2.1.0 开始从 OTA 主库中分离为独立库,使各自的版本可以独立迭代;JL_BLEKit 保持可选,是因为 SDK 刻意支持"完全自研蓝牙层"的接入方式,避免强制引入蓝牙实现。
三种蓝牙连接方式
SDK 支持三种蓝牙连接方式,各自对应独立的示例工程。选择哪种方式取决于开发者对蓝牙层的掌控需求:
| 连接方式 | 适用场景 | Demo 路径 |
|---|---|---|
| 原生 CoreBluetooth | 完全掌控 BLE 扫描、连接、服务与分包发送 | code/MiniDemo/MiniSingleDemo/ |
| JL_BLEKit | 快速集成、减少蓝牙细节处理 | code/MiniDemo/JLBleKitOTADemo/ |
| JL_Assist 自定义 | 已有外部蓝牙管控或需桥接到既有蓝牙层 | code/MiniDemo/JLAssistOTADemo/ |
Source: README.md
flowchart TD
Start([需要集成 OTA 的 iOS 工程]) --> Q{"现有蓝牙能力?"}
Q -->|"无,希望完全自研"| Native["原生 CoreBluetooth<br/>MiniSingleDemo"]
Q -->|"无,希望快速集成"| BLEKit["JL_BLEKit 连接<br/>JLBleKitOTADemo"]
Q -->|"已有蓝牙管控层"| Assist["JL_Assist 自定义<br/>JLAssistOTADemo"]
Native --> OTA["JL_OTALib OTA 业务"]
BLEKit --> OTA
Assist --> OTA
选择指南(摘自 README):
- 完全掌控 BLE 扫描、连接、服务与分包发送 → 选择原生自定义连接
- 快速集成、减少蓝牙细节处理 → 选择 SDK 蓝牙连接(JL_BLEKit)
- 已有外部蓝牙管控或需桥接到既有蓝牙层 → 选择 JL_Assist 自定义连接
Source: README.md
无论选择哪种连接方式,上层 OTA 业务都统一走 JL_OTALib,这正是"业务与传输解耦"架构的直接体现。
核心调用流程
OTA 升级的完整调用时序如下(README 定义的标准集成流程):
sequenceDiagram
participant APP as iOS App
participant BLE as 蓝牙连接层
participant OTA as JL_OTALib
participant DEV as 杰理设备
APP->>BLE: 设备连接 + 订阅
BLE-->>OTA: noteEntityConnected
OTA-->>APP: 连接状态回调
APP->>OTA: cmdTargetFeature(查询设备能力)
OTA-->>APP: 能力信息返回
APP->>OTA: cmdOTAData(data) 发送升级数据
OTA->>DEV: 分包写入 OTA 数据
DEV-->>OTA: 数据确认
OTA-->>APP: 委托回调 otaUpgradeResult / otaDataSend
Note over APP,DEV: 升级进行中,持续分包交互
BLE-->>OTA: noteEntityDisconnected(断开)
OTA-->>APP: 回连/结束处理
Source: README.md
流程要点
- 连接与订阅:App 建立 BLE 连接并订阅设备通知,蓝牙层上报
noteEntityConnected; - 能力查询:App 调用
cmdTargetFeature查询设备支持的 OTA 能力(单备份/双备份、空间等),为后续升级策略提供依据; - 数据下发:App 调用
cmdOTAData(data)将升级文件分包发送给设备; - 进度回调:升级过程通过委托回调
otaUpgradeResult(升级结果)与otaDataSend(数据发送进度)反馈给 App; - 断开处理:连接断开时蓝牙层上报
noteEntityDisconnected,App 据此执行回连或结束流程(v2.5.0 修复了 OTA 回连超时问题)。
该流程体现了 SDK 的事件驱动模型:App 不主动轮询设备状态,而是由蓝牙层与 OTA 库通过回调反向通知,从而避免阻塞主线程并简化状态管理。
配置说明
权限配置
在 Info.plist 中添加以下蓝牙权限:
<key>NSBluetoothAlwaysUsageDescription</key>
<string>需要使用蓝牙功能连接杰理设备</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>需要作为蓝牙外设连接杰理设备</string>
Source: README.md
NSBluetoothAlwaysUsageDescription 是 iOS 13+ 持续使用蓝牙所必需的权限描述;NSBluetoothPeripheralUsageDescription 用于兼容低版本 iOS 的外设角色声明。两者缺一不可,否则系统会在首次扫描/连接时直接终止 App。
日志管理
JLLogHelper 默认开启日志打印与存储,可通过以下接口控制:
// Objective-C
[JLLogManager clearLog]; // 清空日志
[JLLogManager setLog:false IsMore:false Level:JLLOG_COMPLETE]; // 关闭日志打印
[JLLogManager saveLogAsFile:false]; // 关闭日志存储
[JLLogManager logWithTimestamp:false]; // 关闭日志打印时间
Source: README.md
// Swift
JLLogManager.saveLog(asFile: true)
JLLogManager.setLog(true, isMore: false, level: .COMPLETE)
JLLogManager.log(withTimestamp: true)
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! + "/abc.txt"
JLLogManager.redirectLogPath(path) // 重置保存路径
JLLogManager.clearLog()
JLLogManager.collectLog { str in
print(str) // 回调所有的日志打印内容
}
JLLogManager.logSomething("abcd")
Source: README.md
日志库自 v2.3.1 起作为独立运行模块提供,支持打印开关、详细级别(JLLOG_COMPLETE)、文件存储开关、时间戳、路径重定向、日志收集回调等能力。在定位 OTA 失败问题时,可开启 collectLog 将 SDK 内部日志实时回调给 App 侧展示,或开启 saveLogAsFile 导出日志文件用于远程排查。
API 参考(核心接口一览)
以下接口为 OTA 集成过程中最常使用的 SDK 入口(来自 README 定义的集成契约,完整签名以 doc/Release_V2.5.0/ 文档为准)。
连接与状态回调
| 回调/方法 | 时机 | 说明 |
|---|---|---|
noteEntityConnected | 设备连接成功 | 蓝牙层通知 OTA 库设备已就绪 |
noteEntityDisconnected | 设备断开 | 触发回连或结束流程 |
cmdTargetFeature | 连接后、升级前 | 查询设备 OTA 能力(备份方式、可用空间等) |
cmdOTAData(data) | 能力确认后 | 将升级数据分包下发到设备 |
otaUpgradeResult | 升级结束 | 委托回调,返回升级结果 |
otaDataSend | 升级过程中 | 委托回调,反馈数据发送进度 |
JLLogManager 日志接口
| 方法 | 作用 |
|---|---|
setLog(_:isMore:level:) | 开关日志打印并设置详细级别(如 JLLOG_COMPLETE) |
saveLog(asFile:) / saveLogAsFile: | 开关日志落盘存储 |
redirectLogPath(_:) | 重置日志文件保存路径 |
clearLog() | 清空日志 |
collectLog { str in } | 回调所有日志内容(实时收集) |
log(withTimestamp:) / logWithTimestamp: | 开关日志时间戳 |
logSomething(_:) | 手动写入自定义日志 |
Source: README.md
版本历史与演进
SDK 版本的演进脉络反映了工程结构的变化:
| 版本 | 发布日期 | 主要更新 |
|---|---|---|
| v2.5.0 | 2026/02/04 | 增加 GATT Over BR/EDR 设备 OTA 升级支持;修复 OTA 回连超时问题 |
| v2.4.0 | 2025/10/13 | OTA 超时处理逻辑优化;增加重复序列号容错;增加特殊空间复用升级支持;增加单备份 SDK 内部自动回连接口 |
| v2.3.1 | 2024/12/12 | 分离日志打印库为独立运行模块;增加所有命令的超时检测;增加 OTA 升级的错误回调;增加 OTA 对象管理容错 |
| v2.1.0 | 2023/03/28 | 性能优化;分离 OTA 模块、设备认证配对业务、广播包解析模块为独立库 |
| v2.0.0 | 2021/10/14 | 支持 BLE 单备份/双备份升级;支持浏览器与第三方电脑软件导入升级文件;可选 BLE 广播包过滤与握手连接 |
Source: README.md
结构演进的关键节点: v2.1.0 将 OTA 主库拆分为"OTA 业务 + 认证 + 广播解析"三个独立库,奠定了当前 libs/ 目录的模块形态;v2.3.1 又将日志模块独立为 JLLogHelper,并引入全命令超时检测与错误回调;v2.5.0 扩展了传输层能力(GATT Over BR/EDR),使同一套 OTA 业务同时覆盖 BLE 与经典蓝牙。
对应地,示例 APP 版本(v3.5.2 起使用 SDK v2.5.0)与 SDK 版本同步演进,其中 v3.3.0 完成 UI 重构并新增自动化测试与广播音箱模块。
失败模式与边界情况
从版本历史与集成说明可以梳理出 SDK 已处理的典型失败场景:
- 回连超时:升级过程中蓝牙意外断开时,SDK 依据设备地址自动回连。v2.5.0 修复了回连超时导致升级中断的问题;v2.4.0 起单备份升级支持 SDK 内部自动回连接口,App 无需自行实现重连逻辑。
- 命令超时:v2.3.1 起所有命令具备超时检测,避免设备无响应时流程永久挂起;v2.4.0 进一步优化超时处理逻辑,缩短异常路径的恢复时间。
- 重复序列号:v2.4.0 增加对重复序列号的容错处理,防止数据包重发或乱序导致的分包计数错乱。
- 对象管理容错:v2.3.1 增加 OTA 对象管理容错,防止多次初始化的重复创建导致资源泄漏。
- 错误回调缺失:早期版本升级失败只能依赖超时间接判断;v2.3.1 起增加 OTA 升级错误回调(
otaUpgradeResult携带错误信息),App 可以及时向用户反馈失败原因。
边界条件提示: 设备空间不足(需通过 cmdTargetFeature 查询)、固件不兼容(固件需支持 RCSP 协议)、以及强制升级场景下设备未处于可升级状态,均属于需要 App 层结合设备能力信息进行前置校验的场景。
性能与运维考虑
- 分包发送效率:
cmdOTAData(data)采用分包发送,数据量较大时发送节奏由 SDK 内部调度;App 应避免在回调线程中执行耗时操作,防止阻塞数据下发。 - 日志开销:
JLLogHelper默认开启打印与存储,生产环境建议通过setLog:false与saveLogAsFile:false关闭以降低 I/O 开销;排查问题时再开启collectLog实时收集。 - 线程模型:回调(
noteEntityConnected、otaUpgradeResult等)由蓝牙层线程触发,App 侧 UI 更新需自行切换到主线程。 - 调试手段:使用 Xcode Console 查看实时日志;SDK 侧问题可参考在线文档中心的调试说明,杰理 OTA APP 还支持导出打印日志用于远程分析。
扩展点
SDK 通过以下方式提供扩展能力:
- 连接层替换:
JL_Assist自定义连接允许将 OTA 桥接到任意既有蓝牙层,是最大的扩展点——第三方蓝牙栈、外部连接管理模块均可接入; - 可选库裁剪:不使用
JL_BLEKit时可不导入,减小包体积; - 升级文件导入渠道:支持浏览器传输与第三方电脑软件导入 OTA 升级文件,App 可在此基础上扩展更多文件来源;
- 日志集成:
JLLogManager.collectLog可将 SDK 日志接入 App 自身的日志体系(如 Crashlytics、自建日志平台)。
Related Links
- README.md(中文总览)
- README_EN.md(英文总览)
- LICENSE(Apache 2.0)
- 杰理在线文档中心:https://doc.zh-jieli.com/Apps/iOS/ota/zh-cn/master/index.html
- 问题反馈:https://github.com/Jieli-Tech/iOS-JL_OTA/issues