Initial commit
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
.idea/
|
||||
.vagrant/
|
||||
.sconsign.dblite
|
||||
.svn/
|
||||
|
||||
.DS_Store
|
||||
*.swp
|
||||
profile
|
||||
|
||||
DerivedData/
|
||||
build/
|
||||
GeneratedPluginRegistrant.h
|
||||
GeneratedPluginRegistrant.m
|
||||
|
||||
.generated/
|
||||
|
||||
*.pbxuser
|
||||
*.mode1v3
|
||||
*.mode2v3
|
||||
*.perspectivev3
|
||||
|
||||
!default.pbxuser
|
||||
!default.mode1v3
|
||||
!default.mode2v3
|
||||
!default.perspectivev3
|
||||
|
||||
xcuserdata
|
||||
|
||||
*.moved-aside
|
||||
|
||||
*.pyc
|
||||
*sync/
|
||||
Icon?
|
||||
.tags*
|
||||
|
||||
/Flutter/Generated.xcconfig
|
||||
/Flutter/ephemeral/
|
||||
/Flutter/flutter_export_environment.sh
|
||||
@@ -0,0 +1,525 @@
|
||||
// Autogenerated from Pigeon (v13.0.0), do not edit directly.
|
||||
// See also: https://pub.dev/packages/pigeon
|
||||
|
||||
import Foundation
|
||||
#if os(iOS)
|
||||
import Flutter
|
||||
#elseif os(macOS)
|
||||
import FlutterMacOS
|
||||
#else
|
||||
#error("Unsupported platform.")
|
||||
#endif
|
||||
|
||||
private func isNullish(_ value: Any?) -> Bool {
|
||||
return value is NSNull || value == nil
|
||||
}
|
||||
|
||||
private func wrapResult(_ result: Any?) -> [Any?] {
|
||||
return [result]
|
||||
}
|
||||
|
||||
private func wrapError(_ error: Any) -> [Any?] {
|
||||
if let flutterError = error as? FlutterError {
|
||||
return [
|
||||
flutterError.code,
|
||||
flutterError.message,
|
||||
flutterError.details
|
||||
]
|
||||
}
|
||||
return [
|
||||
"\(error)",
|
||||
"\(type(of: error))",
|
||||
"Stacktrace: \(Thread.callStackSymbols)"
|
||||
]
|
||||
}
|
||||
|
||||
private func nilOrValue<T>(_ value: Any?) -> T? {
|
||||
if value is NSNull { return nil }
|
||||
return value as! T?
|
||||
}
|
||||
|
||||
/// Generated class from Pigeon that represents data sent in messages.
|
||||
struct UniversalBleScanResult {
|
||||
var deviceId: String
|
||||
var name: String? = nil
|
||||
var isPaired: Bool? = nil
|
||||
var rssi: Int64? = nil
|
||||
var manufacturerData: FlutterStandardTypedData? = nil
|
||||
var manufacturerDataHead: FlutterStandardTypedData? = nil
|
||||
|
||||
static func fromList(_ list: [Any?]) -> UniversalBleScanResult? {
|
||||
let deviceId = list[0] as! String
|
||||
let name: String? = nilOrValue(list[1])
|
||||
let isPaired: Bool? = nilOrValue(list[2])
|
||||
let rssi: Int64? = isNullish(list[3]) ? nil : (list[3] is Int64? ? list[3] as! Int64? : Int64(list[3] as! Int32))
|
||||
let manufacturerData: FlutterStandardTypedData? = nilOrValue(list[4])
|
||||
let manufacturerDataHead: FlutterStandardTypedData? = nilOrValue(list[5])
|
||||
|
||||
return UniversalBleScanResult(
|
||||
deviceId: deviceId,
|
||||
name: name,
|
||||
isPaired: isPaired,
|
||||
rssi: rssi,
|
||||
manufacturerData: manufacturerData,
|
||||
manufacturerDataHead: manufacturerDataHead
|
||||
)
|
||||
}
|
||||
func toList() -> [Any?] {
|
||||
return [
|
||||
deviceId,
|
||||
name,
|
||||
isPaired,
|
||||
rssi,
|
||||
manufacturerData,
|
||||
manufacturerDataHead,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
/// Generated class from Pigeon that represents data sent in messages.
|
||||
struct UniversalBleService {
|
||||
var uuid: String
|
||||
var characteristics: [UniversalBleCharacteristic?]? = nil
|
||||
|
||||
static func fromList(_ list: [Any?]) -> UniversalBleService? {
|
||||
let uuid = list[0] as! String
|
||||
let characteristics: [UniversalBleCharacteristic?]? = nilOrValue(list[1])
|
||||
|
||||
return UniversalBleService(
|
||||
uuid: uuid,
|
||||
characteristics: characteristics
|
||||
)
|
||||
}
|
||||
func toList() -> [Any?] {
|
||||
return [
|
||||
uuid,
|
||||
characteristics,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
/// Generated class from Pigeon that represents data sent in messages.
|
||||
struct UniversalBleCharacteristic {
|
||||
var uuid: String
|
||||
var properties: [Int64?]
|
||||
|
||||
static func fromList(_ list: [Any?]) -> UniversalBleCharacteristic? {
|
||||
let uuid = list[0] as! String
|
||||
let properties = list[1] as! [Int64?]
|
||||
|
||||
return UniversalBleCharacteristic(
|
||||
uuid: uuid,
|
||||
properties: properties
|
||||
)
|
||||
}
|
||||
func toList() -> [Any?] {
|
||||
return [
|
||||
uuid,
|
||||
properties,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
private class UniversalBlePlatformChannelCodecReader: FlutterStandardReader {
|
||||
override func readValue(ofType type: UInt8) -> Any? {
|
||||
switch type {
|
||||
case 128:
|
||||
return UniversalBleCharacteristic.fromList(self.readValue() as! [Any?])
|
||||
case 129:
|
||||
return UniversalBleScanResult.fromList(self.readValue() as! [Any?])
|
||||
case 130:
|
||||
return UniversalBleService.fromList(self.readValue() as! [Any?])
|
||||
default:
|
||||
return super.readValue(ofType: type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class UniversalBlePlatformChannelCodecWriter: FlutterStandardWriter {
|
||||
override func writeValue(_ value: Any) {
|
||||
if let value = value as? UniversalBleCharacteristic {
|
||||
super.writeByte(128)
|
||||
super.writeValue(value.toList())
|
||||
} else if let value = value as? UniversalBleScanResult {
|
||||
super.writeByte(129)
|
||||
super.writeValue(value.toList())
|
||||
} else if let value = value as? UniversalBleService {
|
||||
super.writeByte(130)
|
||||
super.writeValue(value.toList())
|
||||
} else {
|
||||
super.writeValue(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class UniversalBlePlatformChannelCodecReaderWriter: FlutterStandardReaderWriter {
|
||||
override func reader(with data: Data) -> FlutterStandardReader {
|
||||
return UniversalBlePlatformChannelCodecReader(data: data)
|
||||
}
|
||||
|
||||
override func writer(with data: NSMutableData) -> FlutterStandardWriter {
|
||||
return UniversalBlePlatformChannelCodecWriter(data: data)
|
||||
}
|
||||
}
|
||||
|
||||
class UniversalBlePlatformChannelCodec: FlutterStandardMessageCodec {
|
||||
static let shared = UniversalBlePlatformChannelCodec(readerWriter: UniversalBlePlatformChannelCodecReaderWriter())
|
||||
}
|
||||
|
||||
/// Flutter -> Native
|
||||
///
|
||||
/// Generated protocol from Pigeon that represents a handler of messages from Flutter.
|
||||
protocol UniversalBlePlatformChannel {
|
||||
func getBluetoothAvailabilityState(completion: @escaping (Result<Int64, Error>) -> Void)
|
||||
func enableBluetooth(completion: @escaping (Result<Bool, Error>) -> Void)
|
||||
func startScan() throws
|
||||
func stopScan() throws
|
||||
func connect(deviceId: String) throws
|
||||
func disconnect(deviceId: String) throws
|
||||
func setNotifiable(deviceId: String, service: String, characteristic: String, bleInputProperty: Int64) throws
|
||||
func discoverServices(deviceId: String, completion: @escaping (Result<[UniversalBleService], Error>) -> Void)
|
||||
func readValue(deviceId: String, service: String, characteristic: String, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void)
|
||||
func requestMtu(deviceId: String, expectedMtu: Int64, completion: @escaping (Result<Int64, Error>) -> Void)
|
||||
func writeValue(deviceId: String, service: String, characteristic: String, value: FlutterStandardTypedData, bleOutputProperty: Int64, completion: @escaping (Result<Void, Error>) -> Void)
|
||||
func isPaired(deviceId: String, completion: @escaping (Result<Bool, Error>) -> Void)
|
||||
func pair(deviceId: String) throws
|
||||
func unPair(deviceId: String) throws
|
||||
func getConnectedDevices(withServices: [String], completion: @escaping (Result<[UniversalBleScanResult], Error>) -> Void)
|
||||
}
|
||||
|
||||
/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`.
|
||||
class UniversalBlePlatformChannelSetup {
|
||||
/// The codec used by UniversalBlePlatformChannel.
|
||||
static var codec: FlutterStandardMessageCodec { UniversalBlePlatformChannelCodec.shared }
|
||||
/// Sets up an instance of `UniversalBlePlatformChannel` to handle messages through the `binaryMessenger`.
|
||||
static func setUp(binaryMessenger: FlutterBinaryMessenger, api: UniversalBlePlatformChannel?) {
|
||||
let getBluetoothAvailabilityStateChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getBluetoothAvailabilityState", binaryMessenger: binaryMessenger, codec: codec)
|
||||
if let api = api {
|
||||
getBluetoothAvailabilityStateChannel.setMessageHandler { _, reply in
|
||||
api.getBluetoothAvailabilityState() { result in
|
||||
switch result {
|
||||
case .success(let res):
|
||||
reply(wrapResult(res))
|
||||
case .failure(let error):
|
||||
reply(wrapError(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
getBluetoothAvailabilityStateChannel.setMessageHandler(nil)
|
||||
}
|
||||
let enableBluetoothChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.enableBluetooth", binaryMessenger: binaryMessenger, codec: codec)
|
||||
if let api = api {
|
||||
enableBluetoothChannel.setMessageHandler { _, reply in
|
||||
api.enableBluetooth() { result in
|
||||
switch result {
|
||||
case .success(let res):
|
||||
reply(wrapResult(res))
|
||||
case .failure(let error):
|
||||
reply(wrapError(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
enableBluetoothChannel.setMessageHandler(nil)
|
||||
}
|
||||
let startScanChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.startScan", binaryMessenger: binaryMessenger, codec: codec)
|
||||
if let api = api {
|
||||
startScanChannel.setMessageHandler { _, reply in
|
||||
do {
|
||||
try api.startScan()
|
||||
reply(wrapResult(nil))
|
||||
} catch {
|
||||
reply(wrapError(error))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
startScanChannel.setMessageHandler(nil)
|
||||
}
|
||||
let stopScanChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.stopScan", binaryMessenger: binaryMessenger, codec: codec)
|
||||
if let api = api {
|
||||
stopScanChannel.setMessageHandler { _, reply in
|
||||
do {
|
||||
try api.stopScan()
|
||||
reply(wrapResult(nil))
|
||||
} catch {
|
||||
reply(wrapError(error))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
stopScanChannel.setMessageHandler(nil)
|
||||
}
|
||||
let connectChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.connect", binaryMessenger: binaryMessenger, codec: codec)
|
||||
if let api = api {
|
||||
connectChannel.setMessageHandler { message, reply in
|
||||
let args = message as! [Any?]
|
||||
let deviceIdArg = args[0] as! String
|
||||
do {
|
||||
try api.connect(deviceId: deviceIdArg)
|
||||
reply(wrapResult(nil))
|
||||
} catch {
|
||||
reply(wrapError(error))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
connectChannel.setMessageHandler(nil)
|
||||
}
|
||||
let disconnectChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.disconnect", binaryMessenger: binaryMessenger, codec: codec)
|
||||
if let api = api {
|
||||
disconnectChannel.setMessageHandler { message, reply in
|
||||
let args = message as! [Any?]
|
||||
let deviceIdArg = args[0] as! String
|
||||
do {
|
||||
try api.disconnect(deviceId: deviceIdArg)
|
||||
reply(wrapResult(nil))
|
||||
} catch {
|
||||
reply(wrapError(error))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
disconnectChannel.setMessageHandler(nil)
|
||||
}
|
||||
let setNotifiableChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setNotifiable", binaryMessenger: binaryMessenger, codec: codec)
|
||||
if let api = api {
|
||||
setNotifiableChannel.setMessageHandler { message, reply in
|
||||
let args = message as! [Any?]
|
||||
let deviceIdArg = args[0] as! String
|
||||
let serviceArg = args[1] as! String
|
||||
let characteristicArg = args[2] as! String
|
||||
let bleInputPropertyArg = args[3] is Int64 ? args[3] as! Int64 : Int64(args[3] as! Int32)
|
||||
do {
|
||||
try api.setNotifiable(deviceId: deviceIdArg, service: serviceArg, characteristic: characteristicArg, bleInputProperty: bleInputPropertyArg)
|
||||
reply(wrapResult(nil))
|
||||
} catch {
|
||||
reply(wrapError(error))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setNotifiableChannel.setMessageHandler(nil)
|
||||
}
|
||||
let discoverServicesChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.discoverServices", binaryMessenger: binaryMessenger, codec: codec)
|
||||
if let api = api {
|
||||
discoverServicesChannel.setMessageHandler { message, reply in
|
||||
let args = message as! [Any?]
|
||||
let deviceIdArg = args[0] as! String
|
||||
api.discoverServices(deviceId: deviceIdArg) { result in
|
||||
switch result {
|
||||
case .success(let res):
|
||||
reply(wrapResult(res))
|
||||
case .failure(let error):
|
||||
reply(wrapError(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
discoverServicesChannel.setMessageHandler(nil)
|
||||
}
|
||||
let readValueChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readValue", binaryMessenger: binaryMessenger, codec: codec)
|
||||
if let api = api {
|
||||
readValueChannel.setMessageHandler { message, reply in
|
||||
let args = message as! [Any?]
|
||||
let deviceIdArg = args[0] as! String
|
||||
let serviceArg = args[1] as! String
|
||||
let characteristicArg = args[2] as! String
|
||||
api.readValue(deviceId: deviceIdArg, service: serviceArg, characteristic: characteristicArg) { result in
|
||||
switch result {
|
||||
case .success(let res):
|
||||
reply(wrapResult(res))
|
||||
case .failure(let error):
|
||||
reply(wrapError(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
readValueChannel.setMessageHandler(nil)
|
||||
}
|
||||
let requestMtuChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.requestMtu", binaryMessenger: binaryMessenger, codec: codec)
|
||||
if let api = api {
|
||||
requestMtuChannel.setMessageHandler { message, reply in
|
||||
let args = message as! [Any?]
|
||||
let deviceIdArg = args[0] as! String
|
||||
let expectedMtuArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32)
|
||||
api.requestMtu(deviceId: deviceIdArg, expectedMtu: expectedMtuArg) { result in
|
||||
switch result {
|
||||
case .success(let res):
|
||||
reply(wrapResult(res))
|
||||
case .failure(let error):
|
||||
reply(wrapError(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
requestMtuChannel.setMessageHandler(nil)
|
||||
}
|
||||
let writeValueChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.writeValue", binaryMessenger: binaryMessenger, codec: codec)
|
||||
if let api = api {
|
||||
writeValueChannel.setMessageHandler { message, reply in
|
||||
let args = message as! [Any?]
|
||||
let deviceIdArg = args[0] as! String
|
||||
let serviceArg = args[1] as! String
|
||||
let characteristicArg = args[2] as! String
|
||||
let valueArg = args[3] as! FlutterStandardTypedData
|
||||
let bleOutputPropertyArg = args[4] is Int64 ? args[4] as! Int64 : Int64(args[4] as! Int32)
|
||||
api.writeValue(deviceId: deviceIdArg, service: serviceArg, characteristic: characteristicArg, value: valueArg, bleOutputProperty: bleOutputPropertyArg) { result in
|
||||
switch result {
|
||||
case .success:
|
||||
reply(wrapResult(nil))
|
||||
case .failure(let error):
|
||||
reply(wrapError(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
writeValueChannel.setMessageHandler(nil)
|
||||
}
|
||||
let isPairedChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.isPaired", binaryMessenger: binaryMessenger, codec: codec)
|
||||
if let api = api {
|
||||
isPairedChannel.setMessageHandler { message, reply in
|
||||
let args = message as! [Any?]
|
||||
let deviceIdArg = args[0] as! String
|
||||
api.isPaired(deviceId: deviceIdArg) { result in
|
||||
switch result {
|
||||
case .success(let res):
|
||||
reply(wrapResult(res))
|
||||
case .failure(let error):
|
||||
reply(wrapError(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
isPairedChannel.setMessageHandler(nil)
|
||||
}
|
||||
let pairChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.pair", binaryMessenger: binaryMessenger, codec: codec)
|
||||
if let api = api {
|
||||
pairChannel.setMessageHandler { message, reply in
|
||||
let args = message as! [Any?]
|
||||
let deviceIdArg = args[0] as! String
|
||||
do {
|
||||
try api.pair(deviceId: deviceIdArg)
|
||||
reply(wrapResult(nil))
|
||||
} catch {
|
||||
reply(wrapError(error))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pairChannel.setMessageHandler(nil)
|
||||
}
|
||||
let unPairChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.unPair", binaryMessenger: binaryMessenger, codec: codec)
|
||||
if let api = api {
|
||||
unPairChannel.setMessageHandler { message, reply in
|
||||
let args = message as! [Any?]
|
||||
let deviceIdArg = args[0] as! String
|
||||
do {
|
||||
try api.unPair(deviceId: deviceIdArg)
|
||||
reply(wrapResult(nil))
|
||||
} catch {
|
||||
reply(wrapError(error))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unPairChannel.setMessageHandler(nil)
|
||||
}
|
||||
let getConnectedDevicesChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getConnectedDevices", binaryMessenger: binaryMessenger, codec: codec)
|
||||
if let api = api {
|
||||
getConnectedDevicesChannel.setMessageHandler { message, reply in
|
||||
let args = message as! [Any?]
|
||||
let withServicesArg = args[0] as! [String]
|
||||
api.getConnectedDevices(withServices: withServicesArg) { result in
|
||||
switch result {
|
||||
case .success(let res):
|
||||
reply(wrapResult(res))
|
||||
case .failure(let error):
|
||||
reply(wrapError(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
getConnectedDevicesChannel.setMessageHandler(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
private class UniversalBleCallbackChannelCodecReader: FlutterStandardReader {
|
||||
override func readValue(ofType type: UInt8) -> Any? {
|
||||
switch type {
|
||||
case 128:
|
||||
return UniversalBleScanResult.fromList(self.readValue() as! [Any?])
|
||||
default:
|
||||
return super.readValue(ofType: type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class UniversalBleCallbackChannelCodecWriter: FlutterStandardWriter {
|
||||
override func writeValue(_ value: Any) {
|
||||
if let value = value as? UniversalBleScanResult {
|
||||
super.writeByte(128)
|
||||
super.writeValue(value.toList())
|
||||
} else {
|
||||
super.writeValue(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class UniversalBleCallbackChannelCodecReaderWriter: FlutterStandardReaderWriter {
|
||||
override func reader(with data: Data) -> FlutterStandardReader {
|
||||
return UniversalBleCallbackChannelCodecReader(data: data)
|
||||
}
|
||||
|
||||
override func writer(with data: NSMutableData) -> FlutterStandardWriter {
|
||||
return UniversalBleCallbackChannelCodecWriter(data: data)
|
||||
}
|
||||
}
|
||||
|
||||
class UniversalBleCallbackChannelCodec: FlutterStandardMessageCodec {
|
||||
static let shared = UniversalBleCallbackChannelCodec(readerWriter: UniversalBleCallbackChannelCodecReaderWriter())
|
||||
}
|
||||
|
||||
/// Native -> Flutter
|
||||
///
|
||||
/// Generated protocol from Pigeon that represents Flutter messages that can be called from Swift.
|
||||
protocol UniversalBleCallbackChannelProtocol {
|
||||
func onAvailabilityChanged(state stateArg: Int64, completion: @escaping (Result<Void, FlutterError>) -> Void)
|
||||
func onPairStateChange(deviceId deviceIdArg: String, isPaired isPairedArg: Bool, error errorArg: String?, completion: @escaping (Result<Void, FlutterError>) -> Void)
|
||||
func onScanResult(result resultArg: UniversalBleScanResult, completion: @escaping (Result<Void, FlutterError>) -> Void)
|
||||
func onValueChanged(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, value valueArg: FlutterStandardTypedData, completion: @escaping (Result<Void, FlutterError>) -> Void)
|
||||
func onConnectionChanged(deviceId deviceIdArg: String, state stateArg: Int64, completion: @escaping (Result<Void, FlutterError>) -> Void)
|
||||
}
|
||||
class UniversalBleCallbackChannel: UniversalBleCallbackChannelProtocol {
|
||||
private let binaryMessenger: FlutterBinaryMessenger
|
||||
init(binaryMessenger: FlutterBinaryMessenger){
|
||||
self.binaryMessenger = binaryMessenger
|
||||
}
|
||||
var codec: FlutterStandardMessageCodec {
|
||||
return UniversalBleCallbackChannelCodec.shared
|
||||
}
|
||||
func onAvailabilityChanged(state stateArg: Int64, completion: @escaping (Result<Void, FlutterError>) -> Void) {
|
||||
let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onAvailabilityChanged", binaryMessenger: binaryMessenger, codec: codec)
|
||||
channel.sendMessage([stateArg] as [Any?]) { _ in
|
||||
completion(.success(Void()))
|
||||
}
|
||||
}
|
||||
func onPairStateChange(deviceId deviceIdArg: String, isPaired isPairedArg: Bool, error errorArg: String?, completion: @escaping (Result<Void, FlutterError>) -> Void) {
|
||||
let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onPairStateChange", binaryMessenger: binaryMessenger, codec: codec)
|
||||
channel.sendMessage([deviceIdArg, isPairedArg, errorArg] as [Any?]) { _ in
|
||||
completion(.success(Void()))
|
||||
}
|
||||
}
|
||||
func onScanResult(result resultArg: UniversalBleScanResult, completion: @escaping (Result<Void, FlutterError>) -> Void) {
|
||||
let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onScanResult", binaryMessenger: binaryMessenger, codec: codec)
|
||||
channel.sendMessage([resultArg] as [Any?]) { _ in
|
||||
completion(.success(Void()))
|
||||
}
|
||||
}
|
||||
func onValueChanged(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, value valueArg: FlutterStandardTypedData, completion: @escaping (Result<Void, FlutterError>) -> Void) {
|
||||
let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onValueChanged", binaryMessenger: binaryMessenger, codec: codec)
|
||||
channel.sendMessage([deviceIdArg, characteristicIdArg, valueArg] as [Any?]) { _ in
|
||||
completion(.success(Void()))
|
||||
}
|
||||
}
|
||||
func onConnectionChanged(deviceId deviceIdArg: String, state stateArg: Int64, completion: @escaping (Result<Void, FlutterError>) -> Void) {
|
||||
let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onConnectionChanged", binaryMessenger: binaryMessenger, codec: codec)
|
||||
channel.sendMessage([deviceIdArg, stateArg] as [Any?]) { _ in
|
||||
completion(.success(Void()))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
//
|
||||
// UniversalBleHelper.swift
|
||||
// universal_ble
|
||||
//
|
||||
// Created by Rohit Sangwan on 25/10/23.
|
||||
//
|
||||
|
||||
import CoreBluetooth
|
||||
import Foundation
|
||||
#if os(iOS)
|
||||
import Flutter
|
||||
#elseif os(OSX)
|
||||
import FlutterMacOS
|
||||
#endif
|
||||
|
||||
enum BleInputProperty: Int {
|
||||
case disabled = 0
|
||||
case notification = 1
|
||||
case indication = 2
|
||||
}
|
||||
|
||||
enum BleOutputProperty: Int {
|
||||
case withResponse = 0
|
||||
case withoutResponse = 1
|
||||
}
|
||||
|
||||
enum BlueConnectionState: Int64 {
|
||||
case connected = 0
|
||||
case disconnected = 1
|
||||
}
|
||||
|
||||
enum AvailabilityState: Int64 {
|
||||
case unknown = 0
|
||||
case resetting = 1
|
||||
case unsupported = 2
|
||||
case unauthorized = 3
|
||||
case poweredOff = 4
|
||||
case poweredOn = 5
|
||||
}
|
||||
|
||||
enum CharacteristicProperty: Int64 {
|
||||
case broadcast = 0
|
||||
case read = 1
|
||||
case writeWithoutResponse = 2
|
||||
case write = 3
|
||||
case notify = 4
|
||||
case indicate = 5
|
||||
case authenticatedSignedWrites = 6
|
||||
case extendedProperties = 7
|
||||
}
|
||||
|
||||
extension CBCharacteristicProperties {
|
||||
var toCharacteristicProperty: [Int64] {
|
||||
var properties = [Int64]()
|
||||
if contains(.broadcast) {
|
||||
properties.append(CharacteristicProperty.broadcast.rawValue)
|
||||
}
|
||||
if contains(.read) {
|
||||
properties.append(CharacteristicProperty.read.rawValue)
|
||||
}
|
||||
if contains(.writeWithoutResponse) {
|
||||
properties.append(CharacteristicProperty.writeWithoutResponse.rawValue)
|
||||
}
|
||||
if contains(.write) {
|
||||
properties.append(CharacteristicProperty.write.rawValue)
|
||||
}
|
||||
if contains(.notify) {
|
||||
properties.append(CharacteristicProperty.notify.rawValue)
|
||||
}
|
||||
if contains(.indicate) {
|
||||
properties.append(CharacteristicProperty.indicate.rawValue)
|
||||
}
|
||||
if contains(.authenticatedSignedWrites) {
|
||||
properties.append(CharacteristicProperty.authenticatedSignedWrites.rawValue)
|
||||
}
|
||||
if contains(.extendedProperties) {
|
||||
properties.append(CharacteristicProperty.extendedProperties.rawValue)
|
||||
}
|
||||
return properties
|
||||
}
|
||||
}
|
||||
|
||||
extension CBManagerState {
|
||||
func toAvailabilityState() -> AvailabilityState {
|
||||
switch self {
|
||||
case .unknown:
|
||||
return AvailabilityState.unknown
|
||||
case .resetting:
|
||||
return AvailabilityState.resetting
|
||||
case .unsupported:
|
||||
return AvailabilityState.unsupported
|
||||
case .unauthorized:
|
||||
return AvailabilityState.unauthorized
|
||||
case .poweredOff:
|
||||
return AvailabilityState.poweredOff
|
||||
case .poweredOn:
|
||||
return AvailabilityState.poweredOn
|
||||
@unknown default:
|
||||
return AvailabilityState.unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public extension CBUUID {
|
||||
var uuidStr: String {
|
||||
uuidString.lowercased()
|
||||
}
|
||||
}
|
||||
|
||||
public extension CBPeripheral {
|
||||
// FIXME: https://forums.developer.apple.com/thread/84375
|
||||
var uuid: UUID {
|
||||
value(forKey: "identifier") as! NSUUID as UUID
|
||||
}
|
||||
|
||||
func getCharacteristic(_ characteristic: String, of service: String) -> CBCharacteristic? {
|
||||
let GSS_SUFFIX = "0000-1000-8000-00805f9b34fb"
|
||||
let s = services?.first {
|
||||
$0.uuid.uuidStr.lowercased() == service.lowercased() || service.lowercased() == "0000\($0.uuid.uuidStr)-\(GSS_SUFFIX)".lowercased()
|
||||
}
|
||||
let c = s?.characteristics?.first {
|
||||
$0.uuid.uuidStr.lowercased() == characteristic.lowercased() || characteristic.lowercased() == "0000\($0.uuid.uuidStr)-\(GSS_SUFFIX)".lowercased()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func setNotifiable(_ bleInputProperty: String, for characteristic: String, of service: String) {
|
||||
guard let characteristic = getCharacteristic(characteristic, of: service) else {
|
||||
return
|
||||
}
|
||||
setNotifyValue(bleInputProperty != "disabled", for: characteristic)
|
||||
}
|
||||
}
|
||||
|
||||
// Future classes
|
||||
class CharacteristicReadFuture {
|
||||
let deviceId: String
|
||||
let characteristicId: String
|
||||
let serviceId: String?
|
||||
let result: (Result<FlutterStandardTypedData, Error>) -> Void
|
||||
|
||||
init(deviceId: String, characteristicId: String, serviceId: String?, result: @escaping (Result<FlutterStandardTypedData, Error>) -> Void) {
|
||||
self.deviceId = deviceId
|
||||
self.characteristicId = characteristicId
|
||||
self.serviceId = serviceId
|
||||
self.result = result
|
||||
}
|
||||
}
|
||||
|
||||
class CharacteristicWriteFuture {
|
||||
let deviceId: String
|
||||
let characteristicId: String
|
||||
let serviceId: String?
|
||||
let result: (Result<Void, Error>) -> Void
|
||||
|
||||
init(deviceId: String, characteristicId: String, serviceId: String?, result: @escaping (Result<Void, Error>) -> Void) {
|
||||
self.deviceId = deviceId
|
||||
self.characteristicId = characteristicId
|
||||
self.serviceId = serviceId
|
||||
self.result = result
|
||||
}
|
||||
}
|
||||
|
||||
class DiscoverServicesFuture {
|
||||
let deviceId: String
|
||||
let result: (Result<[UniversalBleService], Error>) -> Void
|
||||
|
||||
init(deviceId: String, result: @escaping (Result<[UniversalBleService], Error>) -> Void) {
|
||||
self.deviceId = deviceId
|
||||
self.result = result
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,334 @@
|
||||
import CoreBluetooth
|
||||
|
||||
#if os(iOS)
|
||||
import Flutter
|
||||
import UIKit
|
||||
#elseif os(OSX)
|
||||
import Cocoa
|
||||
import FlutterMacOS
|
||||
#endif
|
||||
|
||||
public class UniversalBlePlugin: NSObject, FlutterPlugin {
|
||||
public static func register(with registrar: FlutterPluginRegistrar) {
|
||||
var messenger: FlutterBinaryMessenger
|
||||
#if os(iOS)
|
||||
messenger = registrar.messenger()
|
||||
#elseif os(macOS)
|
||||
messenger = registrar.messenger
|
||||
#endif
|
||||
let callbackChannel = UniversalBleCallbackChannel(binaryMessenger: messenger)
|
||||
let api = BleCentralDarwin(callbackChannel: callbackChannel)
|
||||
UniversalBlePlatformChannelSetup.setUp(binaryMessenger: messenger, api: api)
|
||||
}
|
||||
}
|
||||
|
||||
private var discoveredPeripherals = [String: CBPeripheral]()
|
||||
|
||||
private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentralManagerDelegate, CBPeripheralDelegate {
|
||||
var callbackChannel: UniversalBleCallbackChannel
|
||||
private lazy var manager: CBCentralManager = .init(delegate: self, queue: nil)
|
||||
private var discoveredServicesProgressMap: [String: [UniversalBleService]] = [:]
|
||||
private var characteristicReadFutures = [CharacteristicReadFuture]()
|
||||
private var characteristicWriteFutures = [CharacteristicWriteFuture]()
|
||||
private var discoverServicesFutures = [DiscoverServicesFuture]()
|
||||
private var bluetoothAvailabilityStateCallback: ((Result<Int64, Error>) -> Void)? {
|
||||
didSet {
|
||||
oldValue?(Result.success(AvailabilityState.unknown.rawValue))
|
||||
}
|
||||
}
|
||||
|
||||
init(callbackChannel: UniversalBleCallbackChannel) {
|
||||
self.callbackChannel = callbackChannel
|
||||
super.init()
|
||||
}
|
||||
|
||||
func getBluetoothAvailabilityState(completion: @escaping (Result<Int64, Error>) -> Void) {
|
||||
let managerState = manager.state
|
||||
|
||||
if managerState == .unknown {
|
||||
bluetoothAvailabilityStateCallback = completion
|
||||
} else {
|
||||
completion(.success(managerState.toAvailabilityState().rawValue))
|
||||
}
|
||||
}
|
||||
|
||||
func enableBluetooth(completion: @escaping (Result<Bool, Error>) -> Void) {
|
||||
completion(Result.failure(FlutterError(code: "NotSupported", message: nil, details: nil)))
|
||||
}
|
||||
|
||||
func startScan() throws {
|
||||
manager.scanForPeripherals(withServices: nil)
|
||||
}
|
||||
|
||||
func stopScan() throws {
|
||||
manager.stopScan()
|
||||
}
|
||||
|
||||
func connect(deviceId: String) throws {
|
||||
let peripheral = try deviceId.getPeripheral()
|
||||
peripheral.delegate = self
|
||||
manager.connect(peripheral)
|
||||
}
|
||||
|
||||
func disconnect(deviceId: String) throws {
|
||||
let peripheral = try deviceId.getPeripheral()
|
||||
if peripheral.state != CBPeripheralState.disconnected {
|
||||
manager.cancelPeripheralConnection(peripheral)
|
||||
}
|
||||
cleanUpConnection(deviceId: deviceId)
|
||||
}
|
||||
|
||||
func cleanUpConnection(deviceId: String) {
|
||||
characteristicReadFutures.removeAll { future in
|
||||
future.deviceId == deviceId
|
||||
}
|
||||
discoverServicesFutures.removeAll { future in
|
||||
future.deviceId == deviceId
|
||||
}
|
||||
discoveredServicesProgressMap[deviceId] = nil
|
||||
}
|
||||
|
||||
func discoverServices(deviceId: String, completion: @escaping (Result<[UniversalBleService], Error>) -> Void) {
|
||||
guard let peripheral = discoveredPeripherals[deviceId] else {
|
||||
completion(Result.failure(
|
||||
FlutterError(code: "IllegalArgument", message: "Unknown deviceId:\(self)", details: nil)))
|
||||
return
|
||||
}
|
||||
if discoveredServicesProgressMap[deviceId] != nil {
|
||||
completion(Result.failure(FlutterError(code: "AlreadyInProgress", message: "Services discovery already in progress for :\(deviceId)", details: nil)))
|
||||
return
|
||||
}
|
||||
peripheral.discoverServices(nil)
|
||||
discoverServicesFutures.append(DiscoverServicesFuture(deviceId: deviceId, result: completion))
|
||||
}
|
||||
|
||||
private func onServicesDiscovered(deviceId: String, services: [UniversalBleService]) {
|
||||
discoverServicesFutures.removeAll { future in
|
||||
if future.deviceId == deviceId {
|
||||
future.result(Result.success(services))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func setNotifiable(deviceId: String, service: String, characteristic: String, bleInputProperty: Int64) throws {
|
||||
let peripheral = try deviceId.getPeripheral()
|
||||
|
||||
guard let c = peripheral.getCharacteristic(characteristic, of: service) else {
|
||||
throw FlutterError(code: "IllegalArgument", message: "Unknown characteristic:\(characteristic)", details: nil)
|
||||
}
|
||||
|
||||
if bleInputProperty == BleInputProperty.notification.rawValue && !c.properties.contains(.notify) {
|
||||
throw FlutterError(code: "InvalidAction", message: "Characteristic does not support notify", details: nil)
|
||||
}
|
||||
|
||||
if bleInputProperty == BleInputProperty.indication.rawValue && !c.properties.contains(.indicate) {
|
||||
throw FlutterError(code: "InvalidAction", message: "Characteristic does not support indicate", details: nil)
|
||||
}
|
||||
|
||||
let shouldNotify = bleInputProperty != BleInputProperty.disabled.rawValue
|
||||
peripheral.setNotifyValue(shouldNotify, for: c)
|
||||
}
|
||||
|
||||
func readValue(deviceId: String, service: String, characteristic: String, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void) {
|
||||
guard let peripheral = discoveredPeripherals[deviceId] else {
|
||||
completion(Result.failure(FlutterError(code: "IllegalArgument", message: "Unknown deviceId:\(self)", details: nil)))
|
||||
return
|
||||
}
|
||||
guard let gattCharacteristic = peripheral.getCharacteristic(characteristic, of: service) else {
|
||||
completion(Result.failure(FlutterError(code: "IllegalArgument", message: "Unknown characteristic:\(characteristic)", details: nil)))
|
||||
return
|
||||
}
|
||||
if !gattCharacteristic.properties.contains(.read) {
|
||||
completion(Result.failure(FlutterError(code: "InvalidAction", message: "Characteristic does not support read", details: nil)))
|
||||
return
|
||||
}
|
||||
peripheral.readValue(for: gattCharacteristic)
|
||||
characteristicReadFutures.append(CharacteristicReadFuture(deviceId: deviceId, characteristicId: gattCharacteristic.uuid.uuidStr, serviceId: gattCharacteristic.service?.uuid.uuidStr, result: completion))
|
||||
}
|
||||
|
||||
func writeValue(deviceId: String, service: String, characteristic: String, value: FlutterStandardTypedData, bleOutputProperty: Int64, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
guard let peripheral = discoveredPeripherals[deviceId] else {
|
||||
completion(Result.failure(FlutterError(code: "IllegalArgument", message: "Unknown deviceId:\(self)", details: nil)))
|
||||
return
|
||||
}
|
||||
guard let gattCharacteristic = peripheral.getCharacteristic(characteristic, of: service) else {
|
||||
completion(Result.failure(FlutterError(code: "IllegalArgument", message: "Unknown characteristic:\(characteristic)", details: nil)))
|
||||
return
|
||||
}
|
||||
|
||||
let type = bleOutputProperty == BleOutputProperty.withoutResponse.rawValue ? CBCharacteristicWriteType.withoutResponse : CBCharacteristicWriteType.withResponse
|
||||
|
||||
if type == CBCharacteristicWriteType.withResponse {
|
||||
if !gattCharacteristic.properties.contains(.write) {
|
||||
completion(Result.failure(FlutterError(code: "InvalidAction", message: "Characteristic does not support write withResponse", details: nil)))
|
||||
return
|
||||
}
|
||||
} else if type == CBCharacteristicWriteType.withoutResponse {
|
||||
if !gattCharacteristic.properties.contains(.writeWithoutResponse) {
|
||||
completion(Result.failure(FlutterError(code: "InvalidAction", message: "Characteristic does not support write withoutResponse", details: nil)))
|
||||
return
|
||||
}
|
||||
}
|
||||
peripheral.writeValue(value.data, for: gattCharacteristic, type: type)
|
||||
|
||||
if type == CBCharacteristicWriteType.withResponse {
|
||||
// Wait for future response
|
||||
characteristicWriteFutures.append(CharacteristicWriteFuture(deviceId: deviceId, characteristicId: gattCharacteristic.uuid.uuidStr, serviceId: gattCharacteristic.service?.uuid.uuidStr, result: completion))
|
||||
} else {
|
||||
completion(Result.success({}()))
|
||||
}
|
||||
}
|
||||
|
||||
func requestMtu(deviceId: String, expectedMtu _: Int64, completion: @escaping (Result<Int64, Error>) -> Void) {
|
||||
guard let peripheral = discoveredPeripherals[deviceId] else {
|
||||
completion(Result.failure(FlutterError(code: "IllegalArgument", message: "Unknown deviceId:\(self)", details: nil)))
|
||||
return
|
||||
}
|
||||
let mtu = peripheral.maximumWriteValueLength(for: CBCharacteristicWriteType.withoutResponse)
|
||||
let GATT_HEADER_LENGTH = 3
|
||||
let mtuResult = Int64(mtu + GATT_HEADER_LENGTH)
|
||||
completion(Result.success(mtuResult))
|
||||
}
|
||||
|
||||
func isPaired(deviceId _: String, completion: @escaping (Result<Bool, Error>) -> Void) {
|
||||
completion(Result.failure(FlutterError(code: "NotSupported", message: nil, details: nil)))
|
||||
}
|
||||
|
||||
func pair(deviceId _: String) throws {
|
||||
throw FlutterError(code: "NotSupported", message: nil, details: nil)
|
||||
}
|
||||
|
||||
func unPair(deviceId _: String) throws {
|
||||
throw FlutterError(code: "NotSupported", message: nil, details: nil)
|
||||
}
|
||||
|
||||
func getConnectedDevices(withServices: [String], completion: @escaping (Result<[UniversalBleScanResult], Error>) -> Void) {
|
||||
var filterCBUUID = withServices.map { CBUUID(string: $0) }
|
||||
// We can't keep this filter empty, so adding a default filter
|
||||
if filterCBUUID.isEmpty { filterCBUUID.append(CBUUID(string: "1800")) }
|
||||
let bleDevices = manager.retrieveConnectedPeripherals(withServices: filterCBUUID)
|
||||
bleDevices.forEach { discoveredPeripherals[$0.uuid.uuidString] = $0 }
|
||||
completion(Result.success(bleDevices.map {
|
||||
UniversalBleScanResult(
|
||||
deviceId: $0.uuid.uuidString,
|
||||
name: $0.name ?? ""
|
||||
)
|
||||
}))
|
||||
}
|
||||
|
||||
func centralManagerDidUpdateState(_ central: CBCentralManager) {
|
||||
let state = central.state.toAvailabilityState().rawValue
|
||||
callbackChannel.onAvailabilityChanged(state: state) { _ in }
|
||||
|
||||
bluetoothAvailabilityStateCallback?(Result.success(state))
|
||||
}
|
||||
|
||||
public func centralManager(_: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) {
|
||||
discoveredPeripherals[peripheral.uuid.uuidString] = peripheral
|
||||
let manufacturerData = advertisementData[CBAdvertisementDataManufacturerDataKey] as? Data
|
||||
callbackChannel.onScanResult(result: UniversalBleScanResult(
|
||||
deviceId: peripheral.uuid.uuidString,
|
||||
name: peripheral.name,
|
||||
isPaired: nil,
|
||||
rssi: RSSI as? Int64,
|
||||
manufacturerData: FlutterStandardTypedData(bytes: manufacturerData ?? Data())
|
||||
)) { _ in }
|
||||
}
|
||||
|
||||
public func centralManager(_: CBCentralManager, didConnect peripheral: CBPeripheral) {
|
||||
callbackChannel.onConnectionChanged(deviceId: peripheral.uuid.uuidString, state: BlueConnectionState.connected.rawValue) { _ in }
|
||||
}
|
||||
|
||||
public func centralManager(_: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error _: Error?) {
|
||||
callbackChannel.onConnectionChanged(deviceId: peripheral.uuid.uuidString, state: BlueConnectionState.disconnected.rawValue) { _ in }
|
||||
}
|
||||
|
||||
public func peripheral(_ peripheral: CBPeripheral, didDiscoverServices _: Error?) {
|
||||
let deviceId = peripheral.identifier.uuidString
|
||||
guard let services = peripheral.services else {
|
||||
onServicesDiscovered(deviceId: deviceId, services: [])
|
||||
return
|
||||
}
|
||||
discoveredServicesProgressMap[deviceId] = services.map { UniversalBleService(uuid: $0.uuid.uuidString, characteristics: nil) }
|
||||
for service in services {
|
||||
peripheral.discoverCharacteristics(nil, for: service)
|
||||
}
|
||||
}
|
||||
|
||||
public func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error _: Error?) {
|
||||
let deviceId = peripheral.identifier.uuidString
|
||||
var universalBleCharacteristicsList: [UniversalBleCharacteristic] = []
|
||||
for characteristic in service.characteristics ?? [] {
|
||||
universalBleCharacteristicsList.append(
|
||||
UniversalBleCharacteristic(uuid: characteristic.uuid.uuidString, properties: characteristic.properties.toCharacteristicProperty))
|
||||
}
|
||||
// Update discoveredServicesProgressMap
|
||||
if let index = discoveredServicesProgressMap[deviceId]?.firstIndex(where: { $0.uuid == service.uuid.uuidString }) {
|
||||
discoveredServicesProgressMap[deviceId]?[index] = UniversalBleService(uuid: service.uuid.uuidString, characteristics: universalBleCharacteristicsList)
|
||||
}
|
||||
// Check if all services and their characteristics have been discovered
|
||||
if discoveredServicesProgressMap[deviceId]?.allSatisfy({ $0.characteristics != nil }) ?? false {
|
||||
onServicesDiscovered(deviceId: deviceId, services: discoveredServicesProgressMap[deviceId] ?? [])
|
||||
discoveredServicesProgressMap[deviceId] = nil
|
||||
}
|
||||
}
|
||||
|
||||
public func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
|
||||
print("peripheral:didWriteValueForCharacteristic \(characteristic.uuid.uuidStr) error: \(String(describing: error))")
|
||||
// Update futures for writeValue
|
||||
characteristicWriteFutures.removeAll { future in
|
||||
if future.deviceId == peripheral.uuid.uuidString && future.characteristicId == characteristic.uuid.uuidStr && future.serviceId == characteristic.service?.uuid.uuidStr {
|
||||
if error != nil {
|
||||
future.result(Result.failure(FlutterError(code: "WriteFailed", message: String(describing: error), details: nil)))
|
||||
} else {
|
||||
future.result(Result.success({}()))
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
public func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
|
||||
// Update callbackChannel if notifying
|
||||
if characteristic.isNotifying {
|
||||
if let characteristicValue = characteristic.value {
|
||||
callbackChannel.onValueChanged(deviceId: peripheral.uuid.uuidString, characteristicId: characteristic.uuid.uuidStr, value: FlutterStandardTypedData(bytes: characteristicValue)) { _ in }
|
||||
}
|
||||
}
|
||||
|
||||
if characteristicReadFutures.count == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// Update futures for readValue
|
||||
characteristicReadFutures.removeAll { future in
|
||||
if future.deviceId == peripheral.uuid.uuidString && future.characteristicId == characteristic.uuid.uuidStr && future.serviceId == characteristic.service?.uuid.uuidStr {
|
||||
if error != nil {
|
||||
future.result(Result.failure(FlutterError(code: "ReadFailed", message: String(describing: error), details: nil)))
|
||||
} else {
|
||||
if let characteristicValue = characteristic.value {
|
||||
future.result(Result.success(FlutterStandardTypedData(bytes: characteristicValue)))
|
||||
} else {
|
||||
future.result(Result.failure(FlutterError(code: "ReadFailed", message: "No value", details: nil)))
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
func getPeripheral() throws -> CBPeripheral {
|
||||
guard let peripheral = discoveredPeripherals[self] else {
|
||||
throw FlutterError(code: "IllegalArgument", message: "Unknown deviceId:\(self)", details: nil)
|
||||
}
|
||||
return peripheral
|
||||
}
|
||||
}
|
||||
|
||||
extension FlutterError: Error {}
|
||||
@@ -0,0 +1,25 @@
|
||||
#
|
||||
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
|
||||
# Run `pod lib lint universal_ble.podspec` to validate before publishing.
|
||||
#
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'universal_ble'
|
||||
s.version = '0.0.1'
|
||||
s.summary = 'A new Flutter plugin project.'
|
||||
s.description = <<-DESC
|
||||
A new Flutter plugin project.
|
||||
DESC
|
||||
s.homepage = 'http://example.com'
|
||||
s.license = { :file => '../LICENSE' }
|
||||
s.author = { 'Your Company' => 'email@example.com' }
|
||||
s.source = { :path => '.' }
|
||||
s.source_files = 'Classes/**/*'
|
||||
s.ios.dependency 'Flutter'
|
||||
s.osx.dependency 'FlutterMacOS'
|
||||
s.ios.deployment_target = '9.0'
|
||||
s.osx.deployment_target = '10.12'
|
||||
|
||||
# Flutter.framework does not contain a i386 slice.
|
||||
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }
|
||||
s.swift_version = '5.0'
|
||||
end
|
||||
Reference in New Issue
Block a user