@capacitor-community/bluetooth-le 8.0.1 → 8.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CapacitorCommunityBluetoothLe.podspec +17 -17
- package/LICENSE +21 -21
- package/Package.swift +27 -27
- package/README.md +2 -1
- package/android/build.gradle +73 -73
- package/android/src/main/AndroidManifest.xml +22 -22
- package/android/src/main/java/com/capacitorjs/community/plugins/bluetoothle/BluetoothLe.kt +1094 -1094
- package/android/src/main/java/com/capacitorjs/community/plugins/bluetoothle/Conversion.kt +51 -51
- package/android/src/main/java/com/capacitorjs/community/plugins/bluetoothle/Device.kt +771 -771
- package/android/src/main/java/com/capacitorjs/community/plugins/bluetoothle/DeviceList.kt +28 -28
- package/android/src/main/java/com/capacitorjs/community/plugins/bluetoothle/DeviceScanner.kt +189 -189
- package/dist/docs.json +43 -43
- package/dist/esm/bleClient.d.ts +278 -278
- package/dist/esm/bleClient.js +361 -361
- package/dist/esm/bleClient.js.map +1 -1
- package/dist/esm/config.d.ts +53 -53
- package/dist/esm/config.js +2 -2
- package/dist/esm/conversion.d.ts +56 -56
- package/dist/esm/conversion.js +134 -134
- package/dist/esm/conversion.js.map +1 -1
- package/dist/esm/definitions.d.ts +352 -352
- package/dist/esm/definitions.js +42 -42
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/index.d.ts +5 -5
- package/dist/esm/index.js +5 -5
- package/dist/esm/plugin.d.ts +2 -2
- package/dist/esm/plugin.js +4 -4
- package/dist/esm/queue.d.ts +3 -3
- package/dist/esm/queue.js +17 -17
- package/dist/esm/timeout.d.ts +1 -1
- package/dist/esm/timeout.js +9 -9
- package/dist/esm/validators.d.ts +1 -1
- package/dist/esm/validators.js +11 -11
- package/dist/esm/web.d.ts +57 -57
- package/dist/esm/web.js +403 -403
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +964 -964
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +964 -964
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/BluetoothLe/Conversion.swift +83 -83
- package/ios/Sources/BluetoothLe/Device.swift +422 -423
- package/ios/Sources/BluetoothLe/DeviceListView.swift +121 -121
- package/ios/Sources/BluetoothLe/DeviceManager.swift +409 -415
- package/ios/Sources/BluetoothLe/Logging.swift +8 -8
- package/ios/Sources/BluetoothLe/Plugin.swift +768 -763
- package/ios/Sources/BluetoothLe/ScanFilters.swift +114 -114
- package/ios/Sources/BluetoothLe/ThreadSafeDictionary.swift +61 -15
- package/ios/Tests/BluetoothLeTests/ConversionTests.swift +55 -55
- package/ios/Tests/BluetoothLeTests/PluginTests.swift +27 -27
- package/ios/Tests/BluetoothLeTests/ScanFiltersTests.swift +153 -153
- package/package.json +114 -114
|
@@ -1,114 +1,114 @@
|
|
|
1
|
-
import Foundation
|
|
2
|
-
import CoreBluetooth
|
|
3
|
-
|
|
4
|
-
struct ManufacturerDataFilter {
|
|
5
|
-
let companyIdentifier: UInt16
|
|
6
|
-
let dataPrefix: Data?
|
|
7
|
-
let mask: Data?
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
struct ServiceDataFilter {
|
|
11
|
-
let serviceUuid: CBUUID
|
|
12
|
-
let dataPrefix: Data?
|
|
13
|
-
let mask: Data?
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
class ScanFilterUtils {
|
|
17
|
-
|
|
18
|
-
static func passesManufacturerDataFilter(_ advertisementData: [String: Any], filters: [ManufacturerDataFilter]?) -> Bool {
|
|
19
|
-
guard let filters = filters, !filters.isEmpty else {
|
|
20
|
-
return true // No filters means everything passes
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
guard let manufacturerData = advertisementData[CBAdvertisementDataManufacturerDataKey] as? Data,
|
|
24
|
-
manufacturerData.count >= 2 else {
|
|
25
|
-
return false // If there's no valid manufacturer data, fail
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
let companyIdentifier = manufacturerData.prefix(2).withUnsafeBytes {
|
|
29
|
-
$0.load(as: UInt16.self).littleEndian // Manufacturer ID is little-endian
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
let payload = Data(manufacturerData.dropFirst(2))
|
|
33
|
-
|
|
34
|
-
for filter in filters {
|
|
35
|
-
if filter.companyIdentifier != companyIdentifier {
|
|
36
|
-
continue // Skip if company ID does not match
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if let dataPrefix = filter.dataPrefix {
|
|
40
|
-
if payload.count < dataPrefix.count {
|
|
41
|
-
continue // Payload too short, does not match
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if let mask = filter.mask {
|
|
45
|
-
// Validate that mask length matches dataPrefix length
|
|
46
|
-
if mask.count != dataPrefix.count {
|
|
47
|
-
continue // Skip this filter if mask length is invalid
|
|
48
|
-
}
|
|
49
|
-
var matches = true
|
|
50
|
-
for i in 0..<dataPrefix.count {
|
|
51
|
-
if (payload[i] & mask[i]) != (dataPrefix[i] & mask[i]) {
|
|
52
|
-
matches = false
|
|
53
|
-
break
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
if matches {
|
|
57
|
-
return true
|
|
58
|
-
}
|
|
59
|
-
} else if payload.starts(with: dataPrefix) {
|
|
60
|
-
return true
|
|
61
|
-
}
|
|
62
|
-
} else {
|
|
63
|
-
return true // Company ID matched, and no dataPrefix required
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return false // If none matched, return false
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
static func passesServiceDataFilter(_ advertisementData: [String: Any], filters: [ServiceDataFilter]?) -> Bool {
|
|
71
|
-
guard let filters = filters, !filters.isEmpty else {
|
|
72
|
-
return true // No filters means everything passes
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
guard let serviceDataDict = advertisementData[CBAdvertisementDataServiceDataKey] as? [CBUUID: Data] else {
|
|
76
|
-
return false // If there's no service data, fail
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
for filter in filters {
|
|
80
|
-
guard let serviceData = serviceDataDict[filter.serviceUuid] else {
|
|
81
|
-
continue // Skip if service UUID does not match
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if let dataPrefix = filter.dataPrefix {
|
|
85
|
-
if serviceData.count < dataPrefix.count {
|
|
86
|
-
continue // Service data too short, does not match
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if let mask = filter.mask {
|
|
90
|
-
// Validate that mask length matches dataPrefix length
|
|
91
|
-
if mask.count != dataPrefix.count {
|
|
92
|
-
continue // Skip this filter if mask length is invalid
|
|
93
|
-
}
|
|
94
|
-
var matches = true
|
|
95
|
-
for i in 0..<dataPrefix.count {
|
|
96
|
-
if (serviceData[i] & mask[i]) != (dataPrefix[i] & mask[i]) {
|
|
97
|
-
matches = false
|
|
98
|
-
break
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
if matches {
|
|
102
|
-
return true
|
|
103
|
-
}
|
|
104
|
-
} else if serviceData.starts(with: dataPrefix) {
|
|
105
|
-
return true
|
|
106
|
-
}
|
|
107
|
-
} else {
|
|
108
|
-
return true // Service UUID matched, and no dataPrefix required
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return false // If none matched, return false
|
|
113
|
-
}
|
|
114
|
-
}
|
|
1
|
+
import Foundation
|
|
2
|
+
import CoreBluetooth
|
|
3
|
+
|
|
4
|
+
struct ManufacturerDataFilter {
|
|
5
|
+
let companyIdentifier: UInt16
|
|
6
|
+
let dataPrefix: Data?
|
|
7
|
+
let mask: Data?
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
struct ServiceDataFilter {
|
|
11
|
+
let serviceUuid: CBUUID
|
|
12
|
+
let dataPrefix: Data?
|
|
13
|
+
let mask: Data?
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
class ScanFilterUtils {
|
|
17
|
+
|
|
18
|
+
static func passesManufacturerDataFilter(_ advertisementData: [String: Any], filters: [ManufacturerDataFilter]?) -> Bool {
|
|
19
|
+
guard let filters = filters, !filters.isEmpty else {
|
|
20
|
+
return true // No filters means everything passes
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
guard let manufacturerData = advertisementData[CBAdvertisementDataManufacturerDataKey] as? Data,
|
|
24
|
+
manufacturerData.count >= 2 else {
|
|
25
|
+
return false // If there's no valid manufacturer data, fail
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let companyIdentifier = manufacturerData.prefix(2).withUnsafeBytes {
|
|
29
|
+
$0.load(as: UInt16.self).littleEndian // Manufacturer ID is little-endian
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let payload = Data(manufacturerData.dropFirst(2))
|
|
33
|
+
|
|
34
|
+
for filter in filters {
|
|
35
|
+
if filter.companyIdentifier != companyIdentifier {
|
|
36
|
+
continue // Skip if company ID does not match
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if let dataPrefix = filter.dataPrefix {
|
|
40
|
+
if payload.count < dataPrefix.count {
|
|
41
|
+
continue // Payload too short, does not match
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if let mask = filter.mask {
|
|
45
|
+
// Validate that mask length matches dataPrefix length
|
|
46
|
+
if mask.count != dataPrefix.count {
|
|
47
|
+
continue // Skip this filter if mask length is invalid
|
|
48
|
+
}
|
|
49
|
+
var matches = true
|
|
50
|
+
for i in 0..<dataPrefix.count {
|
|
51
|
+
if (payload[i] & mask[i]) != (dataPrefix[i] & mask[i]) {
|
|
52
|
+
matches = false
|
|
53
|
+
break
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if matches {
|
|
57
|
+
return true
|
|
58
|
+
}
|
|
59
|
+
} else if payload.starts(with: dataPrefix) {
|
|
60
|
+
return true
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
return true // Company ID matched, and no dataPrefix required
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return false // If none matched, return false
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
static func passesServiceDataFilter(_ advertisementData: [String: Any], filters: [ServiceDataFilter]?) -> Bool {
|
|
71
|
+
guard let filters = filters, !filters.isEmpty else {
|
|
72
|
+
return true // No filters means everything passes
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
guard let serviceDataDict = advertisementData[CBAdvertisementDataServiceDataKey] as? [CBUUID: Data] else {
|
|
76
|
+
return false // If there's no service data, fail
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
for filter in filters {
|
|
80
|
+
guard let serviceData = serviceDataDict[filter.serviceUuid] else {
|
|
81
|
+
continue // Skip if service UUID does not match
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if let dataPrefix = filter.dataPrefix {
|
|
85
|
+
if serviceData.count < dataPrefix.count {
|
|
86
|
+
continue // Service data too short, does not match
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if let mask = filter.mask {
|
|
90
|
+
// Validate that mask length matches dataPrefix length
|
|
91
|
+
if mask.count != dataPrefix.count {
|
|
92
|
+
continue // Skip this filter if mask length is invalid
|
|
93
|
+
}
|
|
94
|
+
var matches = true
|
|
95
|
+
for i in 0..<dataPrefix.count {
|
|
96
|
+
if (serviceData[i] & mask[i]) != (dataPrefix[i] & mask[i]) {
|
|
97
|
+
matches = false
|
|
98
|
+
break
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if matches {
|
|
102
|
+
return true
|
|
103
|
+
}
|
|
104
|
+
} else if serviceData.starts(with: dataPrefix) {
|
|
105
|
+
return true
|
|
106
|
+
}
|
|
107
|
+
} else {
|
|
108
|
+
return true // Service UUID matched, and no dataPrefix required
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return false // If none matched, return false
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -1,15 +1,61 @@
|
|
|
1
|
-
import Foundation
|
|
2
|
-
|
|
3
|
-
class ThreadSafeDictionary<K: Hashable, T> {
|
|
4
|
-
private var dictionary: [K: T] = [:]
|
|
5
|
-
private let queue = DispatchQueue(label: "threadSafeDictionaryQueue", attributes: .concurrent)
|
|
6
|
-
|
|
7
|
-
subscript(key: K) -> T? {
|
|
8
|
-
get {
|
|
9
|
-
return queue.sync { dictionary[key] }
|
|
10
|
-
}
|
|
11
|
-
set {
|
|
12
|
-
queue.async(flags: .barrier) { self.dictionary[key] = newValue }
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
class ThreadSafeDictionary<K: Hashable, T> {
|
|
4
|
+
private var dictionary: [K: T] = [:]
|
|
5
|
+
private let queue = DispatchQueue(label: "threadSafeDictionaryQueue", attributes: .concurrent)
|
|
6
|
+
|
|
7
|
+
subscript(key: K) -> T? {
|
|
8
|
+
get {
|
|
9
|
+
return queue.sync { dictionary[key] }
|
|
10
|
+
}
|
|
11
|
+
set {
|
|
12
|
+
queue.async(flags: .barrier) { self.dictionary[key] = newValue }
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
func removeValue(forKey key: K) -> T? {
|
|
17
|
+
return queue.sync(flags: .barrier) {
|
|
18
|
+
return dictionary.removeValue(forKey: key)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
var count: Int {
|
|
23
|
+
return queue.sync { dictionary.count }
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
func removeAll() {
|
|
27
|
+
queue.async(flags: .barrier) {
|
|
28
|
+
self.dictionary.removeAll()
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/// Atomically gets existing value or inserts and returns new value
|
|
33
|
+
/// The create closure is only called if the key doesn't exist
|
|
34
|
+
/// Returns tuple of (value, wasInserted) where wasInserted indicates if a new value was created
|
|
35
|
+
func getOrInsert(key: K, create: () -> T) -> (value: T, wasInserted: Bool) {
|
|
36
|
+
return queue.sync(flags: .barrier) {
|
|
37
|
+
if let existing = dictionary[key] {
|
|
38
|
+
return (existing, false)
|
|
39
|
+
}
|
|
40
|
+
let newValue = create()
|
|
41
|
+
dictionary[key] = newValue
|
|
42
|
+
return (newValue, true)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/// Atomically gets existing value (calling update on it) or inserts new value
|
|
47
|
+
/// The create closure is only called if the key doesn't exist
|
|
48
|
+
/// The update closure is called on existing values before returning
|
|
49
|
+
/// Returns tuple of (value, wasInserted) where wasInserted indicates if a new value was created
|
|
50
|
+
func getOrInsert(key: K, create: () -> T, update: (T) -> Void) -> (value: T, wasInserted: Bool) {
|
|
51
|
+
return queue.sync(flags: .barrier) {
|
|
52
|
+
if let existing = dictionary[key] {
|
|
53
|
+
update(existing)
|
|
54
|
+
return (existing, false)
|
|
55
|
+
}
|
|
56
|
+
let newValue = create()
|
|
57
|
+
dictionary[key] = newValue
|
|
58
|
+
return (newValue, true)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -1,55 +1,55 @@
|
|
|
1
|
-
import Foundation
|
|
2
|
-
import CoreBluetooth
|
|
3
|
-
import XCTest
|
|
4
|
-
@testable import BluetoothLe
|
|
5
|
-
|
|
6
|
-
class ConversionTests: XCTestCase {
|
|
7
|
-
|
|
8
|
-
func testDataToString() throws {
|
|
9
|
-
let input = Data([0xA1, 0x2E, 0x38, 0xD4, 0x89, 0xC3])
|
|
10
|
-
let output = dataToString(input)
|
|
11
|
-
XCTAssertEqual(output, "a12e38d489c3")
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
func testStringToData() throws {
|
|
15
|
-
let input = "a12e38d489c3"
|
|
16
|
-
let output = stringToData(input)
|
|
17
|
-
let expected = Data([0xA1, 0x2E, 0x38, 0xD4, 0x89, 0xC3])
|
|
18
|
-
for (index, byte) in output.enumerated() {
|
|
19
|
-
XCTAssertEqual(byte, expected[index])
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
func testEmptyStringToData() throws {
|
|
24
|
-
let input = ""
|
|
25
|
-
let output = stringToData(input)
|
|
26
|
-
XCTAssertEqual(output, Data([]))
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
func testCbuuidToString() throws {
|
|
30
|
-
XCTAssertEqual(cbuuidToString(CBUUID(string: "180D")), "0000180d-0000-1000-8000-00805f9b34fb")
|
|
31
|
-
XCTAssertEqual(cbuuidToString(CBUUID(string: "AAAA180D")), "aaaa180d-0000-1000-8000-00805f9b34fb")
|
|
32
|
-
XCTAssertEqual(cbuuidToString(CBUUID(string: "fb005c80-02e7-f387-1cad-8acd2d8df0c8")), "fb005c80-02e7-f387-1cad-8acd2d8df0c8")
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
func testCbuuidToStringUppercase() throws {
|
|
36
|
-
XCTAssertEqual(cbuuidToStringUppercase(CBUUID(string: "180D")), "0000180D-0000-1000-8000-00805F9B34FB")
|
|
37
|
-
XCTAssertEqual(cbuuidToStringUppercase(CBUUID(string: "fb005c80-02e7-f387-1cad-8acd2d8df0c8")), "FB005C80-02E7-F387-1CAD-8ACD2D8DF0C8")
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
func testOptionalStringConversion() throws {
|
|
41
|
-
let str: String? = "180D"
|
|
42
|
-
XCTAssertEqual("\(str)", "Optional(\"180D\")")
|
|
43
|
-
XCTAssertEqual("\(str!)", "180D")
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
func testDescriptorValueToString() throws {
|
|
47
|
-
XCTAssertEqual(descriptorValueToString("Hello"), "48656c6c6f")
|
|
48
|
-
XCTAssertEqual(descriptorValueToString(Data([0, 5, 255])), "0005ff")
|
|
49
|
-
XCTAssertEqual(descriptorValueToString(UInt16(258)), "0201")
|
|
50
|
-
XCTAssertEqual(descriptorValueToString(UInt16(1)), "0100")
|
|
51
|
-
XCTAssertEqual(descriptorValueToString(NSNumber(1)), "0100")
|
|
52
|
-
XCTAssertEqual(descriptorValueToString(0), "")
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
}
|
|
1
|
+
import Foundation
|
|
2
|
+
import CoreBluetooth
|
|
3
|
+
import XCTest
|
|
4
|
+
@testable import BluetoothLe
|
|
5
|
+
|
|
6
|
+
class ConversionTests: XCTestCase {
|
|
7
|
+
|
|
8
|
+
func testDataToString() throws {
|
|
9
|
+
let input = Data([0xA1, 0x2E, 0x38, 0xD4, 0x89, 0xC3])
|
|
10
|
+
let output = dataToString(input)
|
|
11
|
+
XCTAssertEqual(output, "a12e38d489c3")
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
func testStringToData() throws {
|
|
15
|
+
let input = "a12e38d489c3"
|
|
16
|
+
let output = stringToData(input)
|
|
17
|
+
let expected = Data([0xA1, 0x2E, 0x38, 0xD4, 0x89, 0xC3])
|
|
18
|
+
for (index, byte) in output.enumerated() {
|
|
19
|
+
XCTAssertEqual(byte, expected[index])
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
func testEmptyStringToData() throws {
|
|
24
|
+
let input = ""
|
|
25
|
+
let output = stringToData(input)
|
|
26
|
+
XCTAssertEqual(output, Data([]))
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
func testCbuuidToString() throws {
|
|
30
|
+
XCTAssertEqual(cbuuidToString(CBUUID(string: "180D")), "0000180d-0000-1000-8000-00805f9b34fb")
|
|
31
|
+
XCTAssertEqual(cbuuidToString(CBUUID(string: "AAAA180D")), "aaaa180d-0000-1000-8000-00805f9b34fb")
|
|
32
|
+
XCTAssertEqual(cbuuidToString(CBUUID(string: "fb005c80-02e7-f387-1cad-8acd2d8df0c8")), "fb005c80-02e7-f387-1cad-8acd2d8df0c8")
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
func testCbuuidToStringUppercase() throws {
|
|
36
|
+
XCTAssertEqual(cbuuidToStringUppercase(CBUUID(string: "180D")), "0000180D-0000-1000-8000-00805F9B34FB")
|
|
37
|
+
XCTAssertEqual(cbuuidToStringUppercase(CBUUID(string: "fb005c80-02e7-f387-1cad-8acd2d8df0c8")), "FB005C80-02E7-F387-1CAD-8ACD2D8DF0C8")
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
func testOptionalStringConversion() throws {
|
|
41
|
+
let str: String? = "180D"
|
|
42
|
+
XCTAssertEqual("\(str)", "Optional(\"180D\")")
|
|
43
|
+
XCTAssertEqual("\(str!)", "180D")
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
func testDescriptorValueToString() throws {
|
|
47
|
+
XCTAssertEqual(descriptorValueToString("Hello"), "48656c6c6f")
|
|
48
|
+
XCTAssertEqual(descriptorValueToString(Data([0, 5, 255])), "0005ff")
|
|
49
|
+
XCTAssertEqual(descriptorValueToString(UInt16(258)), "0201")
|
|
50
|
+
XCTAssertEqual(descriptorValueToString(UInt16(1)), "0100")
|
|
51
|
+
XCTAssertEqual(descriptorValueToString(NSNumber(1)), "0100")
|
|
52
|
+
XCTAssertEqual(descriptorValueToString(0), "")
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
}
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import XCTest
|
|
2
|
-
import Capacitor
|
|
3
|
-
@testable import BluetoothLe
|
|
4
|
-
|
|
5
|
-
class PluginTests: XCTestCase {
|
|
6
|
-
|
|
7
|
-
func testEcho() {
|
|
8
|
-
// This is an example of a functional test case for a plugin.
|
|
9
|
-
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
|
10
|
-
|
|
11
|
-
let value = "Hello, World!"
|
|
12
|
-
XCTAssertEqual(1, 1)
|
|
13
|
-
|
|
14
|
-
// let plugin = MyPlugin()
|
|
15
|
-
//
|
|
16
|
-
// let call = CAPPluginCall(callbackId: "test", options: [
|
|
17
|
-
// "value": value
|
|
18
|
-
// ], success: { (result, _) in
|
|
19
|
-
// let resultValue = result!.data["value"] as? String
|
|
20
|
-
// XCTAssertEqual(value, resultValue)
|
|
21
|
-
// }, error: { (_) in
|
|
22
|
-
// XCTFail("Error shouldn't have been called")
|
|
23
|
-
// })
|
|
24
|
-
//
|
|
25
|
-
// plugin.echo(call!)
|
|
26
|
-
}
|
|
27
|
-
}
|
|
1
|
+
import XCTest
|
|
2
|
+
import Capacitor
|
|
3
|
+
@testable import BluetoothLe
|
|
4
|
+
|
|
5
|
+
class PluginTests: XCTestCase {
|
|
6
|
+
|
|
7
|
+
func testEcho() {
|
|
8
|
+
// This is an example of a functional test case for a plugin.
|
|
9
|
+
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
|
10
|
+
|
|
11
|
+
let value = "Hello, World!"
|
|
12
|
+
XCTAssertEqual(1, 1)
|
|
13
|
+
|
|
14
|
+
// let plugin = MyPlugin()
|
|
15
|
+
//
|
|
16
|
+
// let call = CAPPluginCall(callbackId: "test", options: [
|
|
17
|
+
// "value": value
|
|
18
|
+
// ], success: { (result, _) in
|
|
19
|
+
// let resultValue = result!.data["value"] as? String
|
|
20
|
+
// XCTAssertEqual(value, resultValue)
|
|
21
|
+
// }, error: { (_) in
|
|
22
|
+
// XCTFail("Error shouldn't have been called")
|
|
23
|
+
// })
|
|
24
|
+
//
|
|
25
|
+
// plugin.echo(call!)
|
|
26
|
+
}
|
|
27
|
+
}
|