2 开发说明

2.1 初始化OTA对象

2.1.1 继承BluetoothOTAManager

用户需要继承BluetoothOTAManager类, 实现抽象接口透传设备连接状态透传接收到的数据

//OTA管理器实现
public class OTAManager extends BluetoothOTAManager {
    /**
     * 蓝牙实现,比如:BLE连接的实现
     */
    private final BleManager bleManager = BleManager.getInstance();

    public OTAManager(Context context) {
        super(context);
            //TODO:用户通过自行实现的连接库对象完成传递设备连接状态和接收到的数据
        bleManager.registerBleEventCallback(new BleEventCallback() {
            @Override
            public void onBleConnection(BluetoothDevice device, int status) {
                //TODO: 注意:转变成OTA库的连接状态
                //注意: 需要正确传入设备连接状态,不要重复传入相同状态, 连接中-已连接-断开 或者 已连接-断开
                int connectStatus = changeConnectStatus(status);
                //传递设备的连接状态
                onBtDeviceConnection(device, connectStatus);
            }

            @Override
            public void onBleDataNotification(BluetoothDevice device, UUID serviceUuid, UUID characteristicsUuid, byte[] data) {
                //传递设备的接收数据
                onReceiveDeviceData(device, data);
            }

            @Override
            public void onBleDataBlockChanged(BluetoothDevice device, int block, int status) {
                //传递BLE的MTU改变
                //注意: 非必要实现,建议客户在设备连接上时进行MTU协商
                onMtuChanged(getConnectedBluetoothGatt(), block, status);
            }
        });
    }

        /**
         * 获取已连接的蓝牙设备
         * <p>
         *  注意:<br/>
         *  1. 是通讯方式对应的蓝牙设备对象<br/>
         *  2. 实时反映设备的连接状态,设备已连接时有值,设备断开时返回null
         * </p>
         */
        @Override
    public BluetoothDevice getConnectedDevice() {
        //TODO:用户自行实现
        return bleManager.getConnectedBtDevice();
    }

        /**
         * 获取已连接的BluetoothGatt对象
         * <p>
         * 若选择BLE方式OTA,需要实现此方法。反之,SPP方式不需要实现<br/>
         * 若不需要SDK内部调整BLE的MTU,则不需要实现
         * </p>
         */
        @Override
    public BluetoothGatt getConnectedBluetoothGatt() {
        //TODO:用户自行实现
        return bleManager.getConnectedBtGatt();
    }

    /**
         * 连接蓝牙设备
         * <p>
         *  注意:<br/>
         *  1. 目前的回连方式都是回连BLE设备,只需要实现回连设备的BLE<br/>
         *  2. 该方法用于设备回连过程,如果客户是双备份OTA或者自行实现回连流程,不需要实现
         * </p>
         * @param device 通讯方式的蓝牙设备
         */
    @Override
    public void connectBluetoothDevice(BluetoothDevice device) {
        //TODO:用户自行实现连接设备
        bleManager.connectBleDevice(device);
    }

    /**
         * 断开蓝牙设备的连接
         *
         * @param device 通讯方式的蓝牙设备
         */
    @Override
    public void disconnectBluetoothDevice(BluetoothDevice device) {
        //TODO:用户自行实现断开设备
        bleManager.disconnectBleDevice(device);
    }

    /**
         *发送数据到蓝牙设备
         *<p>
         *  注意: <br/>
         *  1. 需要实现可靠的大数据传输<br/>
         *  1.1 如果是BLE发送数据,需要根据MTU进行分包,然后队列式发数,确保数据发出<br/>
         *  1.2 如果是BLE发送数据 而且 协商MTU大于128, 建议发送MTU = 协商MTU - 6, 进行边缘保护<br/>
         *  2. 该方法在发送数据时回调,发送的数据是组装好的RCSP命令。一般长度在[10, 525]
         *</p>
         * @param device 已连接的蓝牙设备
         * @param data 数据包
         * @return 操作结果
         */
    @Override
    public boolean sendDataToDevice(BluetoothDevice device, byte[] data) {
        //TODO:用户自行实现发送数据,BLE方式,需要注意MTU分包和队列式发数
        bleManager.writeDataByBleAsync(device, BleManager.BLE_UUID_SERVICE, BleManager.BLE_UUID_WRITE, data, new OnWriteDataCallback() {
            @Override
            public void onBleResult(BluetoothDevice device, UUID serviceUUID, UUID characteristicUUID, boolean result, byte[] data) {
                //返回结果
            }
        });
        //也可以阻塞等待结果
        return true;
    }

