杰理 SDK 文档中心
首页
首页
  • 概述与快速开始

    • 仓库概览
    • 运行环境与 SDK 集成
    • 工程结构与目录导航
  • 核心 SDK 架构

    • SDK 库体系与模块划分
    • 蓝牙连接与 RCSP 协议
    • 广播包解析与设备认证
    • 日志助手与调试支持
  • 设备功能模块

    • OTA 固件升级
    • 表盘管理与自定义表盘
    • 图像转换工具
    • 资源打包
    • 音频编解码
    • 健康与运动数据同步
    • 消息通知与实用设备功能
  • 宜动健康示例应用

    • 应用架构与页面导航
    • 健康界面与数据可视化
    • 设备连接与数据同步
    • 登录注册与用户中心
    • AI 云服务与语音交互
    • 本地数据库与持久化
    • 多语言国际化
  • 测试与调试

    • SDKTestHelper 功能测试工具
    • 音频编解码示例工程
    • 调试技巧与问题排查
  • 文档与资源

    • 在线文档与版本历史
    • 第三方框架与依赖管理

设备连接与数据同步

本文档介绍 iOS-JL_Health 中智能手表(Watch)设备的 BLE 连接管理与健康数据同步机制:从设备搜索、连接、状态变更通知,到健康数据(心率/步数/血氧/睡眠等)从服务器增量拉取并写入本地 SQLite 的完整链路。

Purpose and Scope

本页覆盖「设备连接与数据同步」这条完整能力链路:

  • 设备连接:基于 JL_BLEKit 框架的 BLE 扫描、过滤、连接、重连与状态变更通知,核心实现位于 JL_RunSDK;
  • 设备准备:连接成功后进入设备准备(preparation)流程,涉及 JLPreparation 与 SyncDataManager;
  • 数据同步:UserDataSync 负责从云端按表增量拉取健康数据并写入本地 SQLite(JLSqliteHeartRate、JLSqliteStep、JLSqliteOxyhemoglobinSaturation 等)。

以下主题属于相邻能力,由各自页面说明,不在本页展开:OTA 固件升级(kUI_JL_DEVICE_OTA)、AI 云服务(AI云服务/ 目录)、表盘/UI 管理(DialUICache、JLDialInfoExtentedModel)、HTTP 账户体系(JLWatchHttp、BasicHttp)。

Overview

本 App 的硬件生态是杰理(Jieli)智能穿戴设备。所有设备交互都基于 JL_BLEKit 蓝牙 SDK,而 JL_RunSDK 是 App 侧对 SDK 的一层单例封装,承担:

  1. 设备发现:初始化 JL_BLEMultiple(多设备管理实例),开启设备过滤(BLE_FILTER_ENABLE)、配对(BLE_PAIR_ENABLE),并限定只搜索 Watch 类型设备;
  2. 连接管理:以 isConnecting 标志位 + linkedUuidArr 数组防止重复连接;通过 connectEntity:Result: 与 JL_EntityM_StatusPaired 状态判断连接成功;
  3. 状态广播:以自定义通知(如 kUI_JL_DEVICE_CHANGE)把连接状态变化广播给各页面(通过 JL_Tools add:Action:Own: 注册);
  4. 健康数据同步:连接成功后,SyncDataManager 触发设备数据同步,同时 UserDataSync 从服务器按 tb_heart_rate、tb_step、tb_oxyhemoglobin_saturation、tb_sleep 等表增量拉取历史数据,去重/合并后写入本地 SQLite,供健康图表页面使用。

Architecture

