iOS-OTA版本说明
OTASDKDemo的目的是做最简单的OTA集成Demo程序,让开发者能以最小的成本实现对我司OTASDK的整合。
请将Xcode版本升级到Xcode14以上。否则会出现找不到符号的错误。
SLB OTA参考的网址https://www.aligenie.com/doc/357554/iz1ttl
20220628更新1.1.1版本
1、支持多设备OTA,同一时间可以并行6个设备进行数据传输
2、优化使用体验,不再需要选择模式,会根据设备服务特性自动进行判断
3、优化升级成功率
4、优化错误码
5、简化SDK开发流程
按如下流程进行处理:
- initOTA
- startScan
- selectFilePath
- addDevices
- tryStartOTA
App Store 1.1.2版本 针对重复升级模式,进行优化,没有涉及SDK上的修改
20220801 SDK 更新1.1.3版本 针对App已经连接设备的情况下,集成我司SDK,在不断开的情况下,直接传递蓝牙对象进行OTA。对手环项目,这是非常必要的优化。
奉加OTA开发文档
一、如何使用OTASDK.xcframework
1、导入头文件
#import <OTASDK/OTASDK.h>
2、初始化蓝牙中心管理器,一定要设置委托协议PHYBLEManagerDelegate。
self.bluetoothManager = [PHYBLEManager shareInstance];
self.bluetoothManager.delegate = self;
3、监听设备蓝牙开启或关闭
- (void)centerMessage:(NSString *)message code:(NSUInteger)code {
if (code == BLENOTActive) {
NSLog(@"%@",message);
[self stopScanAction];
}else if(code == BLEActive) {
[self startScanAction];
}
}
4、扫描设备。会将未设备蓝牙名的设备过滤掉,在开启扫描前,先判断是否已经在扫描中,避免重复扫描,节约资源。
if (!self.bluetoothManager.isScanning) {
[self.bluetoothManager startScan];
}
扫描结果回调:
- (void)deviceFound:(NSArray *)devicesArray {
self.showArray = [devicesArray mutableCopy];
[self.tableView reloadData];
}
5、停止扫描
if (self.bluetoothManager.isScanning) {
[self.bluetoothManager stopScan];
}
6、选择需要升级的设备,以数组形式设置。
[self.bluetoothManager addDevices:self.selectArray];
7、为设备选择升级文件,这个方法应该在添加设备
之前。
[self.bluetoothManager selectFilePath:fileModel.fileAbsolutePath];
8、开始升级
[self.bluetoothManager tryStartOTA];
9、清空设备列表和文件数据,意味着OTA升级环境变量初始化,重新开始OTA前最好是执行这个方法重置一次。
[self.bluetoothManager initOTA];
10、进度信息,升级完成,升级异常等等,均通过如下回调
- (void)listenNotify:(CBPeripheral *)peripheral message:(NSString *)message code:(NSUInteger)code {
self.selectArray = [self.bluetoothManager.deviceArray mutableCopy];
[self.tableView reloadData];
}
iOS OTA代码详解
1、AppDelegate
合并项目时用不到。如下代码是其他文件打开
接收升级文件,将升级文件从微信,QQ,钉钉等通信App下载后存入iOS App储存空间。
#pragma mark - ApplicationDelegate
- (BOOL)application:(UIApplication *)application openURL:(nonnull NSURL *)url options:(nonnull NSDictionary<NSString *,id> *)options {
if (options) {
NSString *str = [NSString stringWithFormat:@"\n发送请求的应用程序的 Bundle ID:%@\n\n文件的NSURL:%@", options[UIApplicationOpenURLOptionsSourceApplicationKey], url];
NSLog(@"%@", str);
if (self.window && url) {
// 根据“其他应用” 用“本应用”打开,通过url,进入列表页
[self pushDocListViewControllerWithUrl:url];
}
}
return YES;
}
#pragma mark ApplicationDelegate Method
/** 根据“其他应用” 用“本应用”打开,通过url,进入列表页 */
- (void)pushDocListViewControllerWithUrl:(NSURL *)url {
}
2、SelectDeviceVC
实现扫描周边蓝牙设备,选择待升级设备的功能。
主要涉及如下代码
2.1、蓝牙初始化和设置委托
//蓝牙初始化
self.bluetoothManager = [PHYBLEManager shareInstance];
self.bluetoothManager.delegate = self;
执行self.bluetoothManager.delegate = self;
时会将蓝牙中心回调指向OTASDK。
2.2、将OTA状态初始化
一般客户工程师无需进行这步,在SDK内部,每一次新的OTA开始时会自动执行。
[self.bluetoothManager initOTA];
SDK内部实现如下:
- (void)initOTA {
[self.deviceArray removeAllObjects];
myFilePath = nil;
fileDetail = nil;
isStartOTA = NO;
mtusize = 0;
}
2.3、开始扫描设备
[self startScanAction];
扫描结果会在deviceFound回调方法中返回。返回结果是过滤掉空蓝牙名,根据信号强度排序的所有设备的数组。
- (void)deviceFound:(NSArray *)devicesArray
2.4、SDK对蓝牙是否开启的检测
如果检测到手机蓝牙已关闭,会通过如下回调中返回。这个部分一般用不到,客户工程师都会在项目启动时就进行检测。
可以参考代码中关于OTAType枚举值的使用方式
- (void)centerMessage:(NSString *)message code:(NSUInteger)code {
self.showTip.text = message;
if (code == BLENOTActive) {
NSLog(@"%@",message);
[self stopScanAction];
}else if(code == BLEActive) {
[self startScanAction];
}else {
[self showAlert:message];
}
}
2.5、扫描时不会触发具体蓝牙设备的回调
为了兼容Swift,3个委托方法必须实现,但在扫描期间如下回调方法不会用到
- (void)listenNotify:(CBPeripheral *)peripheral message:(NSString *)message code:(NSUInteger)code {
NSLog(@"%@ -- %@",peripheral.name, message);
}
2.6、将选择的设备传到SDK
使用如下语句将选择的设备传到SDK。至少选择一个设备。
[self.bluetoothManager addDevices:self.selectArray];
在执行上述语句前,请确认2.1中的委托已经设置。因为在执行上述语句后,会自动连接数组中的第一个设备。如果没有设置委托,将接收不到相关的回调的信息。
3.OTAUpgradeVC
实现每个蓝牙设备的连接状态,传输升级文件进度,正常或异常情况等。SDK中支持同时对6个进行升级。
3.1、蓝牙初始化和设置委托
如果客户项目中有多类调用了BLEManager,则需要自己控制想让哪个VC接收delegate的回调方法。
self.bluetoothManager = [PHYBLEManager shareInstance];
self.bluetoothManager.delegate = self;
3.2、获取SDK中待升级设备
self.selectArray = [self.bluetoothManager.deviceArray mutableCopy];
待升级数组中的元素为PHYBLEModel对象,具体的定义如下:
@interface PHYBLEModel : NSObject
@property (nonatomic, strong) CBPeripheral *peripheral; //系统蓝牙对象
@property (nonatomic, strong) NSDictionary *advertisementData;//广播数据
@property (nonatomic, strong) NSNumber *RSSI; //信号强度
@property (nonatomic, strong) NSString *realName; //设备名称
@property (nonatomic, strong) NSString *adverMacAddr; //MAC地址
@property (nonatomic, strong) NSDate *lastUpdateDate; //最后一次扫描时间
@property (nonatomic, assign) NSInteger OTAType; //OTA类型:SLB或者SingleBank
@property (nonatomic, strong) NSString *OTAMessage; //显示的提示信息
@property (nonatomic, assign) int disconnectTimes; //断开连接次数
@property (nonatomic, strong) SLBContext *mSLBContext; //SLB模式传输数据中的参数
@property (nonatomic, strong) SBHContext *mSBHContext; //SBH模式传输数据中的参数
@property (nonatomic, strong, nullable) NSTimer *myTimer; //定时器
@property (nonatomic, strong) NSMutableArray *bufferArray; //一组数据的缓存
@end
可以根据待升级设备数组中元素的参数自行判断设备的详细状态。
3.3、升级模式:单次模式和循环模式
循环模式是为了压测OTA的稳定性,一般开发者不用管,代码合并时也不要理会。
3.4、加密OTA:Security OTA模式
Security OTA目前只在SBH模式下实现了,不支持SLB。仅支持hexe16格式的升级文件,使用的客户较少,客户喜欢自研加密算法。
SLB加密OTA暂时没有开发计划。
如果不是加密模式,则项目中涉及到密钥的代码都可以不看。
3.5、总结:自定义功能的实现方法
self.bluetoothManager.deviceArray
的结果就是实时的SDK中待升级设备的状态和各项参数。
第二种场景
假设项目中已经连接蓝牙设备,不想经过断开后再扫描、重连的耗时操作,如何进行OTA?
这个场景下只支持单个设备OTA升级的情况。
专门针对这种场景,基于第一个场景的代码逻辑,改编出了如下解决方案。
4、DemoVC
这个模式需要开发者,根据自己设备名修改代码。
打开App后,直接通过左上角的测试按钮,进入到测试页面。
首先在demo程序源码中,设置要升级设备的MAC地址或者UDID地址,模拟设备已经连接,然后修改项目中升级文件名称。
4.1、蓝牙初始化
假如客户使用的是CBCentralManager,将系统蓝牙的回调类指定为当前类。同时进行PHYBLEManager的初始化,但不要设置委托。
self.mCentralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
self.bluetoothManager = [PHYBLEManager shareInstance];
4.2、模拟设备已连接
模拟客户App中启动App立即连接设备的操作。
在Demo页面中按下开始按钮进行扫描,这里提供了两种方式,可以根据MAC地址或蓝牙名称,或者您可以自己根据广播信息及UUID等其他方式建立连接。
进入到DemoVC页面,打开蓝牙就会开始扫描,建立连接,发现服务和特性。
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
NSObject *value = [advertisementData objectForKey:@"kCBAdvDataManufacturerData"];
self.macString = [JCDataConvert getPeripheralMac:value];
self.mPeripheral = peripheral;
if ([self.macString isEqualToString:@"A2:62:22:00:00:19"] ||
[peripheral.name isEqualToString:@"BUMBLE- -22000019"]) {
[self.mCentralManager stopScan];
NSLog(@"找到设备,进行连接!%@",self.mPeripheral);
[self.mCentralManager connectPeripheral:self.mPeripheral options:nil];
}else if(peripheral.name.length > 0){
NSLog(@"%@",peripheral.name);
}
}
4.3、已连接单个设备OTA
需要修改升级文件名。Demo
在设备已经连接的前提下,点击DemoVC页面中的开始按钮,执行如下代码,等待升级成功即可。
self.bluetoothManager.myCentralManager = _mCentralManager;
self.bluetoothManager.delegate = self;
//----------- 升级文件获取的方式 -------------
NSString *folderPath = [NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"Documents/Inbox/"]];
NSString *fileName = @"simpleBlePeripheral(1)_phy6222.hex16";
NSString *FileURL = [folderPath stringByAppendingPathComponent:fileName];
[self.bluetoothManager selectFilePath:FileURL];
[self.bluetoothManager connectedDeviceOTA:self.mPeripheral mac:self.macString];
- 我们知道手机中只有一个蓝牙,所以这里采用将DemoVC中的蓝牙管理对象CBCentralManager传递到SDK中。传递之后接收不到CBCentralManager的委托方法,相当于蓝牙访问权限交给了OTASDK。
- 接收来自OTASDK的回调方法,设置OTASDK的委托为当前类。
- 设置升级文件,可以写死的项目中或者通过服务器下载。
- 将要升级的设备传递到SDK中。SLB模式下MAC地址可以填空字符串@“”。
4.4、OTASDK回调方法
以获取自定义进度条的值作为例子,代码如下:
- (void)listenNotify:(CBPeripheral *)peripheral message:(NSString *)message code:(NSUInteger)code {
self.showLabel.text = message;
if(code == ProgressCallBack) {
float value = [message floatValue];
NSLog(@"Custom progress value: %.2f",value);
}
}
另外:OTASDK中目前已经支持的事件
typedef NS_ENUM(NSInteger, OTAType) {
None = 0,
/*蓝牙状态*/
BLENOTActive, //未检测到蓝牙开启!
BLEActive, //成功检测到蓝牙开启!
LastTaskNotEnd, //上次升级任务还未完成!
UnexpectedConnection, //存在意料之外的BLE连接!
ChangeFileFail, //升级途中不能修改OTA文件!
UnbelievableError, //理论上不会触发的错误!
OTAEnd, //本轮OTA结束
RESCANStart, //二次扫描开始
RESCANDevice, //二次扫描找到设备
DeviceConnecting, //连接中...
DeviceConnectFail, //设备建立连接失败!
DeviceDisconnected, //设备连接已经断开!
ServicesDiscovering, //连接成功,发现服务中...
SLBServiceFound, //SLB服务获取成功!发现特性中!
SBHServiceFound, //SBH服务获取成功,发现特性中!
SLBOTAConfirm, //特性确认,SLB升级模式!
SBHAppConfirm, //特性确认,SBH App模式!
SBHOTAConfirm, //特性确认,SBH OTA模式!
SBHAppSecurity, //安全模式下指令传输
SLBDeviceReady, //特性Enable成功,SLB设备已准备好!
SBHOTADeviceReady, //特性Enable成功,SBH OTA已准备好!
ProgressCallBack, //进度值返回
OTADataOver, //数据发送完毕,确认升级数据中...
OTACheckFail, //数据传输完成后,CRC校验失败!
OTAComplete = 99, //升级成功,可以主动断开或者超时断开!
// 寻找下一个设备时,不需要再连接
SBHAppOver = 100, //SBH App模式结束,等待二次扫描
// 无法进行OTA的错误类型
OTAServiceNotFound, //设备缺少OTA的蓝牙服务!
OTAServiceConfuse, //同时存在两种升级服务!
CharacteristicError, //特性异常!
MTUConflict, //不支持该设备:MTUSize不一致!
MAXDisconnectedTime, //达到最大连接异常断开次数
NOMACAddress,
};