    /**
         * 用户通知OTA库的错误事件
         * <p>
         * 1. 错误码参考 3.5 章节 错误码定义
         * </p>
         */
    @Override
    public void errorEventCallback(BaseError error) {

    }

        /**
         * 用于释放资源
         */
    @Override
    public void release() {
        super.release();
    }

    //连接状态转换
    private int changeConnectStatus(int status) {
        int changeStatus = StateCode.CONNECTION_DISCONNECT;
        switch (status) {
            case BluetoothProfile.STATE_DISCONNECTED:
            case BluetoothProfile.STATE_DISCONNECTING: {
                 changeStatus = StateCode.CONNECTION_DISCONNECT;
                 break;
            }
            case BluetoothProfile.STATE_CONNECTED:
                 changeStatus = StateCode.CONNECTION_OK;
                 break;
            case BluetoothProfile.STATE_CONNECTING:
                 changeStatus = StateCode.CONNECTION_CONNECTING;
                break;
        }
        return changeStatus;
    }
}

2.1.2 实现抽象接口

2.1.2.1 必须实现的接口

  1. 发送数据接口

    /**
         *发送数据到蓝牙设备
         *<p>
         *  注意:<br/>
         *  1. 需要实现可靠的大数据传输<br/>
         *  1.1 如果是BLE发送数据,需要根据MTU进行分包,然后队列式发数,确保数据发出<br/>
         *  1.2 如果是BLE发送数据 而且 协商MTU大于128, 建议发送MTU = 协商MTU - 6, 进行边缘保护<br/>
         *  2. 该方法在发送数据时回调,发送的数据是组装好的RCSP命令。一般长度在[10, 525]
         *</p>
         * @param device 已连接的蓝牙设备
         * @param data 数据包
         * @return 操作结果
         */
    @Override
    public boolean sendDataToDevice(BluetoothDevice device, byte[] data) {
        //TODO:用户自行实现发送数据,BLE方式,需要注意MTU分包和队列式发数
        //也可以阻塞等待结果
        return false;
    }
    
  2. 获取已连接的蓝牙设备

    用于判断设备是否已连接

    /**
         * 获取已连接的蓝牙设备
         * <p>
         *  注意:<br/>
         *  1. 是通讯方式对应的蓝牙设备对象<br/>
         *  2. 实时反映设备的连接状态,设备已连接时有值,设备断开时返回null
         * </p>
         */
        @Override
    public BluetoothDevice getConnectedDevice() {
        //TODO:用户自行实现
        return null;
    }
    

2.1.2.2 可选实现的接口

  1. 获取已连接的BluetoothGatt对象

    用于SDK内部调整MTU, 建议 调整MTU操作 由用户实现

    /**
         * 获取已连接的BluetoothGatt对象
         * <p>
         * 若选择BLE方式OTA,需要实现此方法。反之,SPP方式不需要实现<br/>
         * 若不需要SDK内部调整BLE的MTU,则不需要实现
         * </p>
         */
         @Override
     public BluetoothGatt getConnectedBluetoothGatt() {
         //TODO:用户自行实现
         return null;
     }
    
  2. 连接指定的蓝牙设备

    用于 单备份OTA 的回连设备流程

    /**
         * 连接蓝牙设备
         * <p>
         *  注意:<br/>
         *  1. 目前的回连方式都是回连BLE设备,只需要实现回连设备的BLE<br/>
         *  2. 该方法用于设备回连过程,如果客户是双备份OTA或者自行实现回连流程,不需要实现
         * </p>
         * @param device 通讯方式的蓝牙设备
         */
     @Override
     public void connectBluetoothDevice(BluetoothDevice device) {
         //TODO:用户自行实现连接设备
     }
    
  3. 断开指定的蓝牙设备

    用于 单备份OTA 的回连设备流程

    /**
         * 断开蓝牙设备的连接
         *
         * @param device 通讯方式的蓝牙设备
         */
     @Override
     public void disconnectBluetoothDevice(BluetoothDevice device) {
         //TODO:用户自行实现断开设备
     }
    

2.1.3 用户传递设备连接状态和数据

2.1.3.1 传递设备连接状态

Important

  1. 调用 BluetoothOTAManager#onBtDeviceConnection(device, connection) 传递设备连接状态

  2. 用户必须调用接口传递设备连接状态