flowchart TD
    subgraph sg_App["App 层 (JieliJianKang)"]
        AppDelegate["AppDelegate<br/>(持有 bleSDK)"]
        JL_RunSDK["JL_RunSDK<br/>(单例: 连接管理)"]
        JLPrep["JLPreparation<br/>(设备准备流程)"]
        SyncMgr["SyncDataManager<br/>(设备数据同步)"]
        UserSync["UserDataSync<br/>(服务器数据同步)"]
    end

    subgraph sg_SDK["JL_BLEKit 蓝牙 SDK"]
        BleMultiple["JL_BLEMultiple<br/>(BLE_FILTER_ENABLE / BLE_PAIR_ENABLE)"]
        Entity["JL_EntityM<br/>(设备实体/状态)"]
    end

    subgraph sg_Cloud["云端"]
        HealthAPI["健康数据 HTTP API<br/>(jwt-token 鉴权)"]
    end

    subgraph sg_Local["本地存储"]
        Sqlite["JLSqlite* 系列<br/>(tb_heart_rate / tb_step / ...)"]
        UserDefaults["NSUserDefaults<br/>(同步时间戳)"]
    end

    AppDelegate --> JL_RunSDK
    JL_RunSDK --> BleMultiple
    BleMultiple --> Entity
    JL_RunSDK -->|"状态通知 kUI_JL_DEVICE_CHANGE"| JLPrep
    JLPrep --> SyncMgr
    UserSync -->|"AFHTTPSessionManager + jwt-token"| HealthAPI
    UserSync -->|"增量写入"| Sqlite
    UserSync -->|"记录最后同步时间"| UserDefaults
    SyncMgr --> Sqlite

架构说明:

  • JL_RunSDK 是连接子系统的唯一入口(sharedMe 单例)。它包装 JL_BLEMultiple,所有 BLE 操作(扫描、连接、断开)都经由它,避免多个页面直接操作 SDK 造成状态竞争。
  • JL_BLEMultiple / JL_EntityM 属于 JL_BLEKit 框架,负责底层 CoreBluetooth 逻辑;JL_EntityM_StatusPaired 是连接成功的判定状态。
  • JLPreparation 在设备连接成功后执行"准备"流程(如初始化 SyncDataManager),isPreparateOK 标记准备是否完成。
  • UserDataSync 与设备无关,负责云端↔本地双向增量同步;SyncDataManager 负责设备↔本地同步。两者通过 SQLite 汇合,保证页面读到的数据一致。
  • NSUserDefaults 保存每个数据表的上次同步时间戳(如 LastHealthHeartRateUpeateTime),用于增量拉取与节流判断。

设备连接实现详解

单例与 SDK 初始化

JL_RunSDK 使用 dispatch_once 实现全局单例,在 init 中完成 BLE SDK 初始化。关键配置如下:

static JL_RunSDK *SDK = nil;
+(id)sharedMe{
    static dispatch_once_t predicate;
    dispatch_once(&predicate, ^{
        SDK = [[self alloc] init];
    });
    return SDK;
}
- (instancetype)init{
    self = [super init];
    if (self) {
        isConnecting = NO;
        preparationArr = [NSMutableArray new];
        linkedUuidArr  = [NSMutableArray new];
        connectMaxCount = 20;
        connectCount = 0;
        /*--- 初始化JL_SDK ---*/
        self.mBleMultiple = [[JL_BLEMultiple alloc] init];
        self.mBleMultiple.BLE_FILTER_ENABLE = YES;
        self.mBleMultiple.BLE_PAIR_ENABLE = YES;
        self.mBleMultiple.BLE_TIMEOUT = 10;
        /*--- 选择设备类型搜索 ---*/
        self.mBleMultiple.bleDeviceTypeArr = @[@(JL_DeviceTypeWatch)];//只选Watch
        self.mDialUICache = [[DialUICache alloc] init];
        self.dialInfoExtentedModel = [[JLDialInfoExtentedModel alloc] init];
        [self addNote];
    }
    return self;
}

Source: JL_RunSDK.m

设计意图:

  • 单例模式保证 App 全局只有一套 BLE 连接状态机,页面之间共享同一份 JL_EntityM,避免多实例重复连接同一设备;
  • BLE_FILTER_ENABLE = YES 只接受杰理协议的设备广播;BLE_PAIR_ENABLE = YES 开启配对流程;BLE_TIMEOUT = 10(秒)控制连接超时;
  • bleDeviceTypeArr = @[@(JL_DeviceTypeWatch)] 将扫描范围限定为 Watch 类型,过滤掉耳机、音箱等其他杰理设备;
  • connectMaxCount = 20 是连接重试上限计数(配合 connectTimer 使用,见下文)。

主动连接:connectDevice

