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 为版本号,请以最新发布版本为准

  1. jl_bluetooth_connect_Vxxx-release.aar :蓝牙连接相关, 参考 杰理连接开发文档(Android)

  2. jldecryption_vxxx-release.aar : 加密相关

  3. JL_Watch_Vxxx-release.aar : 健康功能相关

  4. jl_rcsp_Vxxx-release.aar : 基础协议相关

  5. BmpConvert_Vxxx-release.aar : 图片转换, 参考 2.3.14   图像转换

  6. 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

  1. 透传连接状态需要转换库内定义的连接状态

  2. 如设备需要 认证流程 ,请连接成功后并完成设备认证流程再回调成功状态

  3. 发送数据接口,如果是 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

  1. onWatchSystemInit 的错误码,可以参考 3.13   错误码定义

1.3.4 SDK初始化流程

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的接口查询设备的异常状态是否存在

  1. 强制升级状态

    //WatchManager是WatchOpImpl的子类,须在1.3配置好sdk
    WatchManager watchManager = WatchManager.getInstance();
    final DeviceInfo deviceInfo = watchManager.getDeviceInfo();
    if(null == deviceInfo) return; //设备未初始化完成
    deviceInfo.isMandatoryUpgrade(); //设备是否需要强制升级
    
  2. 手表系统异常状态

    //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是正常,其他值为异常
    
  3. 资源更新未完成状态

    //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;
    
  4. 网络模块升级异常状态

    //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 处理异常状态

解决固件异常状态的方案

  1. 固件强制升级状态

    通过 升级固件 的方式来解决。 具体操作参考 杰理OTA外接库开发文档(Android)

  2. 手表系统异常状态

    通过 恢复系统 的方式来解决。 参考 2.3.10   系统恢复

  3. 资源更新未完成状态

    通过 资源更新 的方式来解决。参考 2.3.9   资源更新

  4. 网络模块升级异常状态

    通过 网络模块升级 的方式来解决。参考 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

  1. 代码不能直接使用,而且未经过验证,只为说明实现步骤

  2. 比较完整的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);
    }
}