final OTAManager manager = new OTAManager();
//TODO:用户通过自行实现的连接库对象完成传递设备连接状态
BleManager.getInstance().registerBleEventCallback(new BleEventCallback() {

    @Override
    public void onBleConnection(BluetoothDevice device, int status) {
        //TODO: 注意:转变成OTA库的连接状态
        //注意: 需要正确传入设备连接状态,不要重复传入相同状态, 连接中-已连接-断开 或者 已连接-断开
        int connectStatus = changeConnectStatus(status);
        //传递设备的连接状态
        manager.onBtDeviceConnection(device, connectStatus);
    }
});

//连接状态转换
private int changeConnectStatus(int status) {
    int changeStatus = StateCode.CONNECTION_DISCONNECT;
    switch (status) {
        case BluetoothProfile.STATE_DISCONNECTED:
        case BluetoothProfile.STATE_DISCONNECTING: {
             changeStatus = StateCode.CONNECTION_DISCONNECT;
             break;
        }
        case BluetoothProfile.STATE_CONNECTED:
             changeStatus = StateCode.CONNECTION_OK;
             break;
        case BluetoothProfile.STATE_CONNECTING:
             changeStatus = StateCode.CONNECTION_CONNECTING;
             break;
    }
    return changeStatus;
}

2.1.3.2 传递接收到的蓝牙数据

Important

  1. 调用 BluetoothOTAManager#onReceiveDeviceData(device, data) 传递设备连接状态

  2. 用户必须调用接口传递接收到的蓝牙数据

final OTAManager manager = new OTAManager();
//TODO:用户通过自行实现的连接库对象完成传递接收到的数据
BleManager.getInstance().registerBleEventCallback(new BleEventCallback() {

    @Override
    public void onBleDataNotification(BluetoothDevice device, UUID serviceUuid, UUID characteristicsUuid, byte[] data) {
        //传递设备的接收数据
        manager.onReceiveDeviceData(device, data);
    }
});

2.1.3.3 传递BLE的MTU改变值

Important

  1. 调用 BluetoothOTAManager#onMtuChanged(device, mtu, status) 传递MTU值

  2. 非必要, 用户可以选择性实现。

  3. 用于SDK内部调整MTU, 如果客户外部调整好MTU, 不需要调用

final OTAManager manager = new OTAManager();
//TODO:用户通过自行实现的连接库对象完成传递BLE的MTU改变
BleManager.getInstance().registerBleEventCallback(new BleEventCallback() {

    @Override
    public void onBleDataBlockChanged(BluetoothDevice device, int block, int status) {
        //传递BLE的MTU改变
        manager.onMtuChanged(getConnectedBluetoothGatt(), block, status);
    }
});

2.2 配置OTA参数

OTAManager otaManager = new OTAManager();
BluetoothOTAConfigure bluetoothOption = BluetoothOTAConfigure.createDefault();
bluetoothOption.setPriority(BluetoothOTAConfigure.PREFER_BLE) //请按照项目需要选择
            .setUseAuthDevice(true) //具体根据固件的配置选择
            .setBleIntervalMs(500) //默认是500毫秒
            .setTimeoutMs(3000) //命令超时时间
            .setMtu(500) //BLE底层通讯MTU值,会影响BLE传输数据的速率。建议用500 或者 270。该MTU值会使OTA库在BLE连接时改变MTU,所以用户SDK需要对此处理。
            .setNeedChangeMtu(false) //不需要调整MTU,建议客户连接时调整好BLE的MTU
            .setUseReconnect(false); //是否自定义回连方式,默认为false,走SDK默认回连方式,客户可以根据需求进行变更
bluetoothOption.setFirmwareFilePath(firmwarePath); //设置本地存储OTA文件的路径
//        bluetoothOption.setFirmwareFileData(firmwareData);//设置本地存储OTA文件的数据, 与setFirmwareFilePath,二者选其一
otaManager.configure(bluetoothOption); //设置OTA参数

2.2.1 BluetoothOTAConfigure

蓝牙OTA库配置

属性名

类型

描述

参考值

priority

int

OTA的通讯方式

0 - BluetoothOTAConfigure#PREFER_BLE
1 - BluetoothOTAConfigure#PREFER_SPP
默认是BLE方式

isUseReconnect

boolean

是否使用自定义回连方式

默认是不使用

isUseAuthDevice

boolean

是否启用设备认证

默认是开启

firmwareFilePath

String

固件升级文件存放路径

默认为空,升级前需要设置

firmwareFileData

byte[]

固件升级文件数据

