杰理 SDK 文档中心
首页
首页
  • SDK 框架库

    • JL_BLEKit 蓝牙通信核心
    • JL_AdvParse 广播包解析
    • JL_HashPair 加密配对
    • JL_OTALib 固件升级
    • JLDialUnit 彩屏仓与表盘控制
    • JLBmpConvertKit 位图转换
    • JLPackageResKit 资源包处理
    • JLLogHelper 日志工具
  • 核心功能模块

    • 音乐与媒体控制
    • 音效调节与均衡器
    • 设备发现、连接与设置
    • Auracast 广播接收与发射
    • 文件浏览、闹钟、FM 与灯光控制
    • ANC、按键设置与查找设备
    • AI 翻译与自定义命令
  • 应用架构与工程支撑

    • 杰理之家 App 架构与导航
    • 数据存储与缓存
    • Swift 工具与扩展层
    • JLAudioUnitKit 示例工程
    • SDKTestHelper 测试工具
  • 开发文档与资源

    • 文档中心与 JL_OTALib API 说明
    • 自定义蓝牙接入方式
    • 调试技巧与问题排查
    • 版本历史与社区支持

JLDialUnit 彩屏仓与表盘控制

JLDialUnit 是杰理(Jieli)iOS 蓝牙 SDK 中的表盘管理框架,负责彩屏设备(如智能手表)的文件资源仓(彩屏仓)管理与表盘(Dial)的读取、设置、自定义背景激活等控制操作。本页完整介绍该框架的公共 API、数据模型、核心流程与集成方式。

Purpose and Scope

本页面向需要集成 JLDialUnit 框架的 iOS 开发者,覆盖以下内容:

  • JLDialUnitMgr 核心管理器:初始化、文件列表(彩屏仓)管理、文件传输/删除、剩余空间查询、表盘控制等全部公共接口;
  • JLDialSourceModel 数据模型:表盘/背景资源在 App 侧的表示形式;
  • 框架依赖的底层模块(JL_BLEKit、JLFlashOpMgr、JLModel_File)及其协作关系;
  • 表盘更新、背景激活的端到端控制流、失败模式与注意事项。

不涉及的内容(由同级目录页负责):JL_BLEKit 底层蓝牙连接与协议细节(见 3.1 相关章节)、JLDialUnit 之外的音频/文件系统框架(如 JL_FlashOperate 的通用文件操作页)。本页聚焦于 彩屏仓(文件资源管理)与表盘控制 这一能力边界。

Overview

JLDialUnit 以 xcframework 二进制框架形式发布(包含 ios-arm64 与 ios-arm64_x86_64-simulator 双架构),公开头文件由伞头 JLDialUnit.h 统一导出:

#import <JLDialUnit/DialManager.h>
#import <JLDialUnit/FatfsObject.h>
#import <JLDialUnit/ZipZap.h>
#import <JLDialUnit/ZZArchive.h>
#import <JLDialUnit/ZZArchiveEntry.h>
#import <JLDialUnit/ZZConstants.h>
#import <JLDialUnit/ZZError.h>
#import <JLDialUnit/JLDialSourceModel.h>
#import <JLDialUnit/JLDialUnitMgr.h>
#import <JLDialUnit/JLSourceUpdate.h>

Source: JLDialUnit.h

从导出头文件可以归纳框架的职责分层:

  • JLDialUnitMgr(入口门面):面向业务层的唯一主要入口,封装了彩屏仓文件操作与表盘控制;
  • JLDialSourceModel(资源模型):继承自 JL_BLEKit 的 JLModel_File,附加 size、crc 字段,表示一个可下发/可管理的表盘或背景文件;
  • DialManager / FatfsObject / JLSourceUpdate:内部文件系统(FATFS)操作与资源更新辅助类;
  • ZipZap / ZZArchive 系列:ZIP 归档解析工具,用于解包表盘资源包(表盘通常以压缩包形式分发)。

