杰理 SDK 文档中心
首页
首页
  • 项目概览

    • 项目概述与功能特性
    • 工程结构与运行环境
  • 快速开始

    • SDK 集成步骤
    • 连接方式选择指南
  • 核心 SDK 架构

    • SDK 框架组成
    • JL_OTAManager 升级管理 API
    • 设备认证与广播解析
  • 蓝牙连接与设备发现

    • 设备扫描与广播发现
    • 原生 CoreBluetooth 连接
    • JL_BLEKit SDK 连接
    • JL_Assist 自定义连接
    • GATT Over BR/EDR 经典蓝牙升级
  • OTA 升级工作流

    • 标准升级流程
    • 自动化测试与批量升级
    • 广播音箱升级
    • 升级文件管理
  • 示例工程

    • 完整示例应用
    • 迷你示例工程
    • 第三方依赖与工具
  • 开发支持与版本发布

    • 文档中心与 API 说明
    • SDK 版本与构建产物
    • 调试技巧与日志辅助

连接方式选择指南

本文档说明 iOS-JL_OTA SDK 提供的三种蓝牙连接方式(原生 CoreBluetooth、JL_BLEKit、JL_Assist 自定义连接)的适用场景、架构差异与选择标准,帮助开发者在集成 OTA 升级之前确定正确的连接方案。

Purpose and Scope

本页是「开始使用」系列中的连接方式选型指南,覆盖以下内容:

  • 三种连接方式的定位与职责边界(谁负责扫描、连接、服务发现、分包发送)
  • 各方式对应的官方示例工程与集成路径
  • 选择决策流程与三种方式的对比总览
  • 与连接方式相关的核心调用流程、配置项、失败模式与重连策略

以下主题属于相邻专题页面,本页只做指引、不展开:

  • OTA 升级接口的完整 API 规范(getOTAManager、cmdOTAData、noteEntityConnected 等)→ 见仓库根目录 doc/API 说明.md
  • 基于某一种连接方式的完整升级开发示例 → 见各 Demo 目录下的「OTA 升级开发示例」文档(code/MiniDemo/MiniSingleDemo/、code/MiniDemo/JLBleKitOTADemo/、code/MiniDemo/JLAssistOTADemo/)

Overview

iOS-JL_OTA 是杰理科技为杰理蓝牙设备提供的 OTA 升级开发平台,基于 RCSP 协议(远程控制系统协议),支持数传设备、手表、音箱等产品线。SDK 将「OTA 升级逻辑」与「蓝牙连接细节」解耦:升级逻辑统一由 JL_OTAManager 提供,而底层数据通道可以来自三种不同的蓝牙连接实现。

