1 接入流程
1.1 支持环境
环境 |
兼容范围 |
备注 |
---|---|---|
软件系统 |
目标版本: Android API 34
最低版本: Android API 19
|
支持BLE功能 |
固件SDK |
AC695N-watch-SDK,
JL701N-watch-SDK,
AC707N-watch-SDK等
|
建议咨询SDK负责人 |
开发工具 |
Android Studio |
建议使用最新版本 |
1.2 库导入
1.2.1 依赖库
Important
XXX
为版本号,请以最新发布版本为准
jl_bluetooth_connect_Vxxx-release.aar :蓝牙连接相关, 参考 杰理连接开发文档(Android)
jldecryption_vxxx-release.aar : 加密相关
JL_Watch_Vxxx-release.aar : 健康功能相关
jl_rcsp_Vxxx-release.aar : 基础协议相关
BmpConvert_Vxxx-release.aar : 图片转换, 参考 2.3.14 图像转换
jl_bt_ota_Vxxx-release.aar : 杰理蓝牙升级相关, 参考 杰理OTA外接库开发文档(Android)
1.2.2 导入库
<-- 1.将1.2.1的aar文件放入工程目录中的对应moudle的lib文件夹下 --!>
<-- 2.在moudlu的build.gradle中添加 --!>
implementation fileTree(include: ['*.aar'], dir: 'libs')
1.2.3 必要权限
<-- 使用蓝牙权限 --!>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<-- 定位权限,官方要求使用蓝牙或网络开发,需要位置信息 --!>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<-- Android 12+ 需要增加蓝牙连接权限 --!>
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
1.3 SDK配置
1.3.1 继承父类
//实现健康管理类
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);
}
/**
* 获取当前连接的设备,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) {
//TODO: 客户重写实现功能
return false;
}
}
1.3.2 外部状态和数据同步
WatchManager mWatchManager = WatchManager.getInstance();
//1. 通知SDK蓝牙设备状态
//targetDevice : 目标设备
//connection status : 连接状态
//注意:连接状态需要转换成StateCode的连接状态
mWatchManager.notifyBtDeviceConnection(targetDevice, StateCode.CONNECTION_OK);
//2. 通知SDK接收数据
//targetDevice: 目标设备
//data:byte数组, 接收到目标数据发送的数据
mWatchManager.notifyReceiveDeviceData(targetDevice,data);
//3. SDK通知外部需要发送数据(在子类重写方法实现)
//device: 目标设备
//data: 发送数据
sendDataToDevice(BluetoothDevice device, byte[] data);
Important
透传连接状态需要转换库内定义的连接状态
如设备需要 认证流程 ,请连接成功后并完成设备认证流程再回调成功状态
发送数据接口,如果是 BLE实现 ,需要注意
MTU分包
和队列式发数
- BLE的MTU分包处理: BLE 连接会协商MTU值, 超出MTU的值, 会被系统抛弃。为了避免数据丢失, 请按照MTU大小发送, 若发送数据长度超过MTU, 则需要进行MTU分包发送处理
- BLE发送-队列式发数: BLE并发式发送容易导致手机系统BLE底层协议栈卡住。建议发送数据后根据
BluetoothGattCallback#onCharacteristicWrite
回调的状态,进行 队列式发数 处理
1.3.3 SDK状态数据回调
WatchManager mWatchManager = WatchManager.getInstance();
//1.手表表盘相关回调
mWatchManager.registerOnWatchCallback(new OnWatchCallback() {
//参考3.2的说明
/**
* RCSP协议初始化状态回调
*
*/
@Override
public void onRcspInit(BluetoothDevice device, boolean isInit) {
//1. RCSP协议初始化是否成功
//2. 当条件1成立后,会去判断是否支持手表功能
//3. 当条件2成立后,会去初始化手表协议
}
/**
* 手表系统初始化状态回调
*
* @param code 初始化状态
* <p>
* 若是0,表示初始化成功;其他值,为错误码
* </p>
*/
public void onWatchSystemInit(int code) {
//code为0时,意味着库的初始化已完成,可以进行功能操作
//code为错误码时,需要断开设备
}
});
//2.设备主动推送事件回调
mWatchManager.registerOnRcspEventListener(new OnRcspEventListener() {
//参考3.3的说明
});
Important
onWatchSystemInit
的错误码,可以参考 3.13 错误码定义
1.3.4 SDK初始化流程