-(void)connectDevice:(JL_EntityM*)entityM callBack:(void (^)(BOOL))callBack{
    if (isConnecting) {
        kJLLog(JLLOG_WARN, @"isConnecting,please wait");
        callBack(NO);
        return;
    }
    if ([linkedUuidArr containsObject:entityM.mUUID]) {
        kJLLog(JLLOG_WARN, @"isLinked,please don't connect again! %@",entityM.mUUID);
        callBack(YES);
        return;
    }
    [self startTimer];
    kJLLog(JLLOG_INFO, @"connectDevice:%@,item:%@", entityM.mUUID,entityM.mItem);
    isConnecting = YES;
    [self.mBleMultiple connectEntity:entityM Result:^(JL_EntityM_Status status) {
        if (status == JL_EntityM_StatusPaired) {
            [self setMBleEntityM:entityM];
            callBack(YES);
        }else{
            callBack(NO);
        }
        self->isConnecting = NO;
        [self stopTimer];
    }];
}

Source: JL_RunSDK.m

这段代码体现了三层防护:

  1. 重入保护:isConnecting 为 YES 时直接拒绝新连接请求,保证同一时刻只有一个连接流程在跑;
  2. 去重保护:linkedUuidArr 记录已连接设备的 UUID,重复连接同一设备直接回调 YES(幂等);
  3. 超时兜底:startTimer 启动连接计时器,防止 SDK 回调永远不触发导致 isConnecting 卡死;成功/失败回调中都会 stopTimer 并复位标志位。

连接成功的判定是 JL_EntityM_StatusPaired——即设备完成配对,此时通过 setMBleEntityM: 保存当前设备实体。此外还提供 connectDeviceMac:callBack: 通过 MAC 地址连接(同文件第 116 行起),用于已知设备的快速重连。

连接状态广播

连接状态的变化通过自定义通知广播给所有关注页面:

NSString *kUI_JL_DEVICE_CHANGE          = @"UI_JL_DEVICE_CHANGE";
NSString *kUI_JL_DEVICE_PREPARING       = @"UI_JL_DEVICE_PREPARING";
NSString *kUI_JL_DEVICE_OTA             = @"UI_JL_DEVICE_OTA";
NSString *kUI_JL_BLE_SCAN_OPEN          = @"UI_JL_BLE_SCAN_OPEN";
NSString *kUI_JL_BLE_SCAN_CLOSE         = @"UI_JL_BLE_SCAN_CLOSE";
NSString *kUI_RECONNECT_TO_DEVICE       = @"UI_RECONNECT_TO_DEVICE";

Source: JL_RunSDK.m

通知的注册与监听通过 JL_Tools 工具类完成(基于 NSNotificationCenter 的封装)。AppDelegate 中可以看到典型的注册方式:

[JL_Tools add:kJL_BLE_M_EDR_CHANGE Action:@selector(noteEdrChange:) Own:self];

Source: AppDelegate.m

设计意图:连接状态(扫描开启/关闭、设备变化、准备中、OTA 中、需要重连)是跨页面共享的系统级事件,用通知而非回调链可以解耦——无论当前处于搜索页、首页还是设置页,都能感知设备状态变化并刷新 UI。

Core Flow:连接 → 准备 → 同步

sequenceDiagram
    participant UI as 搜索/首页 UI
    participant SDK as JL_RunSDK
    participant BLE as JL_BLEMultiple (BLEKit)
    participant Prep as JLPreparation
    participant SM as SyncDataManager
    participant US as UserDataSync
    participant Cloud as 健康数据 API
    participant DB as JLSqlite* (SQLite)

    UI->>SDK: sharedMe (单例初始化)
    SDK->>BLE: 初始化(过滤/配对/超时10s, 仅Watch)
    UI->>SDK: connectDevice:callBack:
    SDK->>SDK: isConnecting 检查 + linkedUuidArr 去重
    SDK->>BLE: connectEntity:Result:
    BLE-->>SDK: JL_EntityM_StatusPaired
    SDK->>SDK: setMBleEntityM: + 回调 YES + 复位 isConnecting
    SDK-->>UI: 通知 kUI_JL_DEVICE_CHANGE / kUI_JL_DEVICE_PREPARING
    UI->>Prep: 进入准备流程
    Prep->>SM: [SyncDataManager share] 启动设备数据同步
    SM-->>DB: 读取/写入设备健康数据
    US->>Cloud: 校验登录态 + 10小时节流
    Cloud-->>US: 增量健康数据 (按表)
    US->>DB: 解析为图表模型并 s_sync_update:
    US->>US: 更新 NSUserDefaults 同步时间戳