框架底层依赖 JL_BLEKit(蓝牙协议栈,提供 JL_ManagerM 连接管理、JLFlashOpMgr Flash 操控句柄、JLModel_File 设备文件模型、JL_CardType/JL_FileHandleType 枚举),以及 JLLogHelper(日志)与 JL_HashPair(哈希配对)。

设计意图:框架层把"设备文件系统"抽象为"App 侧资源仓"。开发者不需要理解 BLE 协议如何分片传输、FATFS 如何寻址,只需操作 JLDialSourceModel 对象数组,由 JLDialUnitMgr 内部通过 JLFlashOpMgr 完成与设备的同步。

Architecture

flowchart TD
    subgraph sg_App["App 应用层"]
        App["App 业务代码"]
    end

    subgraph sg_DialUnit["JLDialUnit 框架"]
        Mgr["JLDialUnitMgr"]
        SourceModel["JLDialSourceModel"]
        DialMgr["DialManager"]
        Fatfs["FatfsObject"]
        Zip["ZipZap / ZZArchive"]
        Update["JLSourceUpdate"]
    end

    subgraph sg_BLEKit["JL_BLEKit 底层"]
        BLEKit["JL_ManagerM"]
        FlashOp["JLFlashOpMgr"]
        FileModel["JLModel_File"]
        CardType["JL_CardType"]
    end

    App -->|"初始化/调用"| Mgr
    Mgr -->|"持有"| SourceModel
    Mgr -->|"文件列表"| CardType
    Mgr -->|"Flash 操控"| FlashOp
    Mgr -->|"内部辅助"| DialMgr
    Mgr -->|"内部辅助"| Fatfs
    Mgr -->|"内部辅助"| Zip
    Mgr -->|"内部辅助"| Update
    SourceModel -->|"继承"| FileModel
    FlashOp -->|"BLE 通道"| BLEKit

架构说明:

  • JLDialUnitMgr 是框架对外暴露的"门面"(Facade),业务层只需持有这一个对象即可完成彩屏仓与表盘的全部操作;
  • JLDialSourceModel 继承 JLModel_File(来自 JL_BLEKit),使设备侧文件模型可以在 App 侧直接复用,同时新增 size(文件大小)与 crc(校验值)以支撑表盘资源包完整性校验;
  • JLFlashOpMgr 是 JL_BLEKit 提供的 Flash 操控句柄,JLDialUnitMgr 通过属性 currentFlaghOpMgr 暴露给上层,实际的文件读取、写入、删除指令都由它承载;
  • DialManager、FatfsObject、ZipZap、JLSourceUpdate 为框架内部实现细节,外部一般不直接使用,但可通过伞头引用;
  • 每次 JLDialUnitMgr 初始化都绑定一个 JL_ManagerM(蓝牙管理对象),即 一个蓝牙连接对应一个表盘管理器实例。

JLDialUnitMgr 核心管理器详解

JLDialUnitMgr 是框架的核心类,接口定义于 JLDialUnitMgr.h。其 API 按职责可分为三组:状态属性、彩屏仓(文件)操作、表盘控制。

状态属性

@property (nonatomic,strong)NSMutableArray <JLDialSourceModel *> *fileArray;
@property (nonatomic, strong) JLFlashOpMgr *currentFlaghOpMgr;
@property (nonatomic,strong)JLDialSourceModel *currentFileSource;
@property (nonatomic,strong)JLDialSourceModel *_Nullable currentBackground;

Source: JLDialUnitMgr.h

  • fileArray:App 侧缓存的设备文件列表(即"彩屏仓"),由 getFileList:/updateFileSources: 填充;
  • currentFlaghOpMgr:当前 Flash 操控句柄,是框架与设备文件系统交互的桥梁;
  • currentFileSource:当前正在使用的表盘文件模型(设置表盘后更新);
  • currentBackground:当前使用的自定义表盘背景(可空,未激活自定义背景时为 nil)。

初始化与生命周期

-(instancetype)initWithManager:(JL_ManagerM*)mgr completion:(void (^)(NSError * _Nullable))completion;

Source: JLDialUnitMgr.h

