@wisdomgarden/capacitor-plugin-beacon 0.0.1

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.
Files changed (84) hide show
  1. package/README.md +117 -0
  2. package/WisdomgardenCapacitorPluginBeacon.podspec +17 -0
  3. package/android/build.gradle +52 -0
  4. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  5. package/android/gradle/wrapper/gradle-wrapper.properties +5 -0
  6. package/android/gradle.properties +24 -0
  7. package/android/gradlew +188 -0
  8. package/android/gradlew.bat +100 -0
  9. package/android/proguard-rules.pro +21 -0
  10. package/android/settings.gradle +2 -0
  11. package/android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java +26 -0
  12. package/android/src/main/AndroidManifest.xml +20 -0
  13. package/android/src/main/java/com/wisdomgarden/mobile/beacon/Beacon.java +294 -0
  14. package/android/src/main/java/com/wisdomgarden/mobile/beacon/BeaconUtils.java +118 -0
  15. package/android/src/main/res/layout/bridge_layout_main.xml +15 -0
  16. package/android/src/main/res/values/colors.xml +3 -0
  17. package/android/src/main/res/values/strings.xml +3 -0
  18. package/android/src/main/res/values/styles.xml +3 -0
  19. package/android/src/test/java/com/getcapacitor/ExampleUnitTest.java +18 -0
  20. package/dist/esm/definitions.d.ts +49 -0
  21. package/dist/esm/definitions.js +2 -0
  22. package/dist/esm/definitions.js.map +1 -0
  23. package/dist/esm/index.d.ts +2 -0
  24. package/dist/esm/index.js +3 -0
  25. package/dist/esm/index.js.map +1 -0
  26. package/dist/esm/web.d.ts +25 -0
  27. package/dist/esm/web.js +61 -0
  28. package/dist/esm/web.js.map +1 -0
  29. package/dist/plugin.js +70 -0
  30. package/dist/plugin.js.map +1 -0
  31. package/ios/Plugin/BeaconUtils.swift +103 -0
  32. package/ios/Plugin/Info.plist +30 -0
  33. package/ios/Plugin/Plugin.h +10 -0
  34. package/ios/Plugin/Plugin.m +14 -0
  35. package/ios/Plugin/Plugin.swift +342 -0
  36. package/ios/Plugin.xcodeproj/project.pbxproj +556 -0
  37. package/ios/Plugin.xcodeproj/xcuserdata/peixinliu.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
  38. package/ios/Plugin.xcworkspace/contents.xcworkspacedata +10 -0
  39. package/ios/Plugin.xcworkspace/xcuserdata/peixinliu.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  40. package/ios/PluginTests/Info.plist +22 -0
  41. package/ios/PluginTests/PluginTests.swift +35 -0
  42. package/ios/Podfile +16 -0
  43. package/ios/Podfile.lock +22 -0
  44. package/ios/Pods/Local Podspecs/Capacitor.podspec.json +30 -0
  45. package/ios/Pods/Local Podspecs/CapacitorCordova.podspec.json +22 -0
  46. package/ios/Pods/Manifest.lock +22 -0
  47. package/ios/Pods/Pods.xcodeproj/project.pbxproj +1381 -0
  48. package/ios/Pods/Pods.xcodeproj/xcuserdata/peixinliu.xcuserdatad/xcschemes/Capacitor.xcscheme +58 -0
  49. package/ios/Pods/Pods.xcodeproj/xcuserdata/peixinliu.xcuserdatad/xcschemes/CapacitorCordova.xcscheme +58 -0
  50. package/ios/Pods/Pods.xcodeproj/xcuserdata/peixinliu.xcuserdatad/xcschemes/Pods-Plugin.xcscheme +58 -0
  51. package/ios/Pods/Pods.xcodeproj/xcuserdata/peixinliu.xcuserdatad/xcschemes/Pods-PluginTests.xcscheme +58 -0
  52. package/ios/Pods/Pods.xcodeproj/xcuserdata/peixinliu.xcuserdatad/xcschemes/xcschememanagement.plist +39 -0
  53. package/ios/Pods/Target Support Files/Capacitor/Capacitor-Info.plist +26 -0
  54. package/ios/Pods/Target Support Files/Capacitor/Capacitor-dummy.m +5 -0
  55. package/ios/Pods/Target Support Files/Capacitor/Capacitor-prefix.pch +12 -0
  56. package/ios/Pods/Target Support Files/Capacitor/Capacitor-umbrella.h +23 -0
  57. package/ios/Pods/Target Support Files/Capacitor/Capacitor.debug.xcconfig +16 -0
  58. package/ios/Pods/Target Support Files/Capacitor/Capacitor.modulemap +6 -0
  59. package/ios/Pods/Target Support Files/Capacitor/Capacitor.release.xcconfig +16 -0
  60. package/ios/Pods/Target Support Files/CapacitorCordova/CapacitorCordova-Info.plist +26 -0
  61. package/ios/Pods/Target Support Files/CapacitorCordova/CapacitorCordova-dummy.m +5 -0
  62. package/ios/Pods/Target Support Files/CapacitorCordova/CapacitorCordova-prefix.pch +12 -0
  63. package/ios/Pods/Target Support Files/CapacitorCordova/CapacitorCordova-umbrella.h +33 -0
  64. package/ios/Pods/Target Support Files/CapacitorCordova/CapacitorCordova.debug.xcconfig +13 -0
  65. package/ios/Pods/Target Support Files/CapacitorCordova/CapacitorCordova.modulemap +6 -0
  66. package/ios/Pods/Target Support Files/CapacitorCordova/CapacitorCordova.release.xcconfig +13 -0
  67. package/ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin-Info.plist +26 -0
  68. package/ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin-acknowledgements.markdown +3 -0
  69. package/ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin-acknowledgements.plist +29 -0
  70. package/ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin-dummy.m +5 -0
  71. package/ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin-umbrella.h +16 -0
  72. package/ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin.debug.xcconfig +14 -0
  73. package/ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin.modulemap +6 -0
  74. package/ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin.release.xcconfig +14 -0
  75. package/ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests-Info.plist +26 -0
  76. package/ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests-acknowledgements.markdown +3 -0
  77. package/ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests-acknowledgements.plist +29 -0
  78. package/ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests-dummy.m +5 -0
  79. package/ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests-frameworks.sh +188 -0
  80. package/ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests-umbrella.h +16 -0
  81. package/ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests.debug.xcconfig +15 -0
  82. package/ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests.modulemap +6 -0
  83. package/ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests.release.xcconfig +15 -0
  84. package/package.json +64 -0
package/dist/plugin.js ADDED
@@ -0,0 +1,70 @@
1
+ var capacitorPlugin = (function (exports, core) {
2
+ 'use strict';
3
+
4
+ var __awaiter = (window && window.__awaiter) || function (thisArg, _arguments, P, generator) {
5
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
6
+ return new (P || (P = Promise))(function (resolve, reject) {
7
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
8
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
9
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
10
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
11
+ });
12
+ };
13
+ class BeaconWeb extends core.WebPlugin {
14
+ constructor() {
15
+ super({
16
+ name: 'Beacon',
17
+ platforms: ['web'],
18
+ });
19
+ }
20
+ initialize(_options) {
21
+ return __awaiter(this, void 0, void 0, function* () {
22
+ //
23
+ });
24
+ }
25
+ startBroadcasting(_options) {
26
+ return __awaiter(this, void 0, void 0, function* () {
27
+ //
28
+ });
29
+ }
30
+ stopBroadcasting() {
31
+ return __awaiter(this, void 0, void 0, function* () {
32
+ //
33
+ });
34
+ }
35
+ startMonitoring() {
36
+ return __awaiter(this, void 0, void 0, function* () {
37
+ //
38
+ });
39
+ }
40
+ stopMonitoring() {
41
+ return __awaiter(this, void 0, void 0, function* () {
42
+ //
43
+ });
44
+ }
45
+ cleanup() {
46
+ return __awaiter(this, void 0, void 0, function* () {
47
+ //
48
+ });
49
+ }
50
+ parseMessage(_options) {
51
+ return __awaiter(this, void 0, void 0, function* () {
52
+ return {
53
+ rollcallId: 0,
54
+ nonce: '',
55
+ };
56
+ });
57
+ }
58
+ }
59
+ const Beacon = new BeaconWeb();
60
+ core.registerWebPlugin(Beacon);
61
+
62
+ exports.Beacon = Beacon;
63
+ exports.BeaconWeb = BeaconWeb;
64
+
65
+ Object.defineProperty(exports, '__esModule', { value: true });
66
+
67
+ return exports;
68
+
69
+ })({}, capacitorExports);
70
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sources":["esm/web.js"],"sourcesContent":["var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nimport { WebPlugin } from '@capacitor/core';\nexport class BeaconWeb extends WebPlugin {\n constructor() {\n super({\n name: 'Beacon',\n platforms: ['web'],\n });\n }\n initialize(_options) {\n return __awaiter(this, void 0, void 0, function* () {\n //\n });\n }\n startBroadcasting(_options) {\n return __awaiter(this, void 0, void 0, function* () {\n //\n });\n }\n stopBroadcasting() {\n return __awaiter(this, void 0, void 0, function* () {\n //\n });\n }\n startMonitoring() {\n return __awaiter(this, void 0, void 0, function* () {\n //\n });\n }\n stopMonitoring() {\n return __awaiter(this, void 0, void 0, function* () {\n //\n });\n }\n cleanup() {\n return __awaiter(this, void 0, void 0, function* () {\n //\n });\n }\n parseMessage(_options) {\n return __awaiter(this, void 0, void 0, function* () {\n return {\n rollcallId: 0,\n nonce: '',\n };\n });\n }\n}\nconst Beacon = new BeaconWeb();\nexport { Beacon };\nimport { registerWebPlugin } from '@capacitor/core';\nregisterWebPlugin(Beacon);\n//# sourceMappingURL=web.js.map"],"names":["this","WebPlugin","registerWebPlugin"],"mappings":"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"}
@@ -0,0 +1,103 @@
1
+ import Foundation
2
+
3
+ public struct BeaconUtils {
4
+ public static let WG_UUID = "1ed18c59-a7cc-4752-96b0-51d77a456584"
5
+ public static let message_max_length = 11
6
+
7
+ private static let chars =
8
+ "2O9AuFNPDx4gtJwS3ye7l1Mq0dEB5HsaKInikRmLhjpG6b8fzQrCcvo"
9
+ private static let radix = chars.count
10
+
11
+ public static func encode(_ num: Int) -> String {
12
+ if num == 0 { return String(chars[chars.startIndex]) }
13
+ var result = ""
14
+ let isNegative = num < 0
15
+ var n = abs(num)
16
+
17
+ while n > 0 {
18
+ let remainder = n % radix
19
+ let char = chars[chars.index(chars.startIndex, offsetBy: remainder)]
20
+ result = String(char) + result
21
+ n /= radix
22
+ }
23
+
24
+ return isNegative ? "-" + result : result
25
+ }
26
+
27
+ public static func decode(_ str: String) -> Int {
28
+ var num = 0
29
+ for char in str {
30
+ if let index = chars.firstIndex(of: char) {
31
+ num =
32
+ num * radix
33
+ + chars.distance(from: chars.startIndex, to: index)
34
+ } else {
35
+ return 0
36
+ }
37
+ }
38
+ return num
39
+ }
40
+
41
+ public static func parseMessage(_ message: String?) -> [String: Any] {
42
+ var payload: [String: Any] = [
43
+ "rollcallId": 0,
44
+ "nonce": "",
45
+ ]
46
+
47
+ guard let message = message else {
48
+ return payload
49
+ }
50
+
51
+ if message.count < message_max_length {
52
+ return payload
53
+ }
54
+
55
+ // 检查字符是否为 nonce 字母,T-Z
56
+ func isNonceLetter(_ c: Character) -> Bool {
57
+ let code = c.asciiValue ?? 0
58
+ return code >= 84 && code <= 90
59
+ }
60
+
61
+ for (i, char) in message.enumerated() {
62
+ if isNonceLetter(char) {
63
+ let rollcallIdStr = String(
64
+ message[
65
+ ..<message.index(
66
+ message.startIndex,
67
+ offsetBy: i
68
+ )
69
+ ]
70
+ )
71
+ payload["rollcallId"] = decode(rollcallIdStr)
72
+
73
+ let nonceStr = String(
74
+ message[
75
+ message.index(
76
+ message.startIndex,
77
+ offsetBy: i
78
+ )...
79
+ ]
80
+ )
81
+ payload["nonce"] = nonceStr
82
+ break
83
+ }
84
+ }
85
+
86
+ return payload
87
+ }
88
+
89
+ // 如果rollcallid 过长,挤占了 message 的长度,导致数据不全,可能会出错,这个数量级需要 id 都在千万级别,一般达不到
90
+ public static func buildMessage(rollcallId: Int, nonce: String) -> String {
91
+ let rollcallIdStr = encode(rollcallId)
92
+
93
+ guard !nonce.isEmpty, let firstChar = nonce.first else {
94
+ return rollcallIdStr + "Z"
95
+ }
96
+
97
+ let remainingChars = String(nonce.dropFirst())
98
+
99
+ let message = rollcallIdStr + nonce
100
+ return message.count > message_max_length
101
+ ? String(message.prefix(message_max_length)) : message
102
+ }
103
+ }
@@ -0,0 +1,30 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>CFBundleDevelopmentRegion</key>
6
+ <string>$(DEVELOPMENT_LANGUAGE)</string>
7
+ <key>CFBundleExecutable</key>
8
+ <string>$(EXECUTABLE_NAME)</string>
9
+ <key>CFBundleIdentifier</key>
10
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11
+ <key>CFBundleInfoDictionaryVersion</key>
12
+ <string>6.0</string>
13
+ <key>CFBundleName</key>
14
+ <string>$(PRODUCT_NAME)</string>
15
+ <key>CFBundlePackageType</key>
16
+ <string>FMWK</string>
17
+ <key>CFBundleShortVersionString</key>
18
+ <string>1.0</string>
19
+ <key>CFBundleVersion</key>
20
+ <string>$(CURRENT_PROJECT_VERSION)</string>
21
+ <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
22
+ <string>Location permission is required to detect the Beacon.</string>
23
+ <key>NSLocationWhenInUseUsageDescription</key>
24
+ <string>Location permission is required to detect the Beacon.</string>
25
+ <key>NSBluetoothAlwaysUsageDescription</key>
26
+ <string> Bluetooth is needed to broadcast the Beacon signal.</string>
27
+ <key>NSPrincipalClass</key>
28
+ <string></string>
29
+ </dict>
30
+ </plist>
@@ -0,0 +1,10 @@
1
+ #import <UIKit/UIKit.h>
2
+
3
+ //! Project version number for Plugin.
4
+ FOUNDATION_EXPORT double PluginVersionNumber;
5
+
6
+ //! Project version string for Plugin.
7
+ FOUNDATION_EXPORT const unsigned char PluginVersionString[];
8
+
9
+ // In this header, you should import all the public headers of your framework using statements like #import <Plugin/PublicHeader.h>
10
+
@@ -0,0 +1,14 @@
1
+ #import <Capacitor/Capacitor.h>
2
+ #import <Foundation/Foundation.h>
3
+
4
+ // Define the plugin using the CAP_PLUGIN Macro, and
5
+ // each method the plugin supports using the CAP_PLUGIN_METHOD macro.
6
+ CAP_PLUGIN(Beacon, "Beacon",
7
+ CAP_PLUGIN_METHOD(initialize, CAPPluginReturnPromise);
8
+ CAP_PLUGIN_METHOD(startBroadcasting, CAPPluginReturnPromise);
9
+ CAP_PLUGIN_METHOD(stopBroadcasting, CAPPluginReturnPromise);
10
+ CAP_PLUGIN_METHOD(startMonitoring, CAPPluginReturnPromise);
11
+ CAP_PLUGIN_METHOD(stopMonitoring, CAPPluginReturnPromise);
12
+ CAP_PLUGIN_METHOD(cleanup, CAPPluginReturnPromise);
13
+ CAP_PLUGIN_METHOD(parseMessage, CAPPluginReturnPromise);
14
+ )
@@ -0,0 +1,342 @@
1
+ import Capacitor
2
+ import CoreBluetooth
3
+ import CoreLocation
4
+ import Foundation
5
+
6
+ /// Please read the Capacitor iOS Plugin Development Guide
7
+ /// here: https://capacitorjs.com/docs/plugins/ios
8
+ @objc(Beacon)
9
+ public class Beacon: CAPPlugin, CBPeripheralManagerDelegate,
10
+ CBCentralManagerDelegate
11
+ {
12
+ private var peripheralManager: CBPeripheralManager?
13
+ private var centralManager: CBCentralManager?
14
+
15
+ private var isBroadcasting: Bool = false
16
+ private var needBroadcasting: Bool = false
17
+
18
+ private var isMonitoring: Bool = false
19
+ private var needMonitoring: Bool = false
20
+
21
+ private var allowDuplicatesKey = true
22
+
23
+ private var rollcallId = 0
24
+ private var nonce = ""
25
+ private var message = ""
26
+
27
+ @objc func parseMessage(_ call: CAPPluginCall) {
28
+ let message = call.getString("message")
29
+ let result = BeaconUtils.parseMessage(message)
30
+ call.resolve(result)
31
+ }
32
+
33
+ @objc func initialize(_ call: CAPPluginCall) {
34
+ allowDuplicatesKey = call.getBool("allowDuplicatesKey") ?? true
35
+ call.resolve()
36
+ }
37
+
38
+ func startAdvertising() {
39
+ super.bridge.logToJs("[Debug] startAdvertising 12")
40
+ if peripheralManager == nil {
41
+ return
42
+ }
43
+
44
+ if isBroadcasting == true {
45
+ return
46
+ }
47
+ super.bridge.logToJs("[Debug] startAdvertising broadcasting 13")
48
+ isBroadcasting = true
49
+
50
+ let advertisementData: [String: Any] = [
51
+ CBAdvertisementDataServiceUUIDsKey: [CBUUID(string: BeaconUtils.WG_UUID)],
52
+ CBAdvertisementDataLocalNameKey: message,
53
+ ]
54
+
55
+ super.bridge.logToJs("[Debug] startAdvertising broadcasting 14")
56
+ peripheralManager?.startAdvertising(advertisementData)
57
+ super.bridge.logToJs("[Debug] startAdvertising broadcasting 15")
58
+ }
59
+
60
+ @objc func startBroadcasting(_ call: CAPPluginCall) {
61
+ super.bridge.logToJs("[Debug] startBroadcasting 11")
62
+
63
+ if let message = call.getString("message"),
64
+ message.count == BeaconUtils.message_max_length
65
+ {
66
+ self.message = message
67
+ } else {
68
+ guard let rollcallId = call.getInt("rollcallId") else {
69
+ call.reject("rollcallId is required")
70
+ return
71
+ }
72
+ guard let nonce = call.getString("nonce") else {
73
+ call.reject("nonce is required")
74
+ return
75
+ }
76
+
77
+ self.rollcallId = rollcallId
78
+ self.nonce = nonce
79
+
80
+ self.message = BeaconUtils.buildMessage(rollcallId: rollcallId, nonce: nonce)
81
+ }
82
+
83
+ super.bridge.logToJs("[Debug] startBroadcasting 11.1")
84
+
85
+ if isBroadcasting {
86
+ call.resolve()
87
+ return
88
+ }
89
+ super.bridge.logToJs("[Debug] startBroadcasting 11.2")
90
+
91
+ needBroadcasting = true
92
+
93
+ if peripheralManager == nil {
94
+ peripheralManager = CBPeripheralManager(
95
+ delegate: self,
96
+ queue: nil
97
+ )
98
+ super.bridge.logToJs("[Debug] startBroadcasting 11.2.1")
99
+ }
100
+
101
+ if peripheralManager?.state == .poweredOn {
102
+ self.startAdvertising()
103
+ super.bridge.logToJs("[Debug] startBroadcasting 11.2.2")
104
+ }
105
+ super.bridge.logToJs("[Debug] startBroadcasting 11.3")
106
+
107
+ call.resolve()
108
+ }
109
+
110
+ @objc func stopBroadcasting(_ call: CAPPluginCall) {
111
+ peripheralManager?.stopAdvertising()
112
+ isBroadcasting = false
113
+ needBroadcasting = false
114
+ call.resolve()
115
+ }
116
+
117
+ func scanForPeripherals() {
118
+ super.bridge.logToJs("[Debug] scanForPeripherals 22")
119
+ if centralManager == nil {
120
+ return
121
+ }
122
+
123
+ if isMonitoring == true {
124
+ return
125
+ }
126
+ super.bridge.logToJs("[Debug] scanForPeripherals monitoring 23")
127
+ isMonitoring = true
128
+
129
+ let options: [String: Any] = [
130
+ CBCentralManagerScanOptionAllowDuplicatesKey: allowDuplicatesKey,
131
+ CBCentralManagerScanOptionSolicitedServiceUUIDsKey: [
132
+ CBUUID(string: BeaconUtils.WG_UUID)
133
+ ],
134
+ ]
135
+ super.bridge.logToJs("[Debug] scanForPeripherals monitoring 24")
136
+
137
+ centralManager?.scanForPeripherals(
138
+ withServices: [CBUUID(string: BeaconUtils.WG_UUID)],
139
+ options: options
140
+ )
141
+ super.bridge.logToJs("[Debug] scanForPeripherals monitoring 25")
142
+ }
143
+
144
+ @objc func startMonitoring(_ call: CAPPluginCall) {
145
+ super.bridge.logToJs("[Debug] startMonitoring 21")
146
+ if isMonitoring {
147
+ call.resolve()
148
+ return
149
+ }
150
+ needMonitoring = true
151
+ super.bridge.logToJs("[Debug] startMonitoring 21.1")
152
+
153
+ if centralManager == nil {
154
+ centralManager = CBCentralManager(delegate: self, queue: nil)
155
+ super.bridge.logToJs("[Debug] startMonitoring 21.1.1")
156
+ }
157
+ super.bridge.logToJs("[Debug] startMonitoring 21.2")
158
+
159
+ if centralManager?.state == .poweredOn {
160
+ super.bridge.logToJs("[Debug] startMonitoring 21.2.1")
161
+ self.scanForPeripherals()
162
+ }
163
+ super.bridge.logToJs("[Debug] startMonitoring 21.3")
164
+
165
+ call.resolve()
166
+ }
167
+
168
+ @objc func stopMonitoring(_ call: CAPPluginCall) {
169
+ centralManager?.stopScan()
170
+ isMonitoring = false
171
+ needMonitoring = false
172
+ call.resolve()
173
+ }
174
+
175
+ @objc func cleanup(_ call: CAPPluginCall) {
176
+ peripheralManager?.stopAdvertising()
177
+ centralManager?.stopScan()
178
+
179
+ peripheralManager = nil
180
+ centralManager = nil
181
+ isBroadcasting = false
182
+ isMonitoring = false
183
+ needBroadcasting = false
184
+ needMonitoring = false
185
+
186
+ self.removeAllListeners(call)
187
+ call.resolve()
188
+ }
189
+
190
+ // MARK: - CBPeripheralManagerDelegate
191
+ public func peripheralManagerDidUpdateState(
192
+ _ peripheral: CBPeripheralManager
193
+ ) {
194
+ super.bridge.logToJs(
195
+ "[Beacon] Peripheral manager state changed to: \(peripheral.state.rawValue)"
196
+ )
197
+
198
+ switch peripheral.state {
199
+ case .poweredOn:
200
+ super.bridge.logToJs("[Beacon] Peripheral manager is powered on")
201
+ notifyListeners(
202
+ "stateUpdated",
203
+ data: ["type": "peripheral", "state": "poweredOn"]
204
+ )
205
+ case .poweredOff:
206
+ super.bridge.logToJs("[Beacon] Peripheral manager is powered off")
207
+ notifyListeners(
208
+ "stateUpdated",
209
+ data: ["type": "peripheral", "state": "poweredOff"]
210
+ )
211
+ case .unauthorized:
212
+ super.bridge.logToJs("[Beacon] Peripheral manager is unauthorized")
213
+ notifyListeners(
214
+ "stateUpdated",
215
+ data: ["type": "peripheral", "state": "unauthorized"]
216
+ )
217
+ case .unsupported:
218
+ super.bridge.logToJs("[Beacon] Peripheral manager is unsupported")
219
+ notifyListeners(
220
+ "stateUpdated",
221
+ data: ["type": "peripheral", "state": "unsupported"]
222
+ )
223
+ default:
224
+ super.bridge.logToJs(
225
+ "[Beacon] Peripheral manager state: \(peripheral.state.rawValue)"
226
+ )
227
+ notifyListeners(
228
+ "stateUpdated",
229
+ data: [
230
+ "type": "peripheral", "state": peripheral.state.rawValue,
231
+ ]
232
+ )
233
+ }
234
+
235
+ if needBroadcasting {
236
+ if peripheral.state == .poweredOn {
237
+ super.bridge.logToJs(
238
+ "[Debug] peripheralManagerDidUpdateState needBroadcasting poweredOn"
239
+ )
240
+ self.startAdvertising()
241
+ } else {
242
+ super.bridge.logToJs(
243
+ "[Debug] peripheralManagerDidUpdateState needBroadcasting but stopAdvertising"
244
+ )
245
+ peripheralManager?.stopAdvertising()
246
+ isBroadcasting = false
247
+ }
248
+ }
249
+ }
250
+
251
+ // MARK: - CBCentralManagerDelegate
252
+
253
+ public func centralManagerDidUpdateState(_ central: CBCentralManager) {
254
+ super.bridge.logToJs(
255
+ "[Beacon] Central manager state changed to: \(central.state.rawValue)"
256
+ )
257
+
258
+ switch central.state {
259
+ case .poweredOn:
260
+ super.bridge.logToJs("[Beacon] Central manager is powered on")
261
+ notifyListeners("bluetoothStateChanged", data: ["enabled": true])
262
+ case .poweredOff:
263
+ super.bridge.logToJs("[Beacon] Central manager is powered off")
264
+ notifyListeners(
265
+ "stateError",
266
+ data: ["type": "central", "state": "poweredOff"]
267
+ )
268
+ notifyListeners("bluetoothStateChanged", data: ["enabled": false])
269
+ case .unauthorized:
270
+ super.bridge.logToJs("[Beacon] Central manager is unauthorized")
271
+ notifyListeners(
272
+ "stateError",
273
+ data: ["type": "central", "state": "unauthorized"]
274
+ )
275
+ notifyListeners(
276
+ "bluetoothStateChanged",
277
+ data: ["enabled": false, "error": "unauthorized"]
278
+ )
279
+ case .unsupported:
280
+ super.bridge.logToJs("[Beacon] Central manager is unsupported")
281
+ notifyListeners(
282
+ "stateError",
283
+ data: ["type": "central", "state": "unsupported"]
284
+ )
285
+ notifyListeners(
286
+ "bluetoothStateChanged",
287
+ data: ["enabled": false, "error": "unsupported"]
288
+ )
289
+ default:
290
+ super.bridge.logToJs(
291
+ "[Beacon] Central manager state: \(central.state.rawValue)"
292
+ )
293
+ notifyListeners(
294
+ "stateError",
295
+ data: ["type": "central", "state": central.state.rawValue]
296
+ )
297
+ notifyListeners(
298
+ "bluetoothStateChanged",
299
+ data: ["enabled": false, "error": "unknown"]
300
+ )
301
+ }
302
+
303
+ if needMonitoring {
304
+ if central.state == .poweredOn {
305
+ super.bridge.logToJs(
306
+ "[Debug] centralManagerDidUpdateState needMonitoring poweredOn"
307
+ )
308
+ self.scanForPeripherals()
309
+ } else {
310
+ super.bridge.logToJs(
311
+ "[Debug] centralManagerDidUpdateState needMonitoring but stopScan"
312
+ )
313
+ centralManager?.stopScan()
314
+ isMonitoring = false
315
+ }
316
+ }
317
+ }
318
+
319
+ public func centralManager(
320
+ _ central: CBCentralManager,
321
+ didDiscover peripheral: CBPeripheral,
322
+ advertisementData: [String: Any],
323
+ rssi RSSI: NSNumber
324
+ ) {
325
+ if let message = advertisementData[CBAdvertisementDataLocalNameKey]
326
+ as? String
327
+ {
328
+ let peripheralId = peripheral.identifier.uuidString
329
+ let rssiValue = RSSI.intValue
330
+
331
+ notifyListeners(
332
+ "beaconReceived",
333
+ data: [
334
+ "message": message,
335
+ "rssi": rssiValue,
336
+ "peripheralId": peripheralId,
337
+ "timestamp": Int64(Date().timeIntervalSince1970 * 1000),
338
+ ]
339
+ )
340
+ }
341
+ }
342
+ }