流程要点:

  1. 连接阶段:JL_RunSDK 是唯一入口,内部通过 isConnecting/linkedUuidArr 双重防护后调用 JL_BLEMultiple connectEntity:Result:;回调 JL_EntityM_StatusPaired 才算连接成功,随后广播 kUI_JL_DEVICE_CHANGE 并记录 UUID。
  2. 准备阶段:JLPreparation 在连接成功后执行准备流程,其中关键一步是 [SyncDataManager share]——它负责设备侧健康数据的同步(见 JLPreparation.m),并用 isPreparateOK 标记流程是否完成。
  3. 云同步阶段:UserDataSync updateHealthAndSportDataFile 在后台低优先级队列中按表(心率/步数/血氧/睡眠等)增量拉取,先查本地最后一条数据的 startDate 作为拉取起点,再合并写入 SQLite,最后更新时间戳。
  4. 持久化阶段:所有健康数据最终落在 JLSqlite* 系列类(如 JLSqliteHeartRate、JLSqliteStep、JLSqliteOxyhemoglobinSaturation)对应的表中,健康图表页面直接读取本地库,避免频繁请求网络。

健康数据同步实现详解(UserDataSync)

同步时间戳与节流

#define LastHealthHeartRateUpeateTime             @"LastHealthHeartRateUpeateTime"///上一次心率健康数据下载时间
#define LastHealthStepCountUpdateTime             @"LastHealthStepCountUpdateTime"///上一次步数健康数据下载时间
#define LastHealthSpoDataUpdateTime               @"LastHealthSpoDataUpdateTime"///上一次血氧健康数据下载时间
#define LastHealthSleepDataUpdateTime             @"LastHealthSleepDataUpdateTime"///上一次睡眠健康数据下载时间
#define LastHealthWeightDataUpdateTime            @"LastHealthWeightDataUpdateTime"///上一次体重健康数据下载时间
#define LastSportUpdateTime                       @"LastSportUpdateTime"///上一次运动数据下载时间
#define LastAllDataUpdateTime                     @"LastAllDataUpdateTime"///上一次所有数据下载时间

Source: UserDataSync.m

每种数据类型都有独立的"上次下载时间"键,并且 LastAllDataUpdateTime 作为全局节流闸门——updateHealthAndSportDataFile 在 10 小时内(36000 秒)不会重复拉取:

+ (void)updateHealthAndSportDataFile {
    if ([self notLoggedIn]) {
        return;
    }
    NSDate *lastAllDataUpdateTime = [[NSUserDefaults standardUserDefaults] objectForKey:[self getUserLastUpeateTimeKeyWithKey:LastAllDataUpdateTime]];
    NSTimeInterval lastAllDataUpdateTimeInterval = [lastAllDataUpdateTime timeIntervalSince1970];
    NSTimeInterval currentTimeInterval = [[NSDate date] timeIntervalSince1970];
    if ((currentTimeInterval - lastAllDataUpdateTimeInterval) < 36000) {
        return;  // 10小时内不再从服务器拉取
    }
    [[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:[self getUserLastUpeateTimeKeyWithKey:LastAllDataUpdateTime]];
    __weak typeof(self) weakSelf = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
        // 同步服务器用户健康数据
        [JLSqliteHeartRate s_checkoutTheLastDataWithResult:^(JLWearSyncHealthHeartRateChart * _Nonnull chart) {
            ...
            [UserDataSync requestHealthDataBetween:startDate End:[NSDate date] ByTableName:tb_heart_rate result:^(NSArray<UserDataHealth *> * _Nonnull array) {
                ...
                for (UserDataHealth *data in array) {
                    JLWearSyncHealthHeartRateChart *chart = [[JLWearSyncHealthHeartRateChart alloc] initChart:data.data];
                    [JLSqliteHeartRate s_sync_update:chart];
                }
                ...
            }];
        }];
        ...
    });
}

Source: UserDataSync.m

设计意图与关键机制:

  • 节流(10 小时):健康数据是低频变化数据,10 小时的全局闸门大幅减少服务器压力与流量消耗;每个表还有独立的 LastHealth*UpdateTime 用于更细粒度的增量判断。
  • 增量拉取:以本地 SQLite 中该表最后一条数据的 startDate 为起点(无数据则从 1970 开始),End 为当前时间,实现"只拉缺失区间"。
  • 低优先级后台队列:整个同步放在 DISPATCH_QUEUE_PRIORITY_LOW 全局队列,避免阻塞 UI 线程;同步完成后 UI 通过数据库通知/刷新。
  • 合并写入:服务器数据先包装为对应图表模型(JLWearSyncHealthHeartRateChart、JL_Chart_MoveSteps、JL_Chart_OxyhemoglobinSaturation 等),再调用 s_sync_update:/s_update: 与本地数据合并去重。