初始化需要传入一个已建立(或可建立)连接的 JL_ManagerM。完成回调返回 NSError,为 nil 表示初始化成功。设计上采用 回调而非同步返回,是因为初始化内部可能涉及与设备的握手/能力探测,属于异步操作。框架以强引用持有 JLFlashOpMgr(currentFlaghOpMgr),因此 JLDialUnitMgr 的生命周期应长于一次表盘操作会话,通常与蓝牙连接会话保持一致。

彩屏仓:文件列表管理

-(void)getFileList:(JL_CardType)cardType count:(NSInteger)count completion:(void (^)(NSArray <JLDialSourceModel *> * _Nullable,NSError * _Nullable))completion;
-(void)cleanFileList;
-(void)updateFileSources:(NSArray<JLModel_File *> *)fileSources completion:(void (^)(NSArray<JLDialSourceModel *> * _Nullable,NSError * _Nullable))completion;

Source: JLDialUnitMgr.h

  • getFileList:count:completion::按存储卡类型(JL_CardType,如内置 Flash 或外置 TF 卡)请求文件列表。count 为请求的条目数,回调返回的是累计数目——即支持分页累加获取,业务层可多次调用直至取完全部文件;
  • cleanFileList:清空 fileArray,用于切换设备/刷新前重置本地缓存;
  • updateFileSources:completion::直接用 JL_BLEKit 层拿到的 JLModel_File 数组更新列表。框架内部会将 JLModel_File 逐个转换为 JLDialSourceModel(见下文模型转换),转换失败时通过 error 回调上报。

设计意图:getFileList 走框架内部分页累加逻辑,updateFileSources 则允许业务层在已经通过其他途径(如 JL_BLEKit 原生接口)获得文件模型时直接注入,避免重复读取,保持与底层数据源的一致性。

彩屏仓:文件写入、删除与空间查询

-(void)updateFileToDevice:(JL_FileHandleType)fileHandleType Data:(NSData *)fileData FilePath:(NSString *)filePath completion:(void (^)(int,double,NSError * _Nullable))resultCompletion;
-(void)deleteFile:(NSString *)filePath getFileList:(BOOL)isGet Completion:(void (^)(BOOL state, NSError * _Nullable error))resultCompletion;
-(void)deleteFiles:(NSArray <NSString*>*) filePathList Completion:(void (^)(BOOL state, NSError * _Nullable error))resultCompletion;
-(void)getRemainingSpace:(void(^)(int freeSize, NSError * _Nullable error))completion;
-(void)getFlashRemainingSpace:(void(^)(int freeSize, NSError * _Nullable error))completion;

Source: JLDialUnitMgr.h

  • updateFileToDevice:Data:FilePath:completion::将表盘/背景资源数据(NSData)下发到设备。fileHandleType 指定目标存储句柄(JL_FileHandleType),filePath 指定设备侧存储路径。回调三元组含义:state(0 成功 / 1 传输中 / -1 失败)、progress(传输进度 0~100)、error。进度回调是幂等可重复触发的,业务层应据此刷新进度条 UI;
  • deleteFile:getFileList:Completion: / deleteFiles:Completion::单个/批量删除设备文件。单个删除可通过 isGet 控制删除完成后是否自动重新拉取文件列表(保持 fileArray 同步);
  • getRemainingSpace: 与 getFlashRemainingSpace::查询剩余空间(单位由设备协议决定,通常为字节/KB),前者为通用接口,后者为 V1 版本专用接口。下发大文件前应先查询剩余空间,避免写入失败。

表盘控制

-(void)dialGetCurrent:(void (^)(JLDialSourceModel * _Nullable))completion;
-(void)dialSetCurrent:(JLDialSourceModel *)model Completion:(void (^)(BOOL state, NSError * _Nullable error))resultCompletion;
-(void)dialActiveCustomBackground:(JLDialSourceModel *)model Completion:(void (^)(BOOL state, NSError * _Nullable error))resultCompletion;
-(void)dialResetCustomBackground:(void (^)(BOOL state, NSError * _Nullable error))resultCompletion;
-(void)dialGetDial:(NSString *)path BackgroundInfo:(void (^)(JLDialSourceModel * _Nullable model, NSError * _Nullable error))resultCompletion;

