forked from juliansteenbakker/nordic_dfu
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request juliansteenbakker#77 from Knightro63/master
Macos implementation
- Loading branch information
Showing
5 changed files
with
214 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
import FlutterMacOS | ||
import AppKit | ||
import iOSDFULibrary | ||
import CoreBluetooth | ||
|
||
public class SwiftNordicDfuPlugin: NSObject, FlutterPlugin, FlutterStreamHandler, DFUServiceDelegate, DFUProgressDelegate, LoggerDelegate { | ||
|
||
let registrar: FlutterPluginRegistrar | ||
var sink: FlutterEventSink! | ||
var pendingResult: FlutterResult? | ||
var deviceAddress: String? | ||
private var dfuController : DFUServiceController! | ||
|
||
public static func register(with registrar: FlutterPluginRegistrar) { | ||
let instance = SwiftNordicDfuPlugin(registrar) | ||
|
||
let method = FlutterMethodChannel(name: "dev.steenbakker.nordic_dfu/method", binaryMessenger: registrar.messenger) | ||
|
||
let event = FlutterEventChannel(name: | ||
"dev.steenbakker.nordic_dfu/event", binaryMessenger: registrar.messenger) | ||
|
||
registrar.addMethodCallDelegate(instance, channel: method) | ||
event.setStreamHandler(instance) | ||
} | ||
|
||
init(_ registrar: FlutterPluginRegistrar) { | ||
self.registrar = registrar | ||
super.init() | ||
} | ||
|
||
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { | ||
switch call.method { | ||
case "startDfu": initializeDfu(call, result) | ||
case "abortDfu" : abortDfu() | ||
default: result(FlutterMethodNotImplemented) | ||
} | ||
} | ||
|
||
public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? { | ||
sink = events | ||
return nil | ||
} | ||
|
||
public func onCancel(withArguments arguments: Any?) -> FlutterError? { | ||
sink = nil | ||
return nil | ||
} | ||
|
||
private func abortDfu() { | ||
_ = dfuController?.abort() | ||
dfuController = nil | ||
} | ||
|
||
private func initializeDfu(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { | ||
guard let arguments = call.arguments as? Dictionary<String, AnyObject> else { | ||
result(FlutterError(code: "ABNORMAL_PARAMETER", message: "no parameters", details: nil)) | ||
return | ||
} | ||
let name = arguments["name"] as? String | ||
guard let address = arguments["address"] as? String, | ||
var filePath = arguments["filePath"] as? String else { | ||
result(FlutterError(code: "ABNORMAL_PARAMETER", message: "address and filePath are required", details: nil)) | ||
return | ||
} | ||
|
||
let forceDfu = arguments["forceDfu"] as? Bool | ||
|
||
let enableUnsafeExperimentalButtonlessServiceInSecureDfu = arguments["enableUnsafeExperimentalButtonlessServiceInSecureDfu"] as? Bool | ||
|
||
let fileInAsset = (arguments["fileInAsset"] as? Bool) ?? false | ||
|
||
if (fileInAsset) { | ||
//let key = registrar.lookupKey(forAsset: filePath) | ||
guard let pathInAsset = Bundle.main.path(forResource: filePath, ofType: nil) else { | ||
result(FlutterError(code: "ABNORMAL_PARAMETER", message: "file in asset not found \(filePath)", details: nil)) | ||
return | ||
} | ||
|
||
filePath = pathInAsset | ||
} | ||
|
||
let alternativeAdvertisingNameEnabled = arguments["alternativeAdvertisingNameEnabled"] as? Bool | ||
|
||
startDfu(address, | ||
name: name, | ||
filePath: filePath, | ||
forceDfu: forceDfu, | ||
enableUnsafeExperimentalButtonlessServiceInSecureDfu: enableUnsafeExperimentalButtonlessServiceInSecureDfu, | ||
alternativeAdvertisingNameEnabled: alternativeAdvertisingNameEnabled, | ||
result: result) | ||
} | ||
|
||
private func startDfu( | ||
_ address: String, | ||
name: String?, | ||
filePath: String, | ||
forceDfu: Bool?, | ||
enableUnsafeExperimentalButtonlessServiceInSecureDfu: Bool?, | ||
alternativeAdvertisingNameEnabled: Bool?, | ||
result: @escaping FlutterResult) { | ||
guard let uuid = UUID(uuidString: address) else { | ||
result(FlutterError(code: "DEVICE_ADDRESS_ERROR", message: "Device address conver to uuid failed", details: "Device uuid \(address) convert to uuid failed")) | ||
return | ||
} | ||
|
||
do{ | ||
let firmware = try DFUFirmware(urlToZipFile: URL(fileURLWithPath: filePath)) | ||
|
||
|
||
|
||
let dfuInitiator = DFUServiceInitiator(queue: nil) | ||
.with(firmware: firmware); | ||
dfuInitiator.delegate = self | ||
dfuInitiator.progressDelegate = self | ||
dfuInitiator.logger = self | ||
|
||
if let enableUnsafeExperimentalButtonlessServiceInSecureDfu = enableUnsafeExperimentalButtonlessServiceInSecureDfu { | ||
dfuInitiator.enableUnsafeExperimentalButtonlessServiceInSecureDfu = enableUnsafeExperimentalButtonlessServiceInSecureDfu | ||
} | ||
|
||
if let forceDfu = forceDfu { | ||
dfuInitiator.forceDfu = forceDfu | ||
} | ||
|
||
if let alternativeAdvertisingNameEnabled = alternativeAdvertisingNameEnabled { | ||
dfuInitiator.alternativeAdvertisingNameEnabled = alternativeAdvertisingNameEnabled | ||
} | ||
|
||
pendingResult = result | ||
deviceAddress = address | ||
|
||
dfuController = dfuInitiator.start(targetWithIdentifier: uuid) | ||
} | ||
catch{ | ||
result(FlutterError(code: "DFU_FIRMWARE_NOT_FOUND", message: "Could not dfu zip file", details: nil)) | ||
return | ||
} | ||
} | ||
|
||
// MARK: DFUServiceDelegate | ||
public func dfuStateDidChange(to state: DFUState) { | ||
switch state { | ||
case .completed: | ||
sink?(["onDfuCompleted":deviceAddress]) | ||
pendingResult?(deviceAddress) | ||
pendingResult = nil | ||
dfuController = nil | ||
case .disconnecting: | ||
sink?(["onDeviceDisconnecting":deviceAddress]) | ||
case .aborted: | ||
sink?(["onDfuAborted": deviceAddress]) | ||
pendingResult?(FlutterError(code: "DFU_ABORTED", message: "DFU ABORTED by user", details: "device address: \(deviceAddress!)")) | ||
pendingResult = nil | ||
case .connecting: | ||
sink?(["onDeviceConnecting":deviceAddress]) | ||
case .starting: | ||
sink?(["onDfuProcessStarting":deviceAddress]) | ||
case .enablingDfuMode: | ||
sink?(["onEnablingDfuMode":deviceAddress]) | ||
case .validating: | ||
sink?(["onFirmwareValidating":deviceAddress]) | ||
case .uploading: | ||
sink?(["onFirmwareUploading":deviceAddress]) | ||
} | ||
} | ||
|
||
public func dfuError(_ error: DFUError, didOccurWithMessage message: String) { | ||
sink?(["onError":["deviceAddress": deviceAddress!, "error": error.rawValue, "errorType":error.rawValue, "message": message]]) | ||
pendingResult?(FlutterError(code: "\(error.rawValue)", message: "DFU FAILED: \(message)", details: "Address: \(deviceAddress!), Error type \(error.rawValue)")) | ||
pendingResult = nil | ||
} | ||
|
||
//MARK: DFUProgressDelegate | ||
public func dfuProgressDidChange(for part: Int, outOf totalParts: Int, to progress: Int, currentSpeedBytesPerSecond: Double, avgSpeedBytesPerSecond: Double) { | ||
sink?(["onProgressChanged":["deviceAddress": deviceAddress!, "percent": progress, "speed":currentSpeedBytesPerSecond, "avgSpeed": avgSpeedBytesPerSecond, "currentPart": part, "partsTotal": totalParts]]) | ||
} | ||
|
||
//MARK: - LoggerDelegate | ||
public func logWith(_ level: LogLevel, message: String) { | ||
//print("\(level.name()): \(message)") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# | ||
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. | ||
# Run `pod lib lint hello.podspec` to validate before publishing. | ||
# | ||
Pod::Spec.new do |s| | ||
s.name = 'nordic_dfu' | ||
s.version = '1.0.0' | ||
s.summary = 'MACOS DFU plugin for flutter.' | ||
s.description = <<-DESC | ||
A new Flutter plugin project. | ||
DESC | ||
s.homepage = 'http://www.timeyaa.com' | ||
s.license = { :file => '../LICENSE' } | ||
s.author = { 'Timeyaa' => 'fengqiangboy@timeyaa.com' } | ||
|
||
s.source = { :path => '.' } | ||
s.source_files = 'Classes/**/*' | ||
s.public_header_files = 'Classes/**/*.h' | ||
s.swift_version = '5.4' | ||
s.dependency 'FlutterMacOS' | ||
s.dependency 'iOSDFULibrary', '~> 4.13.0' | ||
|
||
s.platform = :osx, '10.14' | ||
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters