现在公司用的蓝牙芯片是 NRF51 系列,DFU 升级(OTA 升级)可直接使用官方提供的 iOSDFULibrary。
准备
使用 cocoapods 安装
target 'YourAppTargetName' do
use_frameworks!
pod 'iOSDFULibrary'
end
安装后除了iOSDFULibrary 还有一个 ZIPFoundation。是iOSDFULibrary的一个依赖库,解压zip 包用的,我们不会直接使用。
使用前确认硬件同事发过来的空升包能正常使用,在 APP Store 下载 nRF Connect 操作,能升级成功,再看代码不迟。
空升步骤
- 确认手柄与系统已连接
- 向蓝牙设备发“开启升级模式”消息。此时手柄会主动断连。
- APP 收到蓝牙断开回调,APP 发起蓝牙连接请求,(此时连接的设备名变为会改变,需和硬件同事确认)
- APP 收到蓝牙连接成功回调,读本地空升包,调用 iOSDFULibrary与 dfuService 通信
空升代码
开始空升(空升步骤第3步),我这里建了一个单独的类 DFUHelper,遵守协议 DFUServiceDelegate, DFUProgressDelegate, LoggerDelegate。
func startDFU() {
guard let filePath = Bundle.main.path(forResource: "你的空升包名字", ofType: "zip") else {
return
}
guard let selectedFirmware = DFUFirmware(urlToZipFile: URL(fileURLWithPath: filePath)) else { return }
let initiator = DFUServiceInitiator(centralManager: BlueToothHelper.centralManager, target: BlueToothHelper.peripheral)
initiator.forceDfu = UserDefaults.standard.bool(forKey: "dfu_force_dfu")
initiator.packetReceiptNotificationParameter = UInt16(UserDefaults.standard.integer(forKey: "dfu_number_of_packets"))
initiator.logger = self
initiator.delegate = self
initiator.progressDelegate = self
initiator.enableUnsafeExperimentalButtonlessServiceInSecureDfu = true
dfuController = initiator.with(firmware: selectedFirmware).start()
}
协议回调
// 升级状态回调
func dfuStateDidChange(to state: DFUState) {
switch state {
case .completed:
print("升级成功")
default:
break
}
}
// 升级进度回调,范围 1-100
func dfuProgressDidChange(for part: Int, outOf totalParts: Int, to progress: Int, currentSpeedBytesPerSecond: Double, avgSpeedBytesPerSecond: Double) {
DispatchQueue.main.async {
// 回主线程更新 UI
}
}
func dfuError(_ error: DFUError, didOccurWithMessage message: String) {
print("⚠︎ dfuError: \(error), didOccurWithMessage: \(message)")
}
func logWith(_ level: LogLevel, message: String) {
print("⚠︎ logWith \(level), message: \(message)")
}