2. 开发说明

2.1 OTA库初始化

2.1.1 继承BluetoothOTAManager

//OTA 管理器实现
public class OTAManager extends BluetoothOTAManager {
    private final BleManager bleManager = BleManager.getInstance();//BLE连接的实现

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

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

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

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

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

    /**
         * 连接蓝牙设备
         * <p>
         *  注意:1. 目前的回连方式都是回连BLE设备,只需要实现回连设备的BLE
         *  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>
         *  注意: 1. 需要实现可靠的大数据传输<br/>
         *  1.1 如果是BLE发送数据,需要根据MTU进行分包,然后队列式发数,确保数据发出<br/>
         *  1.2 如果是BLE发送数据 而且 协商MTU大于128, 建议发送MTU = 协商MTU - 6, 进行边缘保护
         *  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() {

    }

    //连接状态转换
    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 传递连接状态

Important

必要, 用户必须实现

final OTAManager manager = new OTAManager();

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

    @Override
    public void onBleConnection(BluetoothDevice device, int status) {
        super.onBleConnection(device, 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.2.2 传递接收到的蓝牙数据

Important

必要, 用户必须实现

final OTAManager manager = new OTAManager();

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

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

2.1.2.3 传递BLE的MTU改变值

Important

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

final OTAManager manager = new OTAManager();

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

    @Override
    public void onBleDataBlockChanged(BluetoothDevice device, int block, int status) {
        super.onBleDataBlockChanged(device, block, 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.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) {
            //...
        }
    }
});

2.4 升级操作使用说明

用户开始升级之前必须先等待OTA库准备流程跑完, 否则容易出现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) {
            if(otaManager.isOTA()) return; //如果已经在OTA流程,则不需要处理
            //1.可以查询是否需要强制升级
            otaManager.queryMandatoryUpdate(new IActionCallback<TargetInfoResponse>() {
                @Override
                public void onSuccess(TargetInfoResponse deviceInfo) {
                    //TODO:说明设备需要强制升级,请跳转到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 --- 下载loader  1 --- 升级固件
                }

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

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

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

Note

queryMandatoryUpdate 的回复结构可以参考 2.4.1 设备信息

2.4.1 设备信息

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 释放资源

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

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