Source: JLDialUnitMgr.h

  • dialGetCurrent::查询设备当前正在使用的表盘,结果模型经 currentFileSource 同步;
  • dialSetCurrent:Completion::切换设备当前表盘。state == YES 表示成功;失败时 error 携带原因(如文件不存在、CRC 校验失败);
  • dialActiveCustomBackground:Completion::激活自定义表盘背景。背景文件须已存在于设备(通常先经 updateFileToDevice: 下发),激活后 currentBackground 更新;
  • dialResetCustomBackground::重置自定义背景,恢复默认背景;
  • dialGetDial:BackgroundInfo::按路径(如 /WATCH)查询目录下的表盘背景信息,返回该背景的 JLDialSourceModel。

设计意图:表盘与背景分离为两套指令,是因为彩屏设备通常支持"表盘主体 + 可替换背景"的组合模式。dialSetCurrent: 面向表盘主体切换,dialActiveCustomBackground: 面向背景层替换,二者独立状态,框架通过 currentFileSource 与 currentBackground 分别跟踪。

JLDialSourceModel 数据模型

@interface JLDialSourceModel : JLModel_File

@property (nonatomic, assign)int size;
@property (nonatomic, assign)uint16_t crc;

+(JLDialSourceModel *)createModel:(JLModel_File *)model;

@end

Source: JLDialSourceModel.h

JLDialSourceModel 是 JLModel_File(设备文件模型,含文件名、路径、属性等)的子类,扩展了两个字段:

  • size:资源文件字节大小,用于传输前校验与进度计算;
  • crc:16 位 CRC 校验值,用于表盘资源完整性校验(设备侧写入后回读比对,或作为设置表盘前的合法性依据)。

工厂方法 createModel: 负责从底层 JLModel_File 转换,转换时拷贝文件元信息并(可能)读取设备侧返回的 size/crc。该工厂模式将"底层模型 → 业务模型"的映射集中在一处,避免业务层散落转换逻辑。

核心流程:表盘资源下发与切换

一次完整的"表盘更新"端到端流程如下(以时序图展示 App 与框架、底层、设备间的协作):

sequenceDiagram
    participant App as App 业务层
    participant Mgr as JLDialUnitMgr
    participant Flash as JLFlashOpMgr
    participant Dev as 设备 (BLE)
    participant Model as JLDialSourceModel

    App->>Mgr: initWithManager:completion:
    Mgr-->>App: completion(nil) 初始化完成

    App->>Mgr: getRemainingSpace:
    Mgr->>Flash: 查询剩余空间
    Flash-->>Mgr: freeSize
    Mgr-->>App: freeSize / error

    App->>Mgr: updateFileToDevice:Data:FilePath:
    Mgr->>Flash: 分片写入文件
    Flash-->>Mgr: progress 0~100
    Mgr-->>App: state=1, progress
    Flash-->>Mgr: 写入完成
    Mgr-->>App: state=0, progress=100

    App->>Mgr: getFileList:count:
    Mgr->>Flash: 拉取设备文件
    Flash-->>Mgr: JLModel_File 列表
    Mgr->>Model: createModel: 转换
    Mgr-->>App: JLDialSourceModel 数组

    App->>Mgr: dialSetCurrent:Completion:
    Mgr->>Flash: 下发设置表盘指令
    Flash-->>Dev: BLE 指令
    Dev-->>Flash: 应答(CRC 校验)
    Flash-->>Mgr: 结果
    Mgr-->>App: state=YES / error

流程要点:

  1. 初始化:initWithManager: 绑定蓝牙连接,异步回调确认就绪;
  2. 空间预检(推荐):大文件下发前先查询剩余空间,避免中途失败;
  3. 文件下发:updateFileToDevice: 内部由 JLFlashOpMgr 完成 BLE 分片传输,state=1 + progress 回调驱动进度条;
  4. 列表刷新:下发完成后通过 getFileList:(或 deleteFile:getFileList:YES)刷新 fileArray,使新文件出现在彩屏仓中;
  5. 表盘切换:dialSetCurrent: 从彩屏仓中选中目标模型,设备侧校验(含 CRC)后切换生效。