鉴权与请求管理

+(AFHTTPSessionManager *)reqMgr{
    NSString *token = [JL_Tools getUserByKey:kUI_ACCESS_TOKEN];
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    [AFJSONRequestSerializer serializer].cachePolicy = NSURLRequestReturnCacheDataElseLoad;
    [manager setRequestSerializer:[AFJSONRequestSerializer serializer]];
    [manager.requestSerializer setValue:token forHTTPHeaderField:@"jwt-token"];
    return manager;
}

Source: UserDataSync.m

所有云同步请求共用 reqMgr:从 NSUserDefaults(键 kUI_ACCESS_TOKEN)取出登录 token 放入 jwt-token 请求头;采用 AFNetworking 的 AFHTTPSessionManager,JSON 序列化并启用"有缓存则读缓存"策略,进一步降低重复请求成本。未登录时(notLoggedIn)直接返回,不做任何同步。

Configuration Options

连接与同步子系统的可配置项(均在代码中直接设置或通过 NSUserDefaults 持久化):

选项类型默认值说明位置
BLE_FILTER_ENABLEBOOLYES是否启用杰理协议设备过滤,只连接合法杰理设备JL_RunSDK.m L74
BLE_PAIR_ENABLEBOOLYES是否启用配对流程JL_RunSDK.m L75
BLE_TIMEOUTNSTimeInterval10(秒)BLE 连接超时时间JL_RunSDK.m L76
bleDeviceTypeArrNSArray@[@(JL_DeviceTypeWatch)]可搜索的设备类型集合,当前仅 WatchJL_RunSDK.m L80
connectMaxCountint20连接重试最大计数(配合 connectTimer)JL_RunSDK.m L70
LastAllDataUpdateTimeNSDate (UserDefaults)nil全局云同步节流时间戳,间隔 < 36000s 跳过拉取UserDataSync.m L30/L53-L60
LastHealth*UpdateTimeNSDate (UserDefaults)nil各健康类型(心率/步数/血氧/睡眠/体重/运动)上次下载时间UserDataSync.m L23-L29
tb_heart_rate 等表名NSString固定表名服务器健康数据表名(心率/步数/血氧/睡眠)UserDataSync.m L71-L122
sport / sport_downloadNSString (路径)文档目录子路径运动数据文件上传/下载目录UserDataSync.m L32-L33
kUI_ACCESS_TOKENNSString (UserDefaults)nil登录 token,写入 jwt-token 请求头UserDataSync.m L38

API Reference

+(id)sharedMe

获取 JL_RunSDK 全局单例(dispatch_once 保证只初始化一次)。

Returns: JL_RunSDK 实例。

-(void)connectDevice:(JL_EntityM*)entityM callBack:(void (^)(BOOL))callBack

主动连接指定 BLE 设备。

Parameters:

  • entityM (JL_EntityM*):目标设备实体(来自扫描结果);
  • callBack (void (^)(BOOL)):连接结果回调,YES 表示已配对成功。

行为: 若 isConnecting 为 YES 立即回调 NO;若 UUID 已在 linkedUuidArr 中直接回调 YES(幂等);否则启动连接计时器并调用 mBleMultiple connectEntity:Result:,配对成功后调用 setMBleEntityM: 并复位 isConnecting/停止计时器。

-(void)connectDeviceMac:(NSString*)mac callBack:(void (^)(BOOL))callBack

通过 MAC 地址连接已知设备(用于快速重连场景),语义与 connectDevice: 一致。

+ (void)updateHealthAndSportDataFile

同步云端健康与运动数据到本地 SQLite。

前置条件: 已登录(否则直接返回);距上次全局同步超过 36000 秒(10 小时节流)。

行为: 在低优先级后台队列中,分别查询本地各表最后一条数据的 startDate 作为起点,调用 requestHealthDataBetween:End:ByTableName:result: 拉取增量,解析为图表模型后经 s_sync_update:/s_update: 合并写入 SQLite,最后更新各表时间戳。

+(AFHTTPSessionManager *)reqMgr