README 的「连接方式选择」一节明确列出了三种方式及其适用场景(见 README.md#L85-L98):

连接方式适用场景Demo 路径
原生 CoreBluetooth完全掌控 BLE 扫描、连接、服务与分包发送code/MiniDemo/MiniSingleDemo/
JL_BLEKit快速集成、减少蓝牙细节处理code/MiniDemo/JLBleKitOTADemo/
JL_Assist 自定义已有外部蓝牙管控或需桥接到既有蓝牙层code/MiniDemo/JLAssistOTADemo/

README 给出的选择指南(原文摘录):

  • 完全掌控 BLE 扫描、连接、服务与分包发送 → 选择原生自定义连接
  • 快速集成、减少蓝牙细节处理 → 选择 SDK 蓝牙连接(JL_BLEKit)
  • 已有外部蓝牙管控或需桥接到既有蓝牙层 → 选择 JL_Assist 自定义连接

设计意图:SDK 不强制绑定某一种蓝牙栈。三种方式共享同一套 OTA 能力层(JL_OTALib、JL_AdvParse 广播解析、JL_HashPair 配对认证),只是「数据通道接入点」不同。这样既满足需要深度定制 BLE 行为的开发者,也满足希望快速上线的开发者,且三种方式的升级协议栈(RCSP)完全一致,升级结果行为一致。

Architecture

flowchart TD
    subgraph sg_App["应用层(你的 iOS App)"]
        App["业务代码 / 升级界面"]
    end

    subgraph sg_Conn["连接方式层(三选一)"]
        CB["原生 CoreBluetooth<br/>自建 BleManager"]
        BK["JL_BLEKit<br/>SDK 蓝牙连接"]
        AS["JL_Assist<br/>自定义蓝牙连接"]
    end

    subgraph sg_OTA["OTA 能力层(共享)"]
        OM["JL_OTAManager"]
        Parser["JL_AdvParse 广播解析"]
        Hash["JL_HashPair 配对认证"]
    end

    subgraph sg_Dev["设备端"]
        Dev["杰理蓝牙设备<br/>(RCSP 协议固件)"]
    end

    App --> CB
    App --> BK
    App --> AS
    CB --> OM
    BK --> OM
    AS --> OM
    OM --> Parser
    OM --> Hash
    CB -->|"BLE GATT 通道"| Dev
    BK -->|"BLE GATT 通道"| Dev
    AS -->|"BLE GATT 通道(桥接)"| Dev

架构说明:应用层只面向 JL_OTAManager 编程,不关心底层数据通道来自哪种连接实现。连接方式层负责建立与设备的 GATT 数据通道:接收方向把设备数据回调给 OTA 层(通过 otaDataSend 委托),发送方向把 OTA 层产出的升级包写入设备。无论选择哪种连接方式,OTA 能力层与设备端固件交互的协议栈完全一致,因此升级结果具有一致性;差别仅在于「扫描/连接/订阅/写数据」这些 BLE 细节由谁负责。

三种连接方式详解

原生 CoreBluetooth(自建 BleManager)

定位:完全掌控 BLE 扫描、连接、服务与分包发送。适合已有自定义 BLE 管理逻辑、需要处理多设备/多服务、或需要精细控制连接参数的工程。

职责边界:开发者自行实现 CBCentralManager 扫描、CBPeripheral 连接、服务/特征发现、setNotifyValue 订阅、以及升级分包发送。SDK 侧的 JL_OTAManager 只负责 RCSP 协议打包与升级状态机。仓库中 code/JL_OTA/BleManager/ 即「自定义蓝牙连接实现」的参考工程目录(见 README.md#L109-L120)。

优点:对 BLE 细节的掌控力最强,方便与既有蓝牙业务(如设备配网、多连接)融合;不引入额外的蓝牙管理依赖。

代价:需要自行处理扫描过滤、连接超时、服务发现失败、分包/粘包、断线重连等全部细节,集成工作量最大。

JL_BLEKit(SDK 蓝牙连接)

定位:快速集成、减少蓝牙细节处理。适合以 OTA 为主要目标、不希望维护复杂 BLE 状态机的工程。

职责边界:扫描、连接、订阅、数据收发均由 SDK 蓝牙框架托管,开发者只需按 SDK 蓝牙连接的示例流程调用并接收连接状态回调,随后把设备句柄交给 JL_OTAManager 即可进入升级流程。对应示例工程为 code/MiniDemo/JLBleKitOTADemo/。

优点:集成路径最短,蓝牙细节由 SDK 封装,升级链路(连接 → 订阅 → 升级 → 回连)的一致性由 SDK 保证。

代价:对底层 BLE 行为的定制能力弱于原生方式;若工程已有独立蓝牙栈,则存在两套蓝牙管理并存的协调成本。

JL_Assist 自定义连接

定位:已有外部蓝牙管控或需桥接到既有蓝牙层。适合 App 中已经存在完整的蓝牙连接管理(例如自有蓝牙框架、跨端共享的蓝牙层),不希望为 OTA 再引入一套连接逻辑的工程。

职责边界:外部蓝牙层负责扫描与连接,JL_Assist 充当「桥接适配器」,把 OTA 层的数据写入请求(bleWrite)转发给既有蓝牙层,并把设备上报的数据回传给 JL_OTAManager。示例见 code/MiniDemo/JLAssistOTADemo/。

优点:与既有蓝牙架构解耦最小,改造范围仅限于桥接写入与回调转发两处;可复用 App 已有的扫描、重连、权限流程。

代价:需要开发者保证桥接层的写操作与订阅回调语义正确(数据分包、写入队列、断线通知),桥接质量直接影响升级稳定性。

对比总览

维度原生 CoreBluetoothJL_BLEKitJL_Assist 自定义
扫描/连接职责开发者自建 BleManagerSDK 托管外部既有蓝牙层
服务/特征订阅开发者实现SDK 封装外部层实现,桥接回调
分包发送开发者实现(写入队列)SDK 封装桥接 bleWrite
集成工作量最大最小中等(桥接适配)
BLE 定制能力最强较弱取决于外部层
示例工程MiniSingleDemo/JLBleKitOTADemo/JLAssistOTADemo/

选择决策流程

flowchart TD
    Start([开始选型]) --> Q1{"已有外部蓝牙管控<br/>或既有蓝牙层?"}
    Q1 -->|"是"| AS["JL_Assist 自定义连接<br/>桥接既有蓝牙层<br/>(JLAssistOTADemo)"]
    Q1 -->|"否"| Q2{"需要完全掌控 BLE 细节?<br/>扫描/连接/服务/分包"}
    Q2 -->|"是"| CB["原生 CoreBluetooth<br/>自建 BleManager<br/>(MiniSingleDemo)"]
    Q2 -->|"否"| BK["JL_BLEKit<br/>SDK 蓝牙连接<br/>(JLBleKitOTADemo)"]
    AS --> Verify["按对应 Demo 集成并验证升级"]
    CB --> Verify
    BK --> Verify

核心调用流程

无论选择哪种连接方式,进入 OTA 升级后的核心调用序列是统一的:设备连接 + 订阅 → noteEntityConnected → cmdTargetFeature → cmdOTAData(data) → 委托回调 → 断开时 noteEntityDisconnected(见 README.md#L100-L105)。

sequenceDiagram
    participant App as App 业务层
    participant Conn as 连接方式层(三选一)
    participant OM as JL_OTAManager
    participant Dev as 杰理蓝牙设备

    App->>Conn: 扫描并连接设备
    Conn->>Dev: 连接 + 订阅特征
    Dev-->>Conn: 已连接
    Conn->>OM: 通知设备已连接(noteEntityConnected)
    Note over OM: 填充 mBLE_UUID / mBLE_NAME 上下文
    OM->>Dev: cmdTargetFeature(查询升级能力)
    Dev-->>OM: 特性返回(单/双备份、强制升级等)
    OM->>Dev: cmdOTAData(data)(分包发送升级包)
    Dev-->>OM: 升级进度 / 结果
    OM-->>App: 委托回调 otaUpgradeResult / otaDataSend
    Note over OM,Dev: 升级完成,或断开 / 升级失败
    App->>OM: noteEntityDisconnected(清理上下文)

关键点说明:

  1. 连接与订阅先于 OTA 上下文创建:只有底层通道就绪(特征订阅成功)后,才应调用 noteEntityConnected,否则数据会丢失。
  2. mBLE_UUID / mBLE_NAME 是 OTA 重连的依据:JL_OTAManager 依靠这两个属性(以及 bleAddr)在升级中断后发起回连(详见「失败模式与重连处理」)。
  3. cmdTargetFeature 是升级前的能力协商:先查询设备支持单备份/双备份、是否强制升级等特性,SDK 据此选择升级策略。
  4. cmdOTAData 分包由 OTA 层驱动:SDK 通过 otaDataSend 委托把每个数据包交给连接方式层写出,开发者只需保证写队列按序可靠送达。

使用示例

以下示例均取自官方 Demo 文档,展示「JL_Assist 自定义连接 + JL_OTAManager」的标准调用流程,可作为另外两种连接方式的调用范式参考(连接方式层不同,OTA 层调用一致)。

Swift 示例:连接与升级主流程

import UIKit
import CoreBluetooth
import JL_OTALib

/// OTA 示例控制器:演示 JL_Assist 自定义蓝牙连接与 JL_OTAManager 的标准调用流程
final class OTAExampleViewController: UIViewController, JL_OTAManagerDelegate {

    private let otaManager = JL_OTAManager.getOTAManager() // 单例获取

    override func viewDidLoad() {
        super.viewDidLoad()
        // 1) 绑定 delegate
        otaManager.delegate = self

        // 2) 扫描并连接设备
        BleManager.shared.startScan()
        // 选择设备后:BleManager.shared.connect(peripheral: sel)
    }

    // 3) 订阅完成后初始化 OTA 上下文
    private func onPeripheralReady(_ peripheral: CBPeripheral) {
        otaManager.mBLE_UUID = peripheral.identifier.uuidString
        otaManager.mBLE_NAME = peripheral.name ?? ""

        otaManager.noteEntityConnected() // 通知 OTA 层设备已就绪
        otaManager.cmdTargetFeature()    // 查询设备升级能力
    }

    // 4) 发起 OTA 升级
    private func startUpgrade(with data: Data) {
        otaManager.cmdOTAData(data)
    }

    // 5) 取消升级
    private func cancelUpgrade() {
        otaManager.cmdOTACancelResult { result in
            print("OTA 取消:\(result)")
        }
        otaManager.noteEntityDisconnected()
    }

    // 6) 委托回调
    func otaUpgradeResult(_ result: JL_OTAResult, progress: Float) {
        print("升级状态:\(result) 进度:\(progress)")
    }
    func otaDataSend(_ data: Data) {
        BleManager.shared.assistManager.bleWrite(data) // 桥接写入既有蓝牙层
    }
    func otaCancel() {}
    func otaFeatureResult(_ manager: JL_OTAManager) {}
}

Source: OTA 升级开发示例(JL_Assist 自定义蓝牙连接).md#L9-L61

Objective-C 示例:回连与超时重试策略

#import <JL_OTALib/JL_OTALib.h>

/**
 异常与重试策略示例(Objective‑C)
 展示基于自定义连接的回连与超时重试的基本处理
 */
@interface OTARetryGuideObjC : NSObject <JL_OTAManagerDelegate>
@property (nonatomic, strong) JL_OTAManager *otaManager;
@property (nonatomic, assign) NSInteger retryCount;
@end

@implementation OTARetryGuideObjC

- (instancetype)init {
    if (self = [super init]) {
        _otaManager = [JL_OTAManager getOTAManager];
        _retryCount = 0;
        _otaManager.delegate = self;
    }
    return self;
}

- (void)otaUpgradeResult:(JL_OTAResult)result Progress:(float)progress {
    switch (result) {
        case JL_OTAResultReconnect:
        case JL_OTAResultReconnectUpdateSource: {
            // 按 UUID 回连
            NSString *uuid = self.otaManager.mBLE_UUID;
            [[BleManager shared] reConnectWithUUID:uuid];
            break;
        }
        case JL_OTAResultReconnectWithMacAddr: {
            // 按 MAC 地址回连
            NSString *mac = self.otaManager.bleAddr;
            [[BleManager shared] reConnectWithMac:mac];
            break;
        }
        case JL_OTAResultFailCmdTimeout: {
            // 命令超时:指数退避重试 cmdTargetFeature,最多 3 次
            if (self.retryCount < 3) {
                self.retryCount += 1;
                NSTimeInterval delay = (NSTimeInterval)self.retryCount;
                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                    [self.otaManager cmdTargetFeature];
                });
            }
            break;
        }
        default:
            break;
    }
}

@end

Source: OTA 升级开发示例(JL_Assist 自定义蓝牙连接).md#L63-L117

两个示例共同揭示了连接方式层与 OTA 层的协作契约:连接方式层只需兑现「能写入、能收数据、能断开」三个能力,其余升级逻辑(分包、校验、状态机、回连触发)全部由 JL_OTAManager 完成。这也解释了为何三种连接方式可以共享同一套 JL_OTAManager API。

配置选项

连接方式的接入不需要额外参数,但无论选择哪种方式,都必须完成以下工程配置(见 README.md#L100-L105):

配置项类型默认值说明
JL_OTALib.xcframework框架依赖必选OTA 核心能力库(JL_OTAManager),需 Embed & Sign
JL_AdvParse.xcframework框架依赖必选广播包解析库
JL_HashPair.xcframework框架依赖必选Hash 配对认证库
JLLogHelper.xcframework框架依赖必选日志辅助库
Privacy - Bluetooth Peripheral Usage DescriptionInfo.plist 权限必填iOS 12.0+ 使用 BLE 必需
Privacy - Bluetooth Always Usage DescriptionInfo.plist 权限必填后台/常驻蓝牙场景必需
mBLE_UUIDJL_OTAManager 属性空已连接设备 UUID,重连依据
mBLE_NAMEJL_OTAManager 属性空设备名,用于日志与回连
bleAddrJL_OTAManager 属性空设备 MAC 地址,MAC 回连依据

运行环境要求(见 README.md#L58-L66):iOS 12.0+、Xcode 14.0+、支持 RCSP 协议的固件(AC695X、AC697X 等 SDK)、Objective-C / Swift 均可。

失败模式、边界情况与并发注意

从上述 Objective-C 示例可以归纳出 SDK 暴露的主要失败模式及推荐处理方式:

失败模式触发场景推荐处理
JL_OTAResultReconnect升级过程中设备断开,需要按 UUID 回连读取 mBLE_UUID 调用 reConnectWithUUID:
JL_OTAResultReconnectUpdateSource升级中断且需要更新升级源后回连与上类似,按 UUID 回连
JL_OTAResultReconnectWithMacAddr设备地址变化/需按 MAC 回连读取 bleAddr 调用 reConnectWithMac:
JL_OTAResultFailCmdTimeout命令发送后超时(设备未响应)有限次数重试 cmdTargetFeature,退避延时随次数递增

边界情况与并发注意:

  • 时序边界:noteEntityConnected 必须在特征订阅完成后调用;过早调用会导致升级数据包无法送达设备。
  • 重连状态机:SDK 以 mBLE_UUID / mBLE_NAME / bleAddr 作为回连身份依据,切换设备或清空上下文前必须 noteEntityDisconnected,否则旧上下文可能被新连接复用。
  • 写入并发:otaDataSend 回调要求连接方式层按序写入;若底层写通道支持无响应写(writeWithoutResponse),SDK 的分包节奏仍要求开发者保证队列 FIFO,避免乱序导致升级包校验失败。
  • 超时重试:JL_OTAResultFailCmdTimeout 的重试需限制次数(示例中为 3 次)并配合退避,防止设备端处于升级异常状态时无限重发造成信道拥塞。
  • 取消语义:cmdOTACancelResult 完成后应调用 noteEntityDisconnected 收尾,确保 OTA 上下文与蓝牙连接状态一致。

性能与运维提示

  • 升级耗时主要取决于 MTU 与写通道吞吐:原生 CoreBluetooth 方式可自行协商 MTU/选择写入类型,吞吐上限最高;JL_BLEKit 与 JL_Assist 方式受 SDK/外部层封装约束。
  • 日志先行:集成 JLLogHelper.xcframework,排查升级失败时优先核对 noteEntityConnected → cmdTargetFeature → cmdOTAData 的调用顺序与 otaDataSend 是否持续被驱动。
  • 真机验证:BLE 行为(扫描、连接、后台订阅)依赖真实硬件,模拟器无法完整验证连接方式层,选型后应在真机上完成回连与断线场景测试。

扩展点

  • 桥接层(JL_Assist):assistManager.bleWrite(data) 是唯一的写入出口,开发者可在其中加入写入队列、日志埋点、流量统计,而无需改动 OTA 层。
  • 自定义 BleManager(原生方式):code/JL_OTA/BleManager/ 提供参考实现,可在此基础上扩展多设备管理、扫描过滤、连接参数配置。
  • 委托回调:JL_OTAManagerDelegate(otaUpgradeResult、otaDataSend、otaCancel、otaFeatureResult)是观察 OTA 状态机的标准扩展接口,可在此基础上实现升级进度 UI、埋点上报、回连提示。

Related Links

  • README(快速开始与工程结构)
  • OTA 升级开发示例(JL_Assist 自定义蓝牙连接)
  • OTA升级开发示例(SDK蓝牙连接)
  • OTA 升级开发示例(原生 MiniSingleDemo)
  • API 说明(JL_OTAManager 接口规范)
Prev
SDK 集成步骤