1.3.5 异常处理
异常状态,是固件系统发生异常返回的状态。用户必须处理固件的异常,才能正常使用设备。
1.3.5.1 监听异常状态
//WatchManager是WatchOpImpl的子类,须在1.3配置好sdk
WatchManager mWatchManager = WatchManager.getInstance();
final OnWatchCallback watchCallback = new OnWatchCallback() {
@Override
public void onRcspInit(BluetoothDevice device, boolean isInit) {
super.onRcspInit(device, isInit);
//回调RCSP协议初始化状态
//首先会初始化RCSP协议
//RCSP初始化失败,按以下情况排查:
//1. 是否没有通过设备认证
//2. 是否发送数据异常
}
@Override
public void onWatchSystemInit(int code) {
super.onWatchSystemInit(code);
//回调手表系统初始化状态
//检测到支持手表功能,会进行手表系统初始化
//手表系统初始化失败,按以下情况排查:
//1. 是否设备离线
//2. 设备是否支持手表功能
//3. 手表系统是否发送异常
}
@Override
public void onWatchSystemException(BluetoothDevice device, int sysStatus) {
super.onWatchSystemException(device, sysStatus);
//回调手表系统异常
//AC695N_WATCH_SDK可能会回调系统异常,需要进行恢复系统的操作,恢复成功后才能正常使用手表功能。
//AC701N_WATCH_SDK一般不会回调系统异常,内部处理了。
}
@Override
public void onMandatoryUpgrade(BluetoothDevice device) {
super.onMandatoryUpgrade(device);
//回调设备需要强制升级
//此情况一般发生在单备份升级异常后。导致设备处于强制升级状态。
//此时设备仅有BLE,而且BLE仅支持OTA功能。只有强制升级成功后,才能正常使用
}
@Override
public void onResourceUpdateUnfinished(BluetoothDevice device) {
super.onResourceUpdateUnfinished(device);
//回调设备资源未更新完成
//此情况一般发生在更新资源失败后,导致设备处于更正资源状态。
//此情况设备手表系统能运行,但是部分资源受损,需要更新资源完成,才能正常使用。
//部分资源受损,强行使用功能,可能导致设备死机。
}
@Override
public void onNetworkModuleException(BluetoothDevice device, NetworkInfo info) {
super.onNetworkModuleException(device, info);
//回调网络模块发送异常
//此情况一般发送在网络模块升级失败后,设备检测到网络模块(4G模块)异常
//此情况建议强制升级网络模块,网络模块升级完成后,才能正常使用网络功能。
}
};
//注册手表事件监听器
mWatchManager.registerOnWatchCallback(watchCallback);
//不需要使用时,注销回调
//mWatchManager.unregisterOnWatchCallback(watchCallback);
1.3.5.2 获取异常状态
除了监听,用户可以通过SDK的接口查询设备的异常状态是否存在
强制升级状态
//WatchManager是WatchOpImpl的子类,须在1.3配置好sdk WatchManager watchManager = WatchManager.getInstance(); final DeviceInfo deviceInfo = watchManager.getDeviceInfo(); if(null == deviceInfo) return; //设备未初始化完成 deviceInfo.isMandatoryUpgrade(); //设备是否需要强制升级
手表系统异常状态
//WatchManager是WatchOpImpl的子类,须在1.3配置好sdk WatchManager watchManager = WatchManager.getInstance(); //获取外挂Flash信息 final ExternalFlashMsgResponse externalFlashMsg = watchManager.getExternalFlashMsg(watchManager.getConnectedDevice()); if(null == externalFlashMsg) return; //设备不支持手表功能 boolean isSysException = externalFlashMsg.getSysStatus() != 0; //判断手表系统是否异常,0是正常,其他值为异常
资源更新未完成状态
//WatchManager是WatchOpImpl的子类,须在1.3配置好sdk WatchManager watchManager = WatchManager.getInstance(); final DeviceInfo deviceInfo = watchManager.getDeviceInfo(); if (null == deviceInfo) return; //设备未初始化完成 //判断设备是否处于更新资源模式 //0 为正常模式, 1为更新资源模式 boolean isUpdateResource = deviceInfo.getExpandMode() == WatchConstant.EXPAND_MODE_RES_OTA;
网络模块升级异常状态
//WatchManager是WatchOpImpl的子类,须在1.3配置好sdk WatchManager watchManager = WatchManager.getInstance(); final DeviceInfo deviceInfo = watchManager.getDeviceInfo(); if (null == deviceInfo) return; //设备未初始化完成 //获取网络模块信息 final NetworkInfo networkInfo = deviceInfo.getNetworkInfo(); if(null == networkInfo){//设备不支持网络模块功能 //需要等 onWatchSystemInit 回调成功后,再查询 return; } boolean isNetworkModeException = networkInfo.isMandatoryOTA(); //网络模块是否需要强制升级
1.3.5.3 处理异常状态
解决固件异常状态的方案
固件强制升级状态
通过
升级固件
的方式来解决。 具体操作参考 杰理OTA外接库开发文档(Android)手表系统异常状态
通过
恢复系统
的方式来解决。 参考 2.3.10 系统恢复资源更新未完成状态
通过
资源更新
的方式来解决。参考 2.3.9 资源更新网络模块升级异常状态
通过
网络模块升级
的方式来解决。参考 2.18.3 开始网络模块OTA
1.3.6 设备认证
是否需要 设备认证
, 需要与固件工程师确认。公版固件SDK默认是 开启设备认证的。
//1. 初始化RcspAuth对象,需要实现发送数据接口和设置数据监听器
RcspAuth mRcspAuth = new RcspAuth(new RcspAuth.IRcspAuthOp() {
@Override
public boolean sendAuthDataToDevice(BluetoothDevice device, byte[] data) {
return sendDataToDevice(device, data);
}
}, mRcspAuthListener);
//2.当设备连接成功时,开始设备认证
mRcspAuth.stopAuth(device, false); //清除旧的设备认证
boolean ret = mRcspAuth.startAuth(device); //开始设备认证, 结果是操作结果
//3.在接收设备数据回调处,进行设备认证数据处理
if (!isAuthDevice(device)) {
mRcspAuth.handleAuthData(device, rawData);
} else {
//TODO: 其他数据处理
}
//4.认证结果会通过监听器回调
//5.不需要使用设备认证功能时,请销毁RcspAuth对象
//mRcspAuth.destroy();
● 发送接口
public interface IRcspAuthOp {
/**
* 向蓝牙设备发送认证数据
*
* @param device 蓝牙设备对象
* @param data 数据包
* @return 操作结果
*/
boolean sendAuthDataToDevice(BluetoothDevice device, byte[] data);
}
● 认证事件监听器
/**
* Rcsp认证监听器
*/
public interface OnRcspAuthListener {
/**
* 初始化结果回调
*
* @param result 结果
*/
void onInitResult(boolean result);
/**
* 设备认证成功回调
*
* @param device 蓝牙设备
*/
void onAuthSuccess(BluetoothDevice device);
/**
* 设备认证失败回调
*
* @param device 蓝牙设备
* @param code 错误码
* @param message 错误信息
*/
void onAuthFailed(BluetoothDevice device, int code, String message);
}
1.4 蓝牙实现
1.4.1 杰理蓝牙连接库实现
1.4.1.1 导入蓝牙库
在 libs
文件夹里放入
jl_bluetooth_connect_Vxxx-release.aar
jldecryption_vxxx-release.aar
在 build.gradle
配置
implementation fileTree(include: ['*.aar'], dir: 'libs')
//Room持久性库
implementation "androidx.room:room-runtime:2.3.0"
annotationProcessor "androidx.room:room-compiler:2.3.0"
在 AndroidManifest.xml
配置权限
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
1.4.1.2 手表操作实现
class WatchManagerByJL extends WatchOpImpl {
/**
* 是否使用设备认证流程
*/
public static final boolean IS_USE_DEVICE_AUTH = true;
/**
* 杰理蓝牙连接库初始化
*/
private final BluetoothHelper jlBtOp = BluetoothHelper.getInstance();
/**
* 设备认证协助类
*/
private final RcspAuth rcspAuth;
/**
* 是否设备认证通过
*/
public final Map<String, Boolean> authResultMap = new HashMap<>();
private final BluetoothEventListener btEventListener = new BluetoothEventListener() {
@Override
public void onConnection(BluetoothDevice device, int status) {
if (null == device) return;
//移除设备认证标志
authResultMap.remove(device.getAddress());
if (status == BluetoothConstant.CONNECT_STATE_CONNECTED) { //连接成功
if (!isAuthPass(device)) {//设备需要认证,但没有通过认证
//开启设备认证
rcspAuth.stopAuth(device, false);
rcspAuth.startAuth(device);
return;
}
}
//TODO: 透传设备认证状态
//TODO: 连接状态需要转换成jl_watch库的连接状态,
/**
* {@link StateCode#CONNECTION_DISCONNECT} --- 未连接
* {@link StateCode#CONNECTION_OK} --- 连接成功
* {@link StateCode#CONNECTION_CONNECTING} --- 连接中
* {@link StateCode#CONNECTION_FAILED} --- 连接失败
*/
int newStatus = RcspUtil.changeConnectStatus(status);
System.out.printf(Locale.ENGLISH, "原连接状态: %d ==> 转换后连接状态: %d%n", status, newStatus);
notifyBtDeviceConnection(device, newStatus);
}
@Override
public void onReceiveData(BluetoothDevice device, byte[] data) {
//回调接收到的数据
if (!isAuthPass(device)) { //设备还没通过设备认证
//TODO: 透传数据到RcspAuth
rcspAuth.handleAuthData(device, data);
return;
}
//TODO: 透传数据到杰理健康SDK
notifyReceiveDeviceData(device, data);
}
};
//func FUNC_WATCH:手表功能
//FUNC_RCSP:仅仅使用rcsp协议
//FUNC_FILE_BROWSE:使用rcsp协议和目录浏览功能
public WatchManagerByJL() {
super(FUNC_WATCH);
//初始化RCSP认证类
rcspAuth = new RcspAuth(this::sendDataToDevice, new RcspAuth.OnRcspAuthListener() {
@Override
public void onInitResult(boolean result) {
}
@Override
public void onAuthSuccess(BluetoothDevice device) {
if (null == device) return;
//设备认证通过
authResultMap.put(device.getAddress(), true);
//设备已连接成功
btEventListener.onConnection(device, BluetoothConstant.CONNECT_STATE_CONNECTED);
}
@Override
public void onAuthFailed(BluetoothDevice device, int code, String message) {
if (null == device) return;
//设备认证失败
//code --- 错误码
//message --- 错误描述
authResultMap.put(device.getAddress(), false);
//断开设备连接
jlBtOp.disconnectDevice(device);
}
});
//增加蓝牙事件监听
jlBtOp.addBluetoothEventListener(btEventListener);
}
public boolean isAuthPass(BluetoothDevice device) {
if (null == device) return false;
if (!IS_USE_DEVICE_AUTH) return true; //不需要设备认证
Boolean result = authResultMap.get(device.getAddress());
return result != null && result;
}
@Override
public BluetoothDevice getConnectedDevice() {
//TODO: 操作中的设备对象
return jlBtOp.getConnectedBtDevice();
}
@Override
public boolean sendDataToDevice(BluetoothDevice device, byte[] data) {
//TODO: 实现蓝牙发数功能
//如果是BLE发数,需要注意 MTU分包 和 线性发数;因为发送超过BLE MTU的数据,系统可能会丢弃部分数据。
return jlBtOp.sendDataToDevice(device, data);
}
@Override
public void release() {
super.release();
authResultMap.clear();
jlBtOp.removeBluetoothEventListener(btEventListener);
rcspAuth.destroy();
}
}
1.4.2 自行实现蓝牙代理
1.4.2.1 手表操作实现
class WatchManagerByCustom extends WatchOpImpl {
private static final String TAG = WatchManagerByCustom.class.getSimpleName();
/**
* 是否使用设备认证流程
*/
public static final boolean IS_USE_DEVICE_AUTH = true;
/**
* 单例对象
*/
private static volatile WatchManagerByCustom instance;
public static WatchManagerByCustom getInstance() {
if (null == instance) {
synchronized (WatchManagerByCustom.class) {
if (null == instance) {
instance = new WatchManagerByCustom();
}
}
}
return instance;
}
/**
* 蓝牙实现初始化
*/
//FIXME: 替换成你们的连接实现
public BleManager mBleManager = BleManager.getInstance();
/**
* 设备认证协助类
*/
private final RcspAuth rcspAuth;
/**
* 是否设备认证通过
*/
public final Map<String, Boolean> authResultMap = new HashMap<>();
private final OnWatchCallback onWatchCallback = new OnWatchCallback() {
@Override
public void onRcspInit(BluetoothDevice device, boolean isInit) {
//回调RCSP协议初始化状态
//首先会初始化RCSP协议
//RCSP初始化失败,按以下情况排查:
//1. 是否没有通过设备认证
//2. 是否发送数据异常
}
@Override
public void onWatchSystemInit(int code) {
//回调手表系统初始化状态
//检测到支持手表功能,会进行手表系统初始化
//手表系统初始化失败,按以下情况排查:
//1. 是否设备离线
//2. 设备是否支持手表功能
//3. 手表系统是否发送异常
}
@Override
public void onWatchSystemException(BluetoothDevice device, int sysStatus) {
//回调手表系统异常
//AC695N_WATCH_SDK可能会回调系统异常,需要进行恢复系统的操作,恢复成功后才能正常使用手表功能。
//AC701N_WATCH_SDK一般不会回调系统异常,内部处理了。
}
@Override
public void onMandatoryUpgrade(BluetoothDevice device) {
//回调设备需要强制升级
//此情况一般发生在单备份升级异常后。导致设备处于强制升级状态。
//此时设备仅有BLE,而且BLE仅支持OTA功能。只有强制升级成功后,才能正常使用
}
@Override
public void onResourceUpdateUnfinished(BluetoothDevice device) {
//回调设备资源未更新完成
//此情况一般发生在更新资源失败后,导致设备处于更正资源状态。
//此情况设备手表系统能运行,但是部分资源受损,需要更新资源完成,才能正常使用。
//部分资源受损,强行使用功能,可能导致设备死机。
}
@Override
public void onNetworkModuleException(BluetoothDevice device, NetworkInfo info) {
//回调网络模块发送异常
//此情况一般发送在网络模块升级失败后,设备检测到网络模块(4G模块)异常
//此情况建议强制升级网络模块,网络模块升级完成后,才能正常使用网络功能。
}
};
//func FUNC_WATCH:手表功能
//FUNC_RCSP:仅仅使用rcsp协议
//FUNC_FILE_BROWSE:使用rcsp协议和目录浏览功能
private WatchManagerByCustom() {
super(WatchOpImpl.FUNC_WATCH); //初始化手表功能
//TODO:设置数据回调
mBleManager.setOnBleEventListener(new BleManager.OnBleEventListener() {
@Override
public void onConnect(BluetoothDevice device, int status) {
System.out.printf(Locale.ENGLISH, "设备[%s]的连接状态: %d\n", device, status);
//移除设备认证标志
authResultMap.remove(device.getAddress());
if (status == BluetoothProfile.STATE_CONNECTED) { //连接成功回调
if (!isAuthPass(device)) {
//开启设备认证
rcspAuth.stopAuth(device, false);
rcspAuth.startAuth(device);
return;
}
}
//TODO: 透传设备认证状态
//TODO: 连接状态需要转换成jl_watch库的连接状态
/*
* {@link StateCode#CONNECTION_DISCONNECT} --- 未连接
* {@link StateCode#CONNECTION_OK} --- 连接成功
* {@link StateCode#CONNECTION_CONNECTING} --- 连接中
* {@link StateCode#CONNECTION_FAILED} --- 连接失败
*/
int newStatus = RcspUtil.changeConnectStatus(status);
System.out.printf(Locale.ENGLISH, "原连接状态: %d ==> 转换后连接状态: %d\n", status, newStatus);
notifyBtDeviceConnection(device, newStatus);
}
@Override
public void onReceiveData(BluetoothDevice device, byte[] data) {
boolean isAuthPass = isAuthPass(device);
System.out.printf(Locale.ENGLISH, "是否通过认证: %s,\n接收到设备[%s]的数据[%s]\n", isAuthPass, device, CHexConver.byte2HexStr(data));
if (!isAuthPass) { //还没通过设备认证
//TODO: 透传数据到RcspAuth
rcspAuth.handleAuthData(device, data);
return;
}
//已通过设备认证
//TODO: 透传数据到杰理健康SDK
notifyReceiveDeviceData(device, data); //透传设备获取的数据
}
});
//实现设备认证流程
rcspAuth = new RcspAuth(this::sendDataToDevice, new RcspAuth.OnRcspAuthListener() {
@Override
public void onInitResult(boolean result) {
}
@Override
public void onAuthSuccess(BluetoothDevice device) {
if (null == device) return;
//设备认证通过
authResultMap.put(device.getAddress(), true);
//设备已连接成功
notifyBtDeviceConnection(device, StateCode.CONNECTION_OK);
}
@Override
public void onAuthFailed(BluetoothDevice device, int code, String message) {
if (null == device) return;
//设备认证失败
//code --- 错误码
//message --- 错误描述
authResultMap.put(device.getAddress(), false);
//断开设备连接
mBleManager.disconnect(); //断开连接
}
});
//增加RCSP事件监听
registerOnWatchCallback(onWatchCallback);
}
public boolean isAuthPass(BluetoothDevice device) {
if (null == device) return false;
if (!IS_USE_DEVICE_AUTH) return true; //不需要设备认证
Boolean result = authResultMap.get(device.getAddress());
return result != null && result;
}
@Override
public BluetoothDevice getConnectedDevice() {
//TODO: 实现连接设备对象返回
return mBleManager.getConnectedDevice();
}
@Override
public boolean sendDataToDevice(BluetoothDevice device, byte[] data) {
//TODO: 实现裸数据发送
//注意,BLE实现发送数据时,数据可能超过BLE的MTU限制。
//需要做 MTU分包 和 队列式发数 等处理
JL_Log.d(TAG, "sendDataToDevice", "device : " + device + ", data = " + CHexConver.byte2HexStr(data));
return mBleManager.sendBleData(data);
}
@Override
public void release() {
super.release();
unregisterOnWatchCallback(onWatchCallback);
mBleManager.setOnBleEventListener(null); //移除回调
rcspAuth.destroy();
instance = null;
}
}
1.4.2.2 BLE蓝牙实现(示例)
Important
代码不能直接使用,而且未经过验证,只为说明实现步骤
比较完整的BLE实现,可以参考 杰理OTA(Android)的蓝牙实现
class BleManager {
private static volatile BleManager instance;
public static BleManager getInstance() {
if (null == instance) {
synchronized (BleManager.class) {
if (null == instance) {
instance = new BleManager();
}
}
}
return instance;
}
private final Context mContext;
private BluetoothGatt mBluetoothGatt;
private OnBleEventListener mOnBleEventListener;
private final UUID serviceUUID = UUID.fromString("你们的服务UUID");
private final UUID writeUUID = UUID.fromString("你们的写特征UUID");
private final UUID notifyUUID = UUID.fromString("你们的通知特征UUID");
private int connection = BluetoothProfile.STATE_DISCONNECTED;
private int bleMtu = 20;
private boolean isSending;
private final LinkedBlockingQueue<byte[]> sendQueue = new LinkedBlockingQueue<>();
//FIXME:BluetoothGatt回调处理,参考代码,不完整
private final BluetoothGattCallback mBluetoothGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
final BluetoothDevice device = gatt.getDevice();
if (null == device) return;
//TODO:回调连接状态
if (status == 0 && newState == BluetoothProfile.STATE_CONNECTED) {
mBluetoothGatt = gatt;
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
mBluetoothGatt = null;
gatt.close();
}
//可以连接成功就回调,或者完成你们库连接成功同步信息后再回调连接成功状态
onConnection(device, newState);
}
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
//TODO:回调发送数据状态
if (writeUUID.equals(characteristic.getUuid())) {
isSending = false;
if (status == 0) {
if (sendQueue.isEmpty()) {
//TODO: 发送数据完成
return;
}
if (!writeDataToBle()) {
//TODO: 发送失败
}
} else {
//TODO: 发送失败, 可以尝试重发
sendQueue.clear();
}
}
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
//TODO:回调接收到的裸数据
if (notifyUUID.equals(characteristic.getUuid())) {
//直接返回接收到的裸数据
if (mOnBleEventListener != null) {
mOnBleEventListener.onReceiveData(gatt.getDevice(), characteristic.getValue());
}
}
}
@Override
public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
super.onMtuChanged(gatt, mtu, status);
//TODO:回调MTU改变
if (status == 0 && (mtu - 3) != bleMtu) {
bleMtu = mtu - 3;
}
}
};
private BleManager() {
mContext = HealthApplication.getAppViewModel().getApplication();
}
public int getBleMtu() {
return bleMtu;
}
public BluetoothGatt getBluetoothGatt() {
return mBluetoothGatt;
}
public BluetoothDevice getConnectedDevice() {
if (null == mBluetoothGatt || connection != BluetoothProfile.STATE_CONNECTED) return null;
return mBluetoothGatt.getDevice();
}
public void setOnBleEventListener(OnBleEventListener onBleEventListener) {
mOnBleEventListener = onBleEventListener;
}
public void connect(BluetoothDevice device) {
if (null == device || !ConnectUtil.isHasConnectPermission(mContext)) return;
BluetoothDevice connectedDevice = getConnectedDevice();
if (null != connectedDevice) {
if (connectedDevice.getAddress().equalsIgnoreCase(device.getAddress())) {
if (mOnBleEventListener != null) {
mOnBleEventListener.onConnect(device, BluetoothProfile.STATE_CONNECTED);
}
return;
}
disconnect();
SystemClock.sleep(500); //延时500毫秒
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mBluetoothGatt = device.connectGatt(mContext, false, mBluetoothGattCallback, BluetoothDevice.TRANSPORT_LE);
} else {
mBluetoothGatt = device.connectGatt(mContext, false, mBluetoothGattCallback);
}
onConnection(device, null != mBluetoothGatt ? BluetoothProfile.STATE_CONNECTING : BluetoothProfile.STATE_DISCONNECTED);
}
public void disconnect() {
if (null == mBluetoothGatt) return;
if (connection == BluetoothProfile.STATE_CONNECTED) {
mBluetoothGatt.disconnect();
return;
}
final BluetoothDevice device = mBluetoothGatt.getDevice();
mBluetoothGatt.close();
mBluetoothGatt = null;
onConnection(device, BluetoothProfile.STATE_DISCONNECTED);
}
//FIXME: 参考发送数据实现,不完整。请替换你们库的发送数据实现
public boolean sendBleData(byte[] data) {
int offset = 0;
while (offset < data.length) {
int left = data.length - offset;
int packetLen = Math.min(left, bleMtu); //根据MTU分包
byte[] packet = Arrays.copyOfRange(data, offset, offset + packetLen);
try {
sendQueue.add(packet); //添加到发数队列
} catch (Exception e) {
e.printStackTrace();
return false;
}
offset += packetLen;
}
return writeDataToBle();
}
public void destroy() {
isSending = false;
sendQueue.clear();
bleMtu = 20;
setOnBleEventListener(null);
disconnect();
instance = null;
}
private void onConnection(BluetoothDevice device, int state) {
connection = state;
if (mOnBleEventListener != null) {
mOnBleEventListener.onConnect(device, state);
}
}
private boolean writeDataToBle() {
boolean ret = isSending;
if (!ret) {
if (mBluetoothGatt == null || sendQueue.isEmpty()) return false;
byte[] data = sendQueue.poll();
if (data == null) return false;
//建议队列式按MTU分包发数
BluetoothGattCharacteristic characteristic = mBluetoothGatt.getService(serviceUUID).getCharacteristic(writeUUID);
if (null == characteristic) return false;
characteristic.setValue(data);
isSending = mBluetoothGatt.writeCharacteristic(characteristic);
ret = isSending;
}
if (!ret) sendQueue.clear();
return ret;
}
interface OnBleEventListener {
void onConnect(BluetoothDevice device, int status);
void onReceiveData(BluetoothDevice device, byte[] data);
}
}