设置自定义背景的补充流程

flowchart LR
    A["dialGetDial:/WATCH 查询背景"] --> B["updateFileToDevice: 下发背景资源"]
    B --> C["getFileList: 确认文件已存在"]
    C --> D{"dialActiveCustomBackground:"}
    D -->|"state=YES"| E["currentBackground 更新"]
    D -->|"state=NO"| F["error 上报,保留原背景"]

自定义背景流程比表盘切换多一步"激活":背景文件先作为普通文件下发到设备(如 /WATCH 目录),随后调用 dialActiveCustomBackground: 使设备将其作为当前背景渲染。若需恢复默认,调用 dialResetCustomBackground:。

使用示例

以下示例均依据 JLDialUnitMgr.h 的公开接口编写,展示了业务层的典型调用方式。

初始化管理器

// 假设已通过 JL_BLEKit 获得蓝牙管理对象 mgr
JLDialUnitMgr *dialMgr = [[JLDialUnitMgr alloc] initWithManager:mgr completion:^(NSError * _Nullable error) {
    if (error) {
        // 初始化失败:检查蓝牙连接状态后重试
    } else {
        // 初始化成功,可开始拉取彩屏仓
    }
}];

Source: JLDialUnitMgr.h

拉取彩屏仓文件列表(分页累加)

[dialMgr getFileList:JL_CardTypeFlash count:20 completion:^(NSArray<JLDialSourceModel *> * _Nullable models, NSError * _Nullable error) {
    if (error == nil && models.count > 0) {
        // 回调返回的是累计数目,可继续调用直至取完
        // models 已同步进 dialMgr.fileArray
    }
}];

Source: JLDialUnitMgr.h

下发表盘资源到设备并设置当前表盘

// 1. 下发资源文件
[dialMgr updateFileToDevice:JL_FileHandleTypeFlash Data:dialData FilePath:@"/WATCH/dial_01.bin"
                 completion:^(int state, double progress, NSError * _Nullable error) {
    if (state == 1) {
        // 传输中:progress 0~100,刷新进度条
    } else if (state == 0) {
        // 传输成功:刷新列表并设置表盘
        [dialMgr getFileList:JL_CardTypeFlash count:50 completion:^(NSArray<JLDialSourceModel *> * _Nullable models, NSError * _Nullable err) {
            JLDialSourceModel *target = [dialMgr.fileArray filteredArrayUsingPredicate:
                [NSPredicate predicateWithFormat:@"path == %@", @"/WATCH/dial_01.bin"]].firstObject;
            if (target) {
                [dialMgr dialSetCurrent:target Completion:^(BOOL state, NSError * _Nullable error) {
                    // state == YES:表盘已切换
                }];
            }
        }];
    } else {
        // state == -1:失败,error 携带原因
    }
}];

Source: JLDialUnitMgr.h 与 JLDialUnitMgr.h

激活 / 重置自定义背景

// 激活自定义背景(文件已存在于设备 /WATCH 目录)
[dialMgr dialActiveCustomBackground:backgroundModel Completion:^(BOOL state, NSError * _Nullable error) {
    // state == YES:背景已生效,dialMgr.currentBackground 已更新
}];

// 恢复默认背景
[dialMgr dialResetCustomBackground:^(BOOL state, NSError * _Nullable error) {
    // state == YES:已重置
}];

Source: JLDialUnitMgr.h

注意:以上示例中的 JL_CardTypeFlash、JL_FileHandleTypeFlash 为 JL_BLEKit 枚举的示意值,实际枚举名以 JL_BLEKit 头文件为准;JLDialSourceModel 的属性访问方式(如 path)继承自 JLModel_File,字段名以 JL_BLEKit 定义为准。

API 参考

JLDialUnitMgr 完整方法签名

初始化