构建携带 jwt-token 请求头的 AFNetworking 会话管理器(JSON 序列化 + 缓存优先策略)。

Failure Modes, Edge Cases & Concurrency

并发与重入保护

  • isConnecting 互斥标志:同一时刻只允许一个连接流程。UI 上快速连续点击"连接"时,后到请求直接回调 NO 并打 JLLOG_WARN 日志,防止 JL_BLEMultiple 进入不一致状态。
  • linkedUuidArr 幂等去重:对已连接设备重复发起连接会直接返回 YES,避免蓝牙层重复 pair 造成设备端异常。
  • 连接计时器兜底:connectTimer + connectCount/connectMaxCount(20) 用于处理 SDK 回调丢失的极端情况,防止 isConnecting 永久卡死导致后续连接全部被拒。

边界条件

  • 未登录:UserDataSync notLoggedIn 时云同步直接跳过,本地 SQLite 仍可正常读写,App 保持离线可用。
  • 首次使用无本地数据:chart.xxxList.firstObject.startDate == nil 时起点回退到 1970-01-01(dateWithTimeIntervalSince1970:0),保证全量拉取不漏数据。
  • 同步节流窗口:10 小时内重复调用 updateHealthAndSportDataFile 会被静默跳过(日志被注释掉,线上无噪音),时间戳在进入节流判断前就已更新,避免并发调用穿透节流。

数据一致性

  • 云端数据合并采用"查本地最后一条 → 拉取其后区间 → s_sync_update: 合并"策略,天然去重且不会覆盖本地较新的设备数据;
  • 各表独立时间戳(心率/步数/血氧/睡眠/体重/运动)允许部分表同步失败后其余表仍能正常推进,互不阻塞;
  • 同步全部在 DISPATCH_QUEUE_PRIORITY_LOW 后台队列执行,配合 __weak self 防止循环引用,UI 线程不受影响。

失败处理

  • 连接失败:回调 NO,isConnecting 复位,计时器停止,UI 依据 kUI_JL_DEVICE_CHANGE 通知刷新状态;
  • token 失效:jwt-token 请求返回 401 时由上层 HTTP 层(JLWatchHttp/BasicHttp)统一处理,本子系统只负责携带 token;
  • 设备中途断开:通过 kUI_RECONNECT_TO_DEVICE 通知触发重连路径(connectDeviceMac: 快速重连)。

Extension Points

  • 通知机制:JL_RunSDK 通过 JL_Tools add:Action:Own: 注册/广播自定义通知(kUI_JL_DEVICE_CHANGE、kUI_JL_DEVICE_PREPARING、kUI_JL_BLE_SCAN_OPEN/CLOSE 等)。新增页面只需监听对应通知即可感知连接状态,无需改动连接核心。
  • 设备类型扩展:bleDeviceTypeArr 当前仅含 JL_DeviceTypeWatch;若产品线增加新设备类型(如手环),只需向该数组追加枚举值。
  • 新增健康数据类型:仿照心率/步数/血氧的模板——在 UserDataSync 中增加 LastHealthXxxUpdateTime 键 + requestHealthDataBetween:...ByTableName: 分支 + 对应的 JLSqlite* 落库类即可接入同一条增量同步链路。
  • 底层 SDK 替换:所有 BLE 操作都收敛在 JL_RunSDK 对 JL_BLEMultiple 的封装之后,上层页面不直接触碰 JL_BLEKit,SDK 升级或替换时影响面可控。

Tests

仓库中未发现针对 JL_RunSDK / UserDataSync 的独立单元测试用例(测试目录以 UI 页面验证为主)。连接与同步逻辑的正确性主要依赖:kJLLog 运行日志(连接警告、同步流程日志)、真机 BLE 联调、以及 NSUserDefaults 时间戳的持久化行为验证。建议后续补充:连接状态机单元测试(isConnecting/linkedUuidArr 分支覆盖)与增量拉取区间计算的纯函数测试。

Related Links

  • JL_RunSDK.m(连接管理核心)
  • UserDataSync.m(云健康数据同步)
  • JLPreparation.m(设备准备流程)
  • AppDelegate.m(SDK 初始化与通知注册)
  • 相邻能力页:OTA 固件升级(kUI_JL_DEVICE_OTA)、AI 云服务、表盘/UI 管理(DialUICache)、账户体系(JLWatchHttp)
Prev
健康界面与数据可视化
Next
登录注册与用户中心