健康SDK核心库 JL_Watch
杰理健康SDK(Android)的核心库,提供穿戴设备的主要功能——基于 RCSP 协议的设备控制、健康/运动数据同步、表盘与文件管理、OTA 升级等,是「宜动健康」等示例应用所有业务功能的地基。
Purpose and Scope
本页面向开发者完整说明 JL_Watch 核心库的架构定位、接入方式、核心抽象(WatchOpImpl)、功能模式、数据通路以及它与周边库的分工。
本页覆盖:
- JL_Watch 在健康 SDK 分层架构中的位置与职责
- 核心抽象
WatchOpImpl的契约方法(getConnectedDevice/sendDataToDevice)与设计意图 - 功能模式
FUNC_WATCH/FUNC_RCSP/FUNC_FILE_BROWSE的语义 - 从应用初始化到设备数据往返的完整控制流
- 与
jl_rcsp、jl_bluetooth_connect、jl_bt_ota、jl_health_http等周边 AAR 的分工边界 - 构建配置、权限、功能模块清单与已知的扩展/边界行为
不覆盖(留给兄弟页面):
- 蓝牙连接的底层实现细节 → 见「蓝牙连接库」相关文档
- RCSP 基础协议包结构与编解码 → 见「RCSP 基础协议」相关文档
- OTA 升级流程 → 见「杰理OTA外接库」开发文档
- 健康服务器接口 → 见「杰理健康服务器」相关文档
说明:
JL_Watch在本仓库中以编译后的 AAR 二进制形式分发(libs/JL_Watch_Vxxx-release.aar),仓库内没有其 Java 源码。本页的架构与控制流结论均来自仓库内可验证的证据:README 集成指南、示例应用(宜动健康)与测试工具(手表测试工具)对WatchOpImpl的实际消费代码,以及工程目录结构。
概述
Android-JL_Health 是珠海市杰理科技股份有限公司为蓝牙穿戴类产品提供的健康数据与设备管理开发平台,基于 RCSP 协议(远程控制系统协议) 构建,支持智能手表、健康手环、智能徽章/戒指等穿戴设备(硬件需支持 RCSP 功能,如 AC701N、AC707N、AC695N 系列 SDK)。
仓库 README 将依赖库清单中的首项明确为:
JL_Watch_Vxxx-release.aar : 杰理健康SDK核心库,提供穿戴设备主要功能
JL_Watch 是功能面最广的库,官方列举的能力包括:
| 功能 | 说明 |
|---|---|
| OTA升级 | 固件空中升级、4G模块OTA、差分升级等 |
| 表盘管理 | 表盘文件浏览、插入、删除、自定义背景等 |
| 健康数据 | 心率、血氧、血压、体温、睡眠等健康监测数据同步 |
| 运动数据 | 运动信息同步、步数统计、卡路里消耗等 |
| 消息同步 | 短信、电话、社交软件消息推送 |
| 天气信息 | 同步天气情况 |
| 联系人 | 常用联系人同步、紧急联系人设置 |
| 闹钟管理 | 闹钟的增删改查 |
| 文件传输 | 大文件传输(如音乐文件)、文件浏览、文件管理 |
| 跌倒/久坐提醒 | 健康设置与安全提醒功能 |
| 音乐控制 | 音乐文件传输、播放控制、ID3信息显示 |
| 图像转换 | BMP/JPEG/PNG 图像编解码转换 |
| 设备查找 | 查找设备或查找手机 |
| 支付宝 | 支付宝激活、支付功能 |
| AI表盘 | AI云服务、AI表盘功能 |
| 自定义命令 | 支持客户拓展功能 |
关键概念
- WatchOpImpl:JL_Watch 对外暴露的抽象操作基类("手表系统对象")。应用必须继承它并实现少数几个契约方法,SDK 的其余功能(健康、表盘、闹钟等)都在此基类之上构建。
- 功能模式(func):构造时通过
super(func)传入,决定 SDK 启用哪一层能力——纯协议(FUNC_RCSP)、协议+目录浏览(FUNC_FILE_BROWSE)、完整手表功能(FUNC_WATCH)。 - 数据通路:JL_Watch 内部生成 RCSP 数据包后,回调应用层通过
sendDataToDevice()发送到蓝牙设备;设备回复的数据再由底层回调回 SDK。应用负责"蓝牙传输"这一环,SDK 负责"协议与业务"。 - 连接状态/认证状态透传:设备连接、认证等状态由底层连接库上报,应用侧需要将其转换为 JL_Watch 库期望的状态语义(示例代码中以 TODO 标注了这一转换点)。
架构
JL_Watch 处于健康 SDK 分层结构的中间层:向上为应用提供业务 API,向下依赖 RCSP 协议层与蓝牙连接层,横向与 OTA、健康服务器、图像/音频转换等库协同。仓库 libs/ 目录的 AAR 集合完整呈现了这一分层:
flowchart TD
subgraph sg_App["应用层(示例工程)"]
App["宜动健康 / 手表测试工具<br/>(code/app, code/tool)"]
WM["WatchManager<br/>extends WatchOpImpl"]
end
subgraph sg_Watch["JL_Watch 核心库(本页主题)"]
WatchOp["WatchOpImpl 抽象基类<br/>getConnectedDevice() / sendDataToDevice()"]
Features["业务功能模块<br/>健康/运动/表盘/闹钟/消息/文件/音乐/自定义命令"]
Proto["RCSP 数据包编解码与命令分发"]
end
subgraph sg_Protocol["协议与连接层"]
RCSP["jl_rcsp 基础协议库"]
BT["jl_bluetooth_connect 蓝牙连接库"]
end
subgraph sg_Helpers["协同库"]
OTA["jl_bt_ota OTA升级"]
HTTP["jl_health_http 健康服务器"]
IMG["BmpConvert / GifConvert 图像转换"]
AUD["jl_audio_decode 音频解码"]
ALI["ALi 支付宝激活库"]
end
subgraph sg_Device["硬件设备"]
DEV["RCSP 穿戴设备<br/>(AC701N/AC707N/AC695N)"]
end
App --> WM
WM -->|"继承并实现契约"| WatchOp
WatchOp --> Features
Features --> Proto
Proto --> RCSP
RCSP --> BT
BT -->|"BLE 数据收发"| DEV
WatchOp -.->|"OTA 回调"| OTA
Features -.->|"健康上报"| HTTP
Features -.->|"表盘/音乐文件转换"| IMG
Features -.->|"语音消息播放"| AUD
Features -.->|"支付能力"| ALI
各层职责说明:
- 应用层:示例工程(宜动健康
code/app、手表测试工具code/tool)在libs/放置全部 AAR 后,通过继承WatchOpImpl得到自己的WatchManager单例,并注册事件监听器接收 SDK 回调。 - JL_Watch 核心层:封装穿戴设备业务——把"健康数据同步""表盘管理"等高层能力翻译为 RCSP 命令;其唯一的"出站"依赖是
sendDataToDevice()回调,由应用注入真实蓝牙发送能力。 - 协议与连接层:
jl_rcsp负责 RCSP 包结构,jl_bluetooth_connect负责 BLE 连接管理与收发;这两层对 JL_Watch 而言是底层依赖,对应用而言通常是"黑盒"。 - 协同库:OTA、健康服务器、图像/音频转换、支付宝等以"外接能力"形式与 JL_Watch 配合,各自解决一个大功能域的专门问题,避免核心库无限膨胀。
- 硬件设备:最终数据落在支持 RCSP 的穿戴设备固件上。
这种"核心库 + 外接库"的拆分是刻意的:JL_Watch 保持对业务功能的高内聚,而把连接、协议、升级、云端、编解码等横切能力下沉/外置,使客户可以按需裁剪依赖(例如仅使用 RCSP 协议或仅使用目录浏览)。
核心抽象:WatchOpImpl 契约
JL_Watch 的使用模型是**"继承 + 回调"**而非"调用静态服务"。应用定义自己的管理类继承 WatchOpImpl,并至少实现两个关键方法,SDK 的所有操作都基于"当前连接设备",所有出站数据都经由应用发送。
初始化与功能模式
README 给出的标准模板:
//实现健康管理类
public class WatchManager extends WatchOpImpl{
private BluetoothDevice mTargetDevice;
public static WatchManager getInstance() {
if (null == instance) {
synchronized (WatchManager.class) {
if (null == instance) {
instance = new WatchManager(FUNC_WATCH);
}
}
}
return instance;
}
//func FUNC_WATCH:手表功能
//FUNC_RCSP:仅仅使用rcsp协议
//FUNC_FILE_BROWSE:使用rcsp协议和目录浏览功能
public WatchManager(int func) {
super(func);
}
设计意图:WatchOpImpl 是模板方法模式的基类——构造参数 func 决定启用哪一档能力(协议 → 协议+浏览 → 完整手表),子类只负责注入"设备从哪来、数据怎么发",业务逻辑全部收敛在父类中。单例使用经典的双重检查锁定(DCL),保证全局只有一个手表管理对象,避免多实例争抢同一蓝牙通道。
两个必须实现的方法
/**
* 获取当前连接的设备,sdk的操作都是基于该设备
* @return 目标设备
*/
@Override
public BluetoothDevice getConnectedDevice() {
//TODO: 客户重写实现功能
return mTargetDevice;
}
/**
* SDK通知外部需要发送数据
* @param device 蓝牙设备对象
* @param data 数据包 byte数组
* @return false:发送失败 true:发送成功
*/
@Override
public boolean sendDataToDevice(BluetoothDevice device, byte[] data) {
getConnectedDevice():告诉 SDK "当前操作哪台设备"。SDK 内部所有命令(查询健康数据、下发闹钟等)都以此方法返回的设备为目标,因此设备切换只需改变这里的返回值。sendDataToDevice(device, data):SDK 组好 RCSP 数据包后回调应用,由应用把byte[]交给蓝牙连接库发出。返回false表示发送失败。这是 JL_Watch 与底层传输之间的唯一出站通道。
这两个方法共同构成"依赖倒置":核心库不直接持有蓝牙栈引用,而是定义抽象接口让上层注入,既便于客户接入自有蓝牙框架,也便于单元测试时注入假发送器。
核心流程:从初始化到设备数据往返
JL_Watch 的运行时控制流可以分为三个阶段:初始化(构建管理对象)→ 命令下发(业务请求 → RCSP 包 → BLE 发送)→ 数据上行(设备响应 → 协议解析 → 事件回调)。示例测试代码(WatchManagerTest.java)展示了前两步的标准姿势:
//初始化手表功能对象
demo = WatchManagerByCustom.getInstance();
//注册事件监听器
sequenceDiagram
participant App as 应用代码
participant WM as WatchManager<br/>(extends WatchOpImpl)
participant SDK as JL_Watch 核心库
participant BT as 蓝牙连接库<br/>(jl_bluetooth_connect)
participant DEV as 穿戴设备
App->>WM: getInstance() 单例(DCL)
WM->>SDK: super(FUNC_WATCH) 初始化手表功能
App->>WM: 注册事件监听器
App->>SDK: 调用业务API(如查询健康数据)
SDK->>WM: getConnectedDevice() 获取目标设备
WM-->>SDK: BluetoothDevice
SDK->>SDK: 组装 RCSP 数据包
SDK->>WM: sendDataToDevice(device, data)
WM->>BT: 通过蓝牙通道发送 byte[]
BT->>DEV: BLE 写特征值
DEV-->>BT: 设备回复数据
BT-->>SDK: 底层回调上报原始数据
SDK->>SDK: RCSP 解析、按命令分发
SDK-->>App: 业务事件回调(健康数据/状态等)
逐步说明(按调试顺序):
- 单例构建:
WatchManagerByCustom.getInstance()用 DCL 创建唯一实例,构造时super(WatchOpImpl.FUNC_WATCH)让核心库进入"完整手表功能"模式(见 WatchManagerTest.java)。 - 注册监听:初始化后立即注册事件监听器,否则后续设备上报的事件无人消费。
- 业务调用:应用调用 SDK 业务 API(健康查询、闹钟下发、表盘操作等),SDK 内部把请求翻译为 RCSP 命令。
- 取设备:SDK 回调
getConnectedDevice()确定操作目标——所有 SDK 操作都基于该设备。 - 组包发送:SDK 组装好
byte[]数据包,回调sendDataToDevice();应用把它交给蓝牙连接库发出。返回false表示发送失败,调用方应做重试或提示。 - 设备回复:设备返回的原始数据经蓝牙连接库回调进入 SDK,SDK 按 RCSP 协议解析并分发到对应业务模块。
- 事件回调:业务结果以事件形式通知应用层,应用在监听器中刷新 UI。
数据通路的单向性
值得注意:sendDataToDevice 是从 SDK 到设备的单向出站回调。设备侧数据(健康数据、认证结果、连接状态)通过蓝牙连接库的独立上行回调进入系统——示例代码中的两条 TODO 明确标注了这一衔接点:
//TODO: 连接状态需要转换成jl_watch库的连接状态
//TODO: 透传设备认证状态
也就是说,连接层上行的"连接状态""认证状态"是连接库语义,业务层需要转换为 JL_Watch 库期望的语义后才能被核心库正确消费。这是集成时最容易出错的边界,也是该页面留给读者最重要的实现提示。
使用示例
示例一:自定义手表管理类(继承 WatchOpImpl)
宜动健康的单元测试工程中定义了 WatchManagerByCustom,它是最贴近生产形态的 JL_Watch 接入样板——私有构造 + DCL 单例 + super(FUNC_WATCH):
class WatchManagerByCustom extends WatchOpImpl {
private static final String TAG = WatchManagerByCustom.class.getSimpleName();
private static volatile WatchManagerByCustom instance;
public static WatchManagerByCustom getInstance() {
if (null == instance) {
synchronized (WatchManagerByCustom.class) {
if (null == instance) {
instance = new WatchManagerByCustom();
}
}
}
return instance;
}
//FUNC_WATCH:手表功能
//FUNC_RCSP:仅仅使用rcsp协议
//FUNC_FILE_BROWSE:使用rcsp协议和目录浏览功能
private WatchManagerByCustom() {
super(WatchOpImpl.FUNC_WATCH); //初始化手表功能
}
设计意图:private 构造防止外部随意创建多个实例——蓝牙通道是串行资源,多实例并发下发会打乱 RCSP 命令的请求/应答配对。volatile + 双重检查在保证线程安全的同时避免每次调用都加锁。
示例二:依赖杰理自有连接的实现(WatchManagerByJL)
测试工程还提供了第二种形态 WatchManagerByJL——同样继承 WatchOpImpl、同样 DCL 单例,区别在于它依托杰理自带的连接库完成 getConnectedDevice / sendDataToDevice 的注入,说明"自定义连接"与"官方连接"两种接入路径都被官方支持:
class WatchManagerByJL extends WatchOpImpl {
private static final String TAG = WatchManagerByJL.class.getSimpleName();
private static volatile WatchManagerByJL instance;
public static WatchManagerByJL getInstance() {
if (null == instance) {
synchronized (WatchManagerByJL.class) {
if (null == instance) {
示例三:测试中的初始化顺序
WatchManagerTest 的测试方法展示了接入的标准顺序——先取单例,再注册事件监听器:
WatchOpImpl demo; //手表系统对象
...
//初始化手表功能对象
demo = WatchManagerByCustom.getInstance();
//注册事件监听器
示例四:JL_Watch 数据文件目录约定
手表测试工具在下载目录下为 JL_Watch 相关文件(表盘、音乐、升级包等)定义了固定目录:
public static final String DIR_JL_WATCH = "JieLi_Watch";
...
return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath()
+ File.separator + DIR_JL_WATCH + File.separator + fileName;
说明:JL_Watch 涉及表盘插入/删除、音乐文件传输、OTA 包等大文件操作,应用侧需要一个统一目录管理这些文件;JieLi_Watch 目录约定使测试工具与正式应用共享一致的存储布局。
配置选项
依赖配置(build.gradle)
JL_Watch 以 AAR 形式随仓库 libs/ 目录分发,接入时放入模块 libs 文件夹并整体引用:
dependencies {
//1.将上面的aar文件放入工程目录中的对应moudle的lib文件夹下
//2.在moudlu的build.gradle中添加
implementation fileTree(include: ['*.aar'], dir: 'libs')
implementation 'com.google.code.gson:gson:2.13.1'
}
权限配置(AndroidManifest.xml)
| 权限 | 用途 | 备注 |
|---|---|---|
android.permission.BLUETOOTH | 基础蓝牙 | 传统蓝牙权限 |
android.permission.BLUETOOTH_ADMIN | 蓝牙管理(扫描/配对) | 传统蓝牙权限 |
android.permission.ACCESS_COARSE_LOCATION | 粗略定位 | 官方要求使用蓝牙需位置信息 |
android.permission.ACCESS_FINE_LOCATION | 精确定位 | 蓝牙扫描必需 |
android.permission.BLUETOOTH_CONNECT | 蓝牙连接 | Android 12+ 必须增加 |
功能模式(构造参数 func)
| 模式常量 | 启用能力 | 适用场景 |
|---|---|---|
FUNC_WATCH | 完整手表功能(健康、表盘、闹钟、消息等全部业务) | 健康/手表类 App(默认推荐) |
FUNC_RCSP | 仅 RCSP 基础协议 | 只需透传协议数据的轻量接入 |
FUNC_FILE_BROWSE | RCSP 协议 + 目录浏览 | 需要文件浏览能力但不需完整手表业务 |
运行环境
| 类别 | 要求 |
|---|---|
| 操作系统 | Android 5.1+(支持 BLE) |
| 硬件 | 支持 RCSP 功能的 SDK(AC701N、AC707N、AC695N 等) |
| 开发平台 | Android Studio(建议最新版) |
| 语言 | Java / Kotlin |
API 参考:WatchOpImpl 核心契约
以下为应用必须/建议实现的方法,签名与语义来自 README 官方模板与示例工程的实际覆写。
WatchManager(int func) — 构造函数
描述: 继承 WatchOpImpl 时通过 super(func) 调用,func 决定 SDK 启用的功能档位。
参数:
func(int):FUNC_WATCH(完整手表功能)、FUNC_RCSP(仅协议)、FUNC_FILE_BROWSE(协议+目录浏览)
示例: super(WatchOpImpl.FUNC_WATCH); //初始化手表功能(WatchManagerTest.java)
getConnectedDevice(): BluetoothDevice — 获取当前连接设备
描述: SDK 所有操作都基于该设备。设备切换时只需改变此方法返回值。
返回: 目标 BluetoothDevice;未连接时可返回 null(SDK 应自行处理)。
设计意图: 把"当前设备是什么"这一状态的所有权留给应用层——连接管理(扫描、配对、断线重连)属于蓝牙连接库的领域,核心库只消费结果。(README.md)
sendDataToDevice(device: BluetoothDevice, data: byte[]): boolean — 发送数据到设备
描述: SDK 组好 RCSP 数据包后回调应用,由应用把 byte[] 交给蓝牙通道发出。这是 SDK 唯一的出站数据通道。
参数:
device(BluetoothDevice):目标设备对象data(byte[]):RCSP 数据包
返回: true 发送成功;false 发送失败(调用方需重试或提示)。
注意: 方法内通常只做"发送",不阻塞等待设备回复;回复走连接库上行回调。大文件(音乐/表盘/OTA 包)传输时该方法可能被高频调用,应避免在内部做重量级操作。(README.md)
事件监听器注册
描述: 初始化 WatchManager 后需立即注册事件监听器,否则设备上报的业务事件无人消费。监听器接口由 JL_Watch 定义,覆盖健康数据、运动数据、连接/认证状态、命令应答等回调(具体接口集合在 AAR 内,示例工程中通过 demo.xxxListener 系列方法注册,见 WatchManagerTest.java)。
失败模式、边界情况与并发
发送失败
sendDataToDevice() 返回 false 表示发送失败——典型场景包括:设备未连接/连接中断、BLE 写特征值超时、数据包过大被底层拒绝。SDK 依赖该返回值感知"命令是否真正离开手机",因此应用侧实现必须如实返回蓝牙通道的结果,不能无条件返回 true,否则上层将无法区分"已下发"与"下发失败",重试与提示逻辑都会失真。
连接/认证状态语义转换(已知 TODO)
示例工程中明确标注了两处待实现的衔接:
//TODO: 连接状态需要转换成jl_watch库的连接状态
//TODO: 透传设备认证状态
这意味着:蓝牙连接库上报的连接状态(如已连接/已断开)与设备认证状态(如已认证/未认证)是连接层的语义,与 JL_Watch 业务层期望的状态并不完全等价。集成方必须在回调边界完成状态映射;遗漏该转换会导致"设备已连接但 SDK 认为未就绪"或"认证未通过却已下发业务命令"等隐蔽问题。
并发与线程
- 单例约束:
WatchOpImpl派生类均采用 DCL 单例(volatile+synchronized),这是刻意的设计——RCSP 命令需要请求/应答配对,并发下发多个命令会破坏配对顺序。应用侧不应绕过单例直接new多个实例。 - 回调线程:
sendDataToDevice由 SDK 内部线程回调,实现中应避免在回调内执行耗时操作(尤其大文件传输时该回调高频触发);UI 刷新应切回主线程。 - 设备切换:
getConnectedDevice()的返回值随时可能变化(断线重连、切换设备),SDK 内部命令在执行时基于该方法快照目标设备,应用侧切换设备前应确保不再有进行中的命令。
Android 版本差异
Android 12+ 需要额外声明 BLUETOOTH_CONNECT 权限,且蓝牙相关权限属于运行时权限,需动态申请(README.md)。Android 6.0+ 的定位权限同样需要运行时申请,否则 BLE 扫描无法返回结果。
性能与运维要点
- 大文件传输:音乐文件、表盘文件、OTA 升级包通过
sendDataToDevice分片下发,链路吞吐取决于 BLE 写通道与设备端处理速度;JieLi_Watch目录(FileUtil.java)统一存放这些大文件,便于断点续传与清理。 - 编解码外置:BMP/JPEG/PNG 转换(
BmpConvert)、GIF 转换(GifConvert)、Opus/Speex 解码(jl_audio_decode)均为独立 AAR,由 JL_Watch 按需调用——这避免核心库携带重量级编解码器,也允许客户替换实现。 - 依赖裁剪:仅需协议能力时用
FUNC_RCSP且不引入业务相关库,可显著减小 APK 体积并降低内存占用。 - 排查路径:问题定位时按"应用回调 → sendDataToDevice 返回值 → 连接库日志 → 设备侧复现"的链路逐层确认,能快速区分是业务层、协议层还是链路层的问题。
扩展点
- 继承
WatchOpImpl:最主要的扩展点。通过覆写getConnectedDevice()接入自有蓝牙框架;通过sendDataToDevice()注入发送通道;SDK 的业务能力全部以父类方法/监听器的形式对外暴露。 - 功能模式组合:
FUNC_RCSP/FUNC_FILE_BROWSE/FUNC_WATCH三档能力从轻到重,客户可按产品形态选择,无需一次性引入全部能力。 - 自定义命令:SDK 官方支持客户自定义 RCSP 命令拓展功能,满足私有协议需求(README.md)。
- 协同库按需替换:健康服务器(
jl_health_http)、支付宝(ALi)、图像/音频转换均为独立 AAR,可替换或裁剪。 - 官方双路径:
WatchManagerByCustom(自定义连接)与WatchManagerByJL(杰理官方连接)两种样板并存,说明核心库对传输层实现无绑定,客户可任选接入路径。
测试
仓库内没有 JL_Watch 核心库自身的单元测试(二进制 AAR),但示例工程 WatchManagerTest.java 提供了对核心库接口的消费侧测试样板:
- 通过
WatchManagerByCustom.getInstance()与WatchManagerByJL.getInstance()两种派生类验证WatchOpImpl的可继承性与单例语义(WatchManagerTest.java)。 - 测试中以
demo(WatchOpImpl类型)持有手表系统对象,注册事件监听器后驱动业务调用,这一模式可直接复制到应用的集成测试中。 - TODO 注释(连接状态转换、认证状态透传)提示了集成测试中必须覆盖的两个衔接点。
相关链接
- 杰理健康SDK(Android) 开发说明文档开发说明) — 官方 SDK 开发说明
- 杰理OTA外接库(Android)开发文档开发文档) — jl_bt_ota 使用说明
- 杰理连接库(Android)开发文档开发文档) — jl_bluetooth_connect 使用说明
- README.md(工程总览与集成指南)
- 宜动健康示例工程(JL_Watch 消费方)
- 手表测试工具(JL_Watch 文件目录约定)
- 工程结构总览(libs/ 目录 AAR 清单)