- (instancetype)initWithManager:(JL_ManagerM *)mgr completion:(void (^)(NSError * _Nullable))completion

创建表盘管理器实例。

  • 参数:
    • mgr(JL_ManagerM *):蓝牙管理对象,须为已初始化且可用的连接;
    • completion(block):初始化结果回调,error == nil 表示成功。
  • 返回:JLDialUnitMgr 实例。
  • 设计说明:异步初始化,内部可能执行设备能力握手。

彩屏仓(文件列表)

- (void)getFileList:(JL_CardType)cardType count:(NSInteger)count completion:(void (^)(NSArray<JLDialSourceModel *> * _Nullable, NSError * _Nullable))completion

获取设备存储中的文件列表(支持分页累加)。

  • 参数:
    • cardType(JL_CardType):设备存储类型(内置 Flash / 外置卡);
    • count(NSInteger):本次请求的条目数;
    • completion(block):返回累计的模型数组;error 非空表示失败。
  • 注意:多次调用返回的数组是累计结果,业务层应循环调用直到取完或返回错误。

- (void)cleanFileList

清空本地 fileArray 缓存。无参数、无回调。适用于切换设备或强制刷新前。

- (void)updateFileSources:(NSArray<JLModel_File *> *)fileSources completion:(void (^)(NSArray<JLDialSourceModel *> * _Nullable, NSError * _Nullable))completion

以底层 JLModel_File 数组直接更新列表,内部转换为 JLDialSourceModel。

  • 参数:
    • fileSources:来自 JL_BLEKit 层的设备文件模型数组;
    • completion:转换后的模型数组;转换失败时 error 非空。

彩屏仓(文件传输)

- (void)updateFileToDevice:(JL_FileHandleType)fileHandleType Data:(NSData *)fileData FilePath:(NSString *)filePath completion:(void (^)(int, double, NSError * _Nullable))resultCompletion

将文件数据下发到设备指定路径。

  • 参数:
    • fileHandleType(JL_FileHandleType):目标存储句柄类型;
    • fileData(NSData *):文件二进制数据;
    • filePath(NSString *):设备侧存储路径(如 /WATCH/xxx.bin);
    • resultCompletion(block):参数依次为 state(0 成功 / 1 传输中 / -1 失败)、progress(0~100)、error。
  • 注意:state == 1 时 progress 持续更新,勿在此时移除回调对象。

- (void)deleteFile:(NSString *)filePath getFileList:(BOOL)isGet Completion:(void (^)(BOOL state, NSError * _Nullable error))resultCompletion

删除单个文件。

  • 参数:
    • filePath:设备侧文件路径;
    • isGet:删除完成后是否自动重新拉取文件列表;
    • resultCompletion:state == YES 表示删除成功。

- (void)deleteFiles:(NSArray<NSString *> *)filePathList Completion:(void (^)(BOOL state, NSError * _Nullable error))resultCompletion

批量删除多个文件(filePathList 为路径数组)。

- (void)getRemainingSpace:(void (^)(int freeSize, NSError * _Nullable error))completion

查询设备剩余空间(通用接口)。freeSize 为剩余字节数(单位以设备协议为准)。

- (void)getFlashRemainingSpace:(void (^)(int freeSize, NSError * _Nullable error))completion

查询 Flash 剩余空间(V1 版本专用接口)。

表盘控制

- (void)dialGetCurrent:(void (^)(JLDialSourceModel * _Nullable))completion

获取设备当前使用的表盘模型;设备无表盘时回调 nil。

- (void)dialSetCurrent:(JLDialSourceModel *)model Completion:(void (^)(BOOL state, NSError * _Nullable error))resultCompletion

设置当前表盘。

  • 参数:
    • model:目标表盘模型(须来自 fileArray 或 dialGetCurrent: 结果);
    • resultCompletion:state == YES 成功;失败时 error 说明原因(如文件不存在、校验失败)。
  • 副作用:成功后 currentFileSource 更新为 model。

- (void)dialActiveCustomBackground:(JLDialSourceModel *)model Completion:(void (^)(BOOL state, NSError * _Nullable error))resultCompletion