默认为空,升级前需要设置
与firmwareFilePath一样, 两者选其一即可

mtu

int

调节后的BLE的MTU值

默认为20, 范围: 20-509

isNeedChangeMtu

boolean

是否需要调节MTU

默认不调节MTU

snGenerator

ICmdSnGenerator

命令SN生成器

若为null,则采用默认SN生成器,
适用于杰理多库联合使用

Note

BluetoothOTAConfigure必须在OTA前配置, 才会生效。

2.2.2 请求调节MTU配置

BluetoothOTAConfigure bluetoothOption = BluetoothOTAConfigure.createDefault();
//BLE底层通讯MTU值,会影响BLE传输数据的速率。建议用500 或者 270。该MTU值会使OTA库在BLE连接时改变MTU,所以用户SDK需要对此处理。
bluetoothOption.setMtu(500)
         .setNeedChangeMtu(true); //不需要调整MTU,建议客户连接时调整好BLE的MTU

Note

  1. 不推荐设置, 建议是客户连接BLE时调整好BLE的MTU

  2. 需要实现接口: BluetoothOTAManager#getConnectedBluetoothGatt()

  3. 需要调用接口: BluetoothOTAManager#onMtuChanged(device, mtu, status)

2.2.3 自定义回连设备策略配置

BluetoothOTAConfigure bluetoothOption = BluetoothOTAConfigure.createDefault();
bluetoothOption.setUseReconnect(true); //设置自定义回连方式

Note

  1. 需要实现接口: BluetoothOTAManager#connectBluetoothDevice(device)BluetoothOTAManager#disconnectBluetoothDevice(device)

2.3 监听OTA初始化结果回调

//1.构建OTAManager对象
OTAManager otaManager = new OTAManager();
//2.注册事件监听器
otaManager.registerBluetoothCallback(new BtEventCallback() {
    @Override
    public void onConnection(BluetoothDevice device, int status) {
        //必须等待库回调连接成功才可以开始OTA库操作
        if (status == StateCode.CONNECTION_OK) { //OTA初始化成功
            //用户可以操作升级对象的接口
        }
    }
});

2.4 升级操作使用说明

Important

  1. 用户需要等待OTA库初始化成功, 才能调用操作接口

  2. 否则容易出现OTA异常或者OTA开始不了的情况。

//OTAManager继承BluetoothOTAManager并实现对应方法
public class OTAManager extends BluetoothOTAManager{
    ...
}

//OTA库的使用
//1.构建OTAManager对象
OTAManager otaManager = new OTAManager();
//2.注册事件监听器
otaManager.registerBluetoothCallback(new BtEventCallback() {
    @Override
    public void onConnection(BluetoothDevice device, int status) {
        //必须等待库回调连接成功才可以开始OTA操作
        if (status == StateCode.CONNECTION_OK) { //OTA初始化成功
            if(otaManager.isOTA()) return; //如果已经在OTA流程,则不需要处理
            //1.可以查询是否需要强制升级
            otaManager.queryMandatoryUpdate(new IActionCallback<TargetInfoResponse>() {
                @Override
                public void onSuccess(TargetInfoResponse deviceInfo) {
                    //设备处于强制升级模式,请跳转到OTA界面,引导用户升级固件
                    deviceInfo.getVersionCode(); //设备版本号
                    deviceInfo.getVersionName(); //设备版本名
                    deviceInfo.getProjectCode(); //设备产品ID(默认是0,如果设备支持会改变)
                    //需要看固件是否支持
                    deviceInfo.getUid();  //客户ID
                    deviceInfo.getPid();  //产品ID
                    //进行步骤2
                }

                @Override
                public void onError(BaseError baseError) {
                    //可以不用处理,也可以获取设备信息
                    //没有错误,设备处于正常模式,可以获取设备信息
                    if (baseError.getCode() == ErrorCode.ERR_NONE && baseError.getSubCode() == ErrorCode.ERR_NONE){
                        TargetInfoResponse deviceInfo = otaManager.getDeviceInfo();
                        deviceInfo.getVersionCode(); //设备版本号
                        deviceInfo.getVersionName(); //设备版本名
                        deviceInfo.getProjectCode(); //设备产品ID(默认是0,如果设备支持会改变)
                        //需要看固件是否支持
                        deviceInfo.getUid();  //客户ID
                        deviceInfo.getPid();  //产品ID
                        //进行步骤2
                    }
                }
            });
            //2.进行OTA升级
            //* 需要先设置升级文件路径 - filePath
            otaManager.getBluetoothOption().setFirmwareFilePath(filePath);
            //* 进行OTA升级,然后根据回调进行UI更新
            otaManager.startOTA(new IUpgradeCallback() {
                @Override
                public void onStartOTA() {
                    //回调开始OTA
                }

                @Override
                public void onNeedReconnect(String addr, boolean isNewReconnectWay) {
                    //回调需要回连的设备地址
                    //如果客户设置了BluetoothOTAConfigure#setUseReconnect()为true,则需要在此处回调进行自定义回连设备流程
                    if(otaManager.getBluetoothOption().isUseReconnect()) {
                        //2-1 进行自定义回连流程
                    }
                }

                @Override
                public void onProgress(int type, float progress) {
                    //回调OTA进度
                    //type : 0 --- 下载资源  1 --- 升级固件
                }

                @Override
                public void onStopOTA() {
                    //回调OTA升级完成
                }

                @Override
                public void onCancelOTA() {
                    //回调OTA升级被取消
                    //双备份OTA才允许OTA流程取消
                }

                @Override
                public void onError(BaseError error) {
                    //回调OTA升级发生的错误事件
                }
            });
        }
    }
});

Note

  1. queryMandatoryUpdate 的回复结构可以参考 2.4.1   TargetInfoResponse

  2. 强制升级模式,说明设备的功能不能正常使用,需要通过升级才能正常使用。

2.4.1 TargetInfoResponse

设备信息

public class TargetInfoResponse {

    private String versionName;     //设备版本名称
    private int versionCode;        //设备版本信息
    private String protocolVersion; //协议版本

    //经典蓝牙相关信息
    private String edrAddr;    //经典蓝牙地址
    private int edrStatus = 0; //经典蓝牙的连接状态
    private int edrProfile = 0;//经典蓝牙支持的协议

    //BLE相关信息
    private String bleAddr;   //BLE地址
    private boolean bleOnly;  //是否仅仅连接ble设备

    //SysInfo属性
    private int volume;      // 设备音量
    private int maxVol;      // 设备最大音量
    private int quantity;    // 设备电量
    private int functionMask;// 功能支持掩码
    private byte curFunction;// 当前模式
    private int sdkType;     // SDK的标识

    private String name;                   // 名字
    private int pid;                       // 产品ID
    private int vid;                       // 厂商ID
    private int uid;                       // 客户ID
    private int mandatoryUpgradeFlag;      // 强制升级
    private int requestOtaFlag;            // 请求升级标志
    private int ubootVersionCode;          // uboot 版本号
    private String ubootVersionName;       // uboot 版本名称
    private boolean isSupportDoubleBackup; // 是否支持双备份升级(单备份[false],需要断开回连过程;双备份[true],不需要断开回连过程)
    private boolean isNeedBootLoader;      // 是否需要下载boot loader
    private int singleBackupOtaWay;        // 单备份OTA连接方式(00 -- 不使能 01 -- BLE  02 -- SPP)
    // 拓展模式
    // 0:不启用
    // 1: 升级资源模式
    private int expandMode;

    private int allowConnectFlag; // 是否允许连接 0 -- 允许 1 -- 不允许

    //用于服务器校验产品信息
    private String authKey;     // 认证秘钥
    private String projectCode; // 项目标识码

    //用于自定义版本信息
    private String customVersionMsg;

    private boolean isSupportMD5;  // 是否支持MD5读取
    private boolean isGameMode;    // 是否游戏模式

    private int communicationMtu;  //通讯MTU
    private int receiveMtu;        //接收MTU
}

2.4.2 注意事项

  1. 为了防止升级失败导致固件变 , 因此固件升级失败后会进入强制升级模式

  2. 因为未连接设备时, 不知道设备状态, 所以库初始化成功后需要优先查询设备升级状态

  3. 用户SDK或APP应该具备回连上一次连接的蓝牙设备的功能, 用于强制升级时自动回连设备, 再通过OTA升级更新固件

  4. 单备份方案, 进入loader后, 将不存在A2DP和HFP。因此回连方式, 不能回连经典蓝牙

  5. 双备份方案, 不需要回连过程,直接开始升级流程

2.5 释放资源

Note

不再使用OTA功能, 可以释放OTAManager的对象

//初始化OTAManager
OTAManager otaManager = new OTAManager();
// ...
//OTA操作完成后,需要注销事件监听器和释放资源
//        otaManager.unregisterBluetoothCallback(this);
otaManager.release();

2.6 工作流程图

OTA流程图