激活自定义表盘背景(文件须已存在于设备)。

  • 副作用:成功后 currentBackground 更新为 model。

- (void)dialResetCustomBackground:(void (^)(BOOL state, NSError * _Nullable error))resultCompletion

重置自定义表盘背景为默认背景。

  • 副作用:成功后 currentBackground 置为 nil。

- (void)dialGetDial:(NSString *)path BackgroundInfo:(void (^)(JLDialSourceModel * _Nullable model, NSError * _Nullable error))resultCompletion

按路径查询表盘背景信息。

  • 参数:
    • path:目录路径,如 /WATCH;
    • resultCompletion:返回该目录下背景资源的 JLDialSourceModel;查询失败时 error 非空。

JLDialSourceModel 方法

+ (JLDialSourceModel *)createModel:(JLModel_File *)model

从底层 JLModel_File 创建 JLDialSourceModel(拷贝文件元信息并填充 size/crc)。

  • 参数:model(JLModel_File *):设备文件模型。
  • 返回:JLDialSourceModel *。

关联底层类型(来自 JL_BLEKit)

类型说明
JL_ManagerM蓝牙协议栈管理对象,JLDialUnitMgr 初始化的入参
JLFlashOpMgrFlash 操控句柄,currentFlaghOpMgr 属性类型,承载文件读写删除指令
JLModel_File设备文件模型,JLDialSourceModel 的父类
JL_CardType存储卡类型枚举(文件列表查询参数)
JL_FileHandleType文件存储句柄类型枚举(文件下发参数)

配置选项

JLDialUnit 作为二进制框架不提供运行时配置文件(无 plist/appsettings 类配置)。"配置"主要体现在以下调用参数与状态上:

配置/参数类型默认/取值说明
cardType(getFileList:)JL_CardType由设备决定文件列表查询的存储介质(Flash / 外置卡)
count(getFileList:)NSInteger业务自定单次请求条目数,回调返回累计值
fileHandleType(updateFileToDevice:)JL_FileHandleType由目标存储决定下发目标存储句柄
filePathNSString如 /WATCH设备侧目录/文件路径,决定资源归类
isGet(deleteFile:)BOOL业务自定删除后是否自动刷新列表

提示:JL_CardType、JL_FileHandleType、JLModel_File 字段名等具体枚举/属性定义位于 JL_BLEKit 框架头文件中,集成时请查阅对应头文件以获取准确取值。

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

以下结论基于公共头文件契约与框架设计推断,具体错误码以设备协议/JL_BLEKit 文档为准。

常见失败模式

场景表现处理建议
蓝牙未连接/连接断开initWithManager: 回调 error;后续所有操作回调 error检查连接状态,重连后重建或复用管理器
剩余空间不足updateFileToDevice: 回调 state == -1下发前调用 getRemainingSpace: 预检,提示用户清理空间
目标路径不存在/非法写入或设置表盘失败先 getFileList: 确认目录结构,使用约定路径(如 /WATCH)
文件 CRC 校验失败dialSetCurrent: 返回失败重新下发资源(size/crc 字段可用于本地校验比对)
分页拉取中断getFileList: 累计数组不完整以回调 error 为终止条件,失败后重试或 cleanFileList 后重建
表盘/背景对象已过期设置时设备侧找不到对应文件设置前从最新 fileArray 中重新取模型,勿缓存旧对象

边界情况

  • 空彩屏仓:dialGetCurrent: 回调 nil,业务层应处理"设备无表盘"的引导界面;
  • 自定义背景未激活:currentBackground 为 nil,调用 dialResetCustomBackground: 幂等返回成功即可;
  • 大批量删除:deleteFiles: 一次性传入较多路径时,建议分批调用并依赖回调确认,避免单次指令超时;
  • 分页参数:getFileList:count: 的 count 过大可能超出设备单次响应能力,建议小步多次(如每次 20~50)。

并发与一致性

  • 回调线程:框架回调(completion/resultCompletion)的线程未在头文件中约定,建议业务层在回调内切换到主线程再刷新 UI(dispatch_async(dispatch_get_main_queue(), ...));
  • 串行操作:同一 JLDialUnitMgr 上的文件写入/删除/表盘设置应避免并发发起——BLE 通道本质上是串行分时复用,并发指令可能导致传输交错。推荐引入串行队列(如 NSOperationQueue 或信号量)包装所有框架调用;
  • 状态一致性:fileArray 由框架内部维护,业务层若通过 updateFileSources: 注入数据,应与 getFileList: 的结果语义保持一致;删除文件时优先使用 deleteFile:getFileList:YES 让框架自动同步列表;
  • 实例生命周期:一个 JLDialUnitMgr 对应一个 JL_ManagerM。设备切换时必须创建新实例并 cleanFileList,不能复用旧实例(其内部 currentFlaghOpMgr 指向旧连接)。

性能与运维注意事项

  • 传输进度:updateFileToDevice: 通过 state == 1 + progress 高频回调驱动 UI,注意避免在回调中做重活(如图片解码、磁盘 IO),防止进度卡顿;
  • 大文件策略:表盘资源包(尤其含 ZIP 解包流程的场景)体积较大,建议:① 下发前压缩(框架内 ZipZap/ZZArchive 提供解包能力,压缩可在服务端完成);② 拆分下发批次;③ 结合 size/crc 做完整性校验后重试;
  • 日志:框架依赖 JLLogHelper 输出日志,排查问题时开启该日志模块可跟踪文件操作指令序列;
  • 升级兼容:getFlashRemainingSpace: 为 V1 专用接口,新设备建议使用通用 getRemainingSpace:,并通过能力判断选择调用。

扩展点

  • 资源模型扩展:JLDialSourceModel 继承自 JLModel_File,业务层可继续子类化,附加自定义元数据(如缩略图、描述文案),在 getFileList: 回调中包装后使用;
  • 列表注入:updateFileSources: 允许业务层从其他数据源(服务端目录、历史缓存)注入文件模型,实现"离线彩屏仓"或混合数据源场景;
  • 背景组合:dialActiveCustomBackground: 与 dialResetCustomBackground: 提供背景层开关,可结合多套背景素材实现"表盘换肤"产品功能;
  • 文件打包:ZipZap/ZZArchive/ZZArchiveEntry 头文件对外公开,业务层可直接用于解析或生成表盘 ZIP 资源包(如从服务端下载的压缩表盘包解包后经 updateFileToDevice: 下发)。

测试与验证建议

仓库内未包含 JLDialUnit 框架的单元测试源码(框架以编译后 xcframework 形式发布,见 libs/JLDialUnit.xcframework)。集成验证可从以下角度覆盖:

  1. 链路冒烟:初始化 → getRemainingSpace: → getFileList: → dialGetCurrent:,确认设备在线且协议可用;
  2. 下发回环:updateFileToDevice: 到 100% 后 getFileList: 确认文件出现,再 deleteFile: 删除并确认列表同步;
  3. 表盘切换:多表盘交替 dialSetCurrent:,校验设备侧实际显示与 dialGetCurrent: 返回值一致;
  4. 背景激活:激活 → 重置 → 再激活,验证 currentBackground 状态机与设备显示一致;
  5. 异常注入:断连、空间不足、非法路径、重复调用场景下,验证回调 error 与业务提示的健壮性。

相关链接

  • JLDialUnitMgr.h(核心管理器接口)
  • JLDialUnit.h(框架伞头)
  • JLDialSourceModel.h(资源数据模型)
  • 集成 Demo:code/JieLi_Home_Demo(含 JLDialUnit 框架引用示例)
  • 蓝牙协议栈 JL_BLEKit:提供 JL_ManagerM、JLFlashOpMgr、JLModel_File、JL_CardType 等底层类型,详见 SDK 框架目录对应页面
  • 日志与工具库:JLLogHelper(日志)、JL_HashPair(哈希配对),均为 JLDialUnit 的编译依赖
Prev
JL_OTALib 固件升级
Next
JLBmpConvertKit 位图转换