@thelacanians/vue-native-cli 0.4.3 → 0.4.4

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 (172) hide show
  1. package/dist/cli.js +34 -17
  2. package/native/android/README.md +205 -0
  3. package/native/android/VueNativeCore/build.gradle.kts +100 -0
  4. package/native/android/VueNativeCore/consumer-rules.pro +12 -0
  5. package/native/android/VueNativeCore/proguard-rules.pro +33 -0
  6. package/native/android/VueNativeCore/src/main/AndroidManifest.xml +17 -0
  7. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/ErrorOverlayView.kt +94 -0
  8. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/HotReloadManager.kt +105 -0
  9. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/JSPolyfills.kt +652 -0
  10. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/JSRuntime.kt +207 -0
  11. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/NativeBridge.kt +417 -0
  12. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/ComponentRegistry.kt +76 -0
  13. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VActionSheetFactory.kt +78 -0
  14. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VActivityIndicatorFactory.kt +46 -0
  15. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VAlertDialogFactory.kt +84 -0
  16. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VButtonFactory.kt +73 -0
  17. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VCheckboxFactory.kt +93 -0
  18. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VDropdownFactory.kt +125 -0
  19. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VImageFactory.kt +75 -0
  20. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VInputFactory.kt +210 -0
  21. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VKeyboardAvoidingFactory.kt +31 -0
  22. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VListFactory.kt +183 -0
  23. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VModalFactory.kt +105 -0
  24. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VPickerFactory.kt +57 -0
  25. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VPressableFactory.kt +109 -0
  26. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VProgressBarFactory.kt +43 -0
  27. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VRadioFactory.kt +103 -0
  28. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VRefreshControlFactory.kt +73 -0
  29. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VRootFactory.kt +39 -0
  30. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSafeAreaFactory.kt +48 -0
  31. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VScrollViewFactory.kt +105 -0
  32. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSectionListFactory.kt +144 -0
  33. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSegmentedControlFactory.kt +77 -0
  34. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSliderFactory.kt +74 -0
  35. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VStatusBarFactory.kt +52 -0
  36. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSwitchFactory.kt +62 -0
  37. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VTextFactory.kt +53 -0
  38. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VVideoFactory.kt +191 -0
  39. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VViewFactory.kt +48 -0
  40. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VWebViewFactory.kt +90 -0
  41. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/NativeComponentFactory.kt +40 -0
  42. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/VTextNodeView.kt +23 -0
  43. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Helpers/GestureHelper.kt +16 -0
  44. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Helpers/TouchableView.kt +105 -0
  45. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/AnimationModule.kt +292 -0
  46. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/AppStateModule.kt +41 -0
  47. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/AsyncStorageModule.kt +59 -0
  48. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/AudioModule.kt +331 -0
  49. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/BackgroundTaskModule.kt +166 -0
  50. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/BiometryModule.kt +56 -0
  51. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/BluetoothModule.kt +302 -0
  52. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/CalendarModule.kt +198 -0
  53. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/CameraModule.kt +64 -0
  54. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/ClipboardModule.kt +36 -0
  55. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/ContactsModule.kt +288 -0
  56. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/DatabaseModule.kt +229 -0
  57. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/DeviceInfoModule.kt +39 -0
  58. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/FileSystemModule.kt +193 -0
  59. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/GeolocationModule.kt +68 -0
  60. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/HapticsModule.kt +61 -0
  61. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/HttpModule.kt +111 -0
  62. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/IAPModule.kt +302 -0
  63. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/KeyboardModule.kt +26 -0
  64. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/LinkingModule.kt +43 -0
  65. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NativeModule.kt +27 -0
  66. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NativeModuleRegistry.kt +92 -0
  67. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NetworkModule.kt +75 -0
  68. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NotificationsModule.kt +181 -0
  69. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/OTAModule.kt +255 -0
  70. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/PerformanceModule.kt +147 -0
  71. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/PermissionsModule.kt +126 -0
  72. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/SecureStorageModule.kt +51 -0
  73. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/SensorsModule.kt +134 -0
  74. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/ShareModule.kt +36 -0
  75. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/SocialAuthModule.kt +160 -0
  76. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/WebSocketModule.kt +155 -0
  77. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Styling/StyleEngine.kt +802 -0
  78. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Tags.kt +43 -0
  79. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/VueNativeActivity.kt +169 -0
  80. package/native/android/VueNativeCore/src/main/res/values/ids.xml +8 -0
  81. package/native/android/app/build.gradle.kts +45 -0
  82. package/native/android/app/proguard-rules.pro +5 -0
  83. package/native/android/app/src/main/AndroidManifest.xml +25 -0
  84. package/native/android/app/src/main/assets/.gitkeep +0 -0
  85. package/native/android/app/src/main/kotlin/com/vuenative/example/counter/MainActivity.kt +14 -0
  86. package/native/android/app/src/main/res/layout/activity_main.xml +6 -0
  87. package/native/android/app/src/main/res/values/strings.xml +3 -0
  88. package/native/android/app/src/main/res/values/themes.xml +9 -0
  89. package/native/android/app/src/main/res/xml/network_security_config.xml +8 -0
  90. package/native/android/build.gradle.kts +6 -0
  91. package/native/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  92. package/native/android/gradle/wrapper/gradle-wrapper.properties +7 -0
  93. package/native/android/gradle.properties +4 -0
  94. package/native/android/gradlew +87 -0
  95. package/native/android/gradlew.bat +48 -0
  96. package/native/android/settings.gradle.kts +20 -0
  97. package/native/ios/VueNativeCore/Package.resolved +23 -0
  98. package/native/ios/VueNativeCore/Package.swift +32 -0
  99. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/CertificatePinning.swift +132 -0
  100. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/ErrorOverlayView.swift +92 -0
  101. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/HotReloadManager.swift +147 -0
  102. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/JSPolyfills.swift +711 -0
  103. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/JSRuntime.swift +421 -0
  104. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/NativeBridge.swift +891 -0
  105. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/VueNativeViewController.swift +88 -0
  106. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/ComponentRegistry.swift +193 -0
  107. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VActionSheetFactory.swift +91 -0
  108. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VActivityIndicatorFactory.swift +74 -0
  109. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VAlertDialogFactory.swift +150 -0
  110. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VButtonFactory.swift +93 -0
  111. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VCheckboxFactory.swift +114 -0
  112. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VDropdownFactory.swift +112 -0
  113. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VImageFactory.swift +172 -0
  114. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VInputFactory.swift +357 -0
  115. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VKeyboardAvoidingFactory.swift +99 -0
  116. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VListFactory.swift +250 -0
  117. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VModalFactory.swift +112 -0
  118. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VPickerFactory.swift +96 -0
  119. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VPressableFactory.swift +168 -0
  120. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VProgressBarFactory.swift +39 -0
  121. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VRadioFactory.swift +167 -0
  122. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VRefreshControlFactory.swift +153 -0
  123. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSafeAreaFactory.swift +56 -0
  124. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VScrollViewFactory.swift +240 -0
  125. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSectionListFactory.swift +248 -0
  126. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSegmentedControlFactory.swift +73 -0
  127. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSliderFactory.swift +63 -0
  128. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VStatusBarFactory.swift +50 -0
  129. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSwitchFactory.swift +108 -0
  130. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VTextFactory.swift +290 -0
  131. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VVideoFactory.swift +246 -0
  132. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VViewFactory.swift +157 -0
  133. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VWebViewFactory.swift +172 -0
  134. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/NativeComponentFactory.swift +53 -0
  135. package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/GestureWrapper.swift +107 -0
  136. package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/TouchableView.swift +136 -0
  137. package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/UIColor+Hex.swift +80 -0
  138. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AnimationModule.swift +291 -0
  139. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AppStateModule.swift +65 -0
  140. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AsyncStorageModule.swift +68 -0
  141. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AudioModule.swift +366 -0
  142. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/BackgroundTaskModule.swift +135 -0
  143. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/BiometryModule.swift +61 -0
  144. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/BluetoothModule.swift +387 -0
  145. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/CalendarModule.swift +161 -0
  146. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/CameraModule.swift +318 -0
  147. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/ClipboardModule.swift +33 -0
  148. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/ContactsModule.swift +173 -0
  149. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/DatabaseModule.swift +259 -0
  150. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/DeviceInfoModule.swift +34 -0
  151. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/FileSystemModule.swift +233 -0
  152. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/GeolocationModule.swift +147 -0
  153. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/HapticsModule.swift +50 -0
  154. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/IAPModule.swift +194 -0
  155. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/KeyboardModule.swift +31 -0
  156. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/LinkingModule.swift +42 -0
  157. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NativeModule.swift +28 -0
  158. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NativeModuleRegistry.swift +78 -0
  159. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NetworkModule.swift +62 -0
  160. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NotificationsModule.swift +215 -0
  161. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/OTAModule.swift +281 -0
  162. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/PerformanceModule.swift +138 -0
  163. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/PermissionsModule.swift +190 -0
  164. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/SecureStorageModule.swift +118 -0
  165. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/SensorsModule.swift +103 -0
  166. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/ShareModule.swift +49 -0
  167. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/SocialAuthModule.swift +240 -0
  168. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/WebSocketModule.swift +213 -0
  169. package/native/ios/VueNativeCore/Sources/VueNativeCore/Resources/vue-native-placeholder.js +8 -0
  170. package/native/ios/VueNativeCore/Sources/VueNativeCore/Styling/StyleEngine.swift +885 -0
  171. package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/JSRuntimeTests.swift +362 -0
  172. package/package.json +3 -2
@@ -0,0 +1,387 @@
1
+ #if canImport(UIKit)
2
+ import UIKit
3
+ import CoreBluetooth
4
+
5
+ /// Native module for Bluetooth Low Energy (BLE) operations.
6
+ ///
7
+ /// Methods:
8
+ /// - startScan(serviceUUIDs?: [String]) — start scanning for peripherals
9
+ /// - stopScan() — stop scanning
10
+ /// - connect(deviceId: String) — connect to a peripheral
11
+ /// - disconnect(deviceId: String) — disconnect from a peripheral
12
+ /// - readCharacteristic(deviceId, serviceUUID, charUUID) — read a characteristic
13
+ /// - writeCharacteristic(deviceId, serviceUUID, charUUID, data) — write a characteristic
14
+ /// - subscribeToCharacteristic(deviceId, serviceUUID, charUUID) — subscribe to notifications
15
+ /// - unsubscribeFromCharacteristic(deviceId, serviceUUID, charUUID)
16
+ /// - getState() — returns current Bluetooth state
17
+ ///
18
+ /// Events:
19
+ /// - ble:deviceFound — peripheral discovered
20
+ /// - ble:connected — peripheral connected
21
+ /// - ble:disconnected — peripheral disconnected
22
+ /// - ble:characteristicChanged — characteristic value updated
23
+ /// - ble:stateChanged — Bluetooth state changed
24
+ /// - ble:error — error occurred
25
+ final class BluetoothModule: NativeModule {
26
+ var moduleName: String { "Bluetooth" }
27
+ private weak var bridge: NativeBridge?
28
+
29
+ init(bridge: NativeBridge) { self.bridge = bridge }
30
+
31
+ func invoke(method: String, args: [Any], callback: @escaping (Any?, String?) -> Void) {
32
+ let weakBridge = bridge
33
+ switch method {
34
+ case "startScan":
35
+ let serviceUUIDs = (args.first as? [String])
36
+ DispatchQueue.main.async {
37
+ BLEManager.shared.startScan(serviceUUIDs: serviceUUIDs, bridge: weakBridge)
38
+ callback(nil, nil)
39
+ }
40
+ case "stopScan":
41
+ DispatchQueue.main.async {
42
+ BLEManager.shared.stopScan()
43
+ callback(nil, nil)
44
+ }
45
+ case "connect":
46
+ guard let deviceId = args.first as? String else {
47
+ callback(nil, "BluetoothModule: missing deviceId"); return
48
+ }
49
+ DispatchQueue.main.async {
50
+ BLEManager.shared.connect(deviceId: deviceId, bridge: weakBridge, callback: callback)
51
+ }
52
+ case "disconnect":
53
+ guard let deviceId = args.first as? String else {
54
+ callback(nil, "BluetoothModule: missing deviceId"); return
55
+ }
56
+ DispatchQueue.main.async {
57
+ BLEManager.shared.disconnect(deviceId: deviceId, callback: callback)
58
+ }
59
+ case "readCharacteristic":
60
+ guard let deviceId = args[safe: 0] as? String,
61
+ let serviceUUID = args[safe: 1] as? String,
62
+ let charUUID = args[safe: 2] as? String else {
63
+ callback(nil, "BluetoothModule: missing deviceId/serviceUUID/charUUID"); return
64
+ }
65
+ DispatchQueue.main.async {
66
+ BLEManager.shared.readCharacteristic(
67
+ deviceId: deviceId, serviceUUID: serviceUUID, charUUID: charUUID, callback: callback
68
+ )
69
+ }
70
+ case "writeCharacteristic":
71
+ guard let deviceId = args[safe: 0] as? String,
72
+ let serviceUUID = args[safe: 1] as? String,
73
+ let charUUID = args[safe: 2] as? String,
74
+ let dataBase64 = args[safe: 3] as? String else {
75
+ callback(nil, "BluetoothModule: missing args for writeCharacteristic"); return
76
+ }
77
+ DispatchQueue.main.async {
78
+ BLEManager.shared.writeCharacteristic(
79
+ deviceId: deviceId, serviceUUID: serviceUUID, charUUID: charUUID,
80
+ dataBase64: dataBase64, callback: callback
81
+ )
82
+ }
83
+ case "subscribeToCharacteristic":
84
+ guard let deviceId = args[safe: 0] as? String,
85
+ let serviceUUID = args[safe: 1] as? String,
86
+ let charUUID = args[safe: 2] as? String else {
87
+ callback(nil, "BluetoothModule: missing args for subscribeToCharacteristic"); return
88
+ }
89
+ DispatchQueue.main.async {
90
+ BLEManager.shared.subscribeToCharacteristic(
91
+ deviceId: deviceId, serviceUUID: serviceUUID, charUUID: charUUID,
92
+ bridge: weakBridge, callback: callback
93
+ )
94
+ }
95
+ case "unsubscribeFromCharacteristic":
96
+ guard let deviceId = args[safe: 0] as? String,
97
+ let serviceUUID = args[safe: 1] as? String,
98
+ let charUUID = args[safe: 2] as? String else {
99
+ callback(nil, "BluetoothModule: missing args for unsubscribeFromCharacteristic"); return
100
+ }
101
+ DispatchQueue.main.async {
102
+ BLEManager.shared.unsubscribeFromCharacteristic(
103
+ deviceId: deviceId, serviceUUID: serviceUUID, charUUID: charUUID, callback: callback
104
+ )
105
+ }
106
+ case "getState":
107
+ DispatchQueue.main.async {
108
+ callback(BLEManager.shared.getState(), nil)
109
+ }
110
+ default:
111
+ callback(nil, "BluetoothModule: Unknown method '\(method)'")
112
+ }
113
+ }
114
+
115
+ func invokeSync(method: String, args: [Any]) -> Any? { nil }
116
+ }
117
+
118
+ // MARK: - Safe array subscript
119
+
120
+ private extension Array {
121
+ subscript(safe index: Int) -> Element? {
122
+ indices.contains(index) ? self[index] : nil
123
+ }
124
+ }
125
+
126
+ // MARK: - BLE Manager
127
+
128
+ @MainActor
129
+ private final class BLEManager: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate {
130
+ static let shared = BLEManager()
131
+
132
+ private var centralManager: CBCentralManager?
133
+ private var discoveredPeripherals: [String: CBPeripheral] = [:]
134
+ private var connectedPeripherals: [String: CBPeripheral] = [:]
135
+
136
+ private struct WeakBridge { weak var bridge: NativeBridge? }
137
+ private var scanBridge: WeakBridge?
138
+ private var connectCallbacks: [String: (Any?, String?) -> Void] = [:]
139
+ private var readCallbacks: [String: (Any?, String?) -> Void] = [:]
140
+ private var writeCallbacks: [String: (Any?, String?) -> Void] = [:]
141
+ private var subscribeBridges: [String: WeakBridge] = [:]
142
+
143
+ // MARK: Setup
144
+
145
+ private func ensureManager() {
146
+ guard centralManager == nil else { return }
147
+ centralManager = CBCentralManager(delegate: self, queue: nil)
148
+ }
149
+
150
+ // MARK: Public interface
151
+
152
+ func getState() -> String {
153
+ ensureManager()
154
+ return stateString(centralManager?.state ?? .unknown)
155
+ }
156
+
157
+ func startScan(serviceUUIDs: [String]?, bridge: NativeBridge?) {
158
+ ensureManager()
159
+ scanBridge = WeakBridge(bridge: bridge)
160
+ let uuids = serviceUUIDs?.map { CBUUID(string: $0) }
161
+ centralManager?.scanForPeripherals(withServices: uuids, options: [
162
+ CBCentralManagerScanOptionAllowDuplicatesKey: false
163
+ ])
164
+ }
165
+
166
+ func stopScan() {
167
+ centralManager?.stopScan()
168
+ scanBridge = nil
169
+ }
170
+
171
+ func connect(deviceId: String, bridge: NativeBridge?, callback: @escaping (Any?, String?) -> Void) {
172
+ guard let peripheral = discoveredPeripherals[deviceId] else {
173
+ callback(nil, "Device not found: \(deviceId)"); return
174
+ }
175
+ connectCallbacks[deviceId] = callback
176
+ scanBridge = WeakBridge(bridge: bridge)
177
+ peripheral.delegate = self
178
+ centralManager?.connect(peripheral, options: nil)
179
+ }
180
+
181
+ func disconnect(deviceId: String, callback: @escaping (Any?, String?) -> Void) {
182
+ guard let peripheral = connectedPeripherals[deviceId] else {
183
+ callback(nil, "Device not connected: \(deviceId)"); return
184
+ }
185
+ centralManager?.cancelPeripheralConnection(peripheral)
186
+ callback(nil, nil)
187
+ }
188
+
189
+ func readCharacteristic(deviceId: String, serviceUUID: String, charUUID: String, callback: @escaping (Any?, String?) -> Void) {
190
+ guard let peripheral = connectedPeripherals[deviceId] else {
191
+ callback(nil, "Device not connected: \(deviceId)"); return
192
+ }
193
+ guard let char = findCharacteristic(peripheral: peripheral, serviceUUID: serviceUUID, charUUID: charUUID) else {
194
+ callback(nil, "Characteristic not found: \(charUUID)"); return
195
+ }
196
+ let key = "\(deviceId):\(serviceUUID):\(charUUID)"
197
+ readCallbacks[key] = callback
198
+ peripheral.readValue(for: char)
199
+ }
200
+
201
+ func writeCharacteristic(deviceId: String, serviceUUID: String, charUUID: String, dataBase64: String, callback: @escaping (Any?, String?) -> Void) {
202
+ guard let peripheral = connectedPeripherals[deviceId] else {
203
+ callback(nil, "Device not connected: \(deviceId)"); return
204
+ }
205
+ guard let char = findCharacteristic(peripheral: peripheral, serviceUUID: serviceUUID, charUUID: charUUID) else {
206
+ callback(nil, "Characteristic not found: \(charUUID)"); return
207
+ }
208
+ guard let data = Data(base64Encoded: dataBase64) else {
209
+ callback(nil, "Invalid base64 data"); return
210
+ }
211
+ let key = "\(deviceId):\(serviceUUID):\(charUUID)"
212
+ writeCallbacks[key] = callback
213
+ let writeType: CBCharacteristicWriteType = char.properties.contains(.writeWithoutResponse) ? .withoutResponse : .withResponse
214
+ peripheral.writeValue(data, for: char, type: writeType)
215
+ if writeType == .withoutResponse {
216
+ writeCallbacks.removeValue(forKey: key)
217
+ callback(nil, nil)
218
+ }
219
+ }
220
+
221
+ func subscribeToCharacteristic(deviceId: String, serviceUUID: String, charUUID: String, bridge: NativeBridge?, callback: @escaping (Any?, String?) -> Void) {
222
+ guard let peripheral = connectedPeripherals[deviceId] else {
223
+ callback(nil, "Device not connected: \(deviceId)"); return
224
+ }
225
+ guard let char = findCharacteristic(peripheral: peripheral, serviceUUID: serviceUUID, charUUID: charUUID) else {
226
+ callback(nil, "Characteristic not found: \(charUUID)"); return
227
+ }
228
+ let key = "\(deviceId):\(serviceUUID):\(charUUID)"
229
+ subscribeBridges[key] = WeakBridge(bridge: bridge)
230
+ peripheral.setNotifyValue(true, for: char)
231
+ callback(nil, nil)
232
+ }
233
+
234
+ func unsubscribeFromCharacteristic(deviceId: String, serviceUUID: String, charUUID: String, callback: @escaping (Any?, String?) -> Void) {
235
+ guard let peripheral = connectedPeripherals[deviceId] else {
236
+ callback(nil, "Device not connected: \(deviceId)"); return
237
+ }
238
+ guard let char = findCharacteristic(peripheral: peripheral, serviceUUID: serviceUUID, charUUID: charUUID) else {
239
+ callback(nil, "Characteristic not found: \(charUUID)"); return
240
+ }
241
+ let key = "\(deviceId):\(serviceUUID):\(charUUID)"
242
+ subscribeBridges.removeValue(forKey: key)
243
+ peripheral.setNotifyValue(false, for: char)
244
+ callback(nil, nil)
245
+ }
246
+
247
+ // MARK: Helpers
248
+
249
+ private func findCharacteristic(peripheral: CBPeripheral, serviceUUID: String, charUUID: String) -> CBCharacteristic? {
250
+ let sUUID = CBUUID(string: serviceUUID)
251
+ let cUUID = CBUUID(string: charUUID)
252
+ guard let service = peripheral.services?.first(where: { $0.uuid == sUUID }) else { return nil }
253
+ return service.characteristics?.first(where: { $0.uuid == cUUID })
254
+ }
255
+
256
+ private func stateString(_ state: CBManagerState) -> String {
257
+ switch state {
258
+ case .poweredOn: return "poweredOn"
259
+ case .poweredOff: return "poweredOff"
260
+ case .unauthorized: return "unauthorized"
261
+ case .unsupported: return "unsupported"
262
+ case .resetting: return "resetting"
263
+ case .unknown: return "unknown"
264
+ @unknown default: return "unknown"
265
+ }
266
+ }
267
+
268
+ private func peripheralId(_ peripheral: CBPeripheral) -> String {
269
+ peripheral.identifier.uuidString
270
+ }
271
+
272
+ // MARK: CBCentralManagerDelegate
273
+
274
+ nonisolated func centralManagerDidUpdateState(_ central: CBCentralManager) {
275
+ Task { @MainActor in
276
+ let state = self.stateString(central.state)
277
+ self.scanBridge?.bridge?.dispatchGlobalEvent("ble:stateChanged", payload: ["state": state])
278
+ }
279
+ }
280
+
281
+ nonisolated func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) {
282
+ Task { @MainActor in
283
+ let id = self.peripheralId(peripheral)
284
+ self.discoveredPeripherals[id] = peripheral
285
+ let payload: [String: Any] = [
286
+ "id": id,
287
+ "name": peripheral.name ?? "",
288
+ "rssi": RSSI.intValue,
289
+ ]
290
+ self.scanBridge?.bridge?.dispatchGlobalEvent("ble:deviceFound", payload: payload)
291
+ }
292
+ }
293
+
294
+ nonisolated func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
295
+ Task { @MainActor in
296
+ let id = self.peripheralId(peripheral)
297
+ self.connectedPeripherals[id] = peripheral
298
+ peripheral.discoverServices(nil)
299
+ let payload: [String: Any] = ["id": id, "name": peripheral.name ?? ""]
300
+ self.scanBridge?.bridge?.dispatchGlobalEvent("ble:connected", payload: payload)
301
+ if let cb = self.connectCallbacks.removeValue(forKey: id) {
302
+ cb(payload, nil)
303
+ }
304
+ }
305
+ }
306
+
307
+ nonisolated func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
308
+ Task { @MainActor in
309
+ let id = self.peripheralId(peripheral)
310
+ self.connectedPeripherals.removeValue(forKey: id)
311
+ let payload: [String: Any] = ["id": id, "name": peripheral.name ?? ""]
312
+ self.scanBridge?.bridge?.dispatchGlobalEvent("ble:disconnected", payload: payload)
313
+ }
314
+ }
315
+
316
+ nonisolated func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
317
+ Task { @MainActor in
318
+ let id = self.peripheralId(peripheral)
319
+ let msg = error?.localizedDescription ?? "Connection failed"
320
+ if let cb = self.connectCallbacks.removeValue(forKey: id) {
321
+ cb(nil, msg)
322
+ }
323
+ self.scanBridge?.bridge?.dispatchGlobalEvent("ble:error", payload: ["message": msg, "deviceId": id])
324
+ }
325
+ }
326
+
327
+ // MARK: CBPeripheralDelegate
328
+
329
+ nonisolated func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
330
+ guard error == nil else { return }
331
+ Task { @MainActor in
332
+ for service in peripheral.services ?? [] {
333
+ peripheral.discoverCharacteristics(nil, for: service)
334
+ }
335
+ }
336
+ }
337
+
338
+ nonisolated func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
339
+ // Characteristics are now available for read/write/subscribe
340
+ }
341
+
342
+ nonisolated func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
343
+ Task { @MainActor in
344
+ let id = self.peripheralId(peripheral)
345
+ let serviceUUID = characteristic.service?.uuid.uuidString ?? ""
346
+ let charUUID = characteristic.uuid.uuidString
347
+ let key = "\(id):\(serviceUUID):\(charUUID)"
348
+ let valueBase64 = characteristic.value?.base64EncodedString() ?? ""
349
+
350
+ // One-shot read callback
351
+ if let cb = self.readCallbacks.removeValue(forKey: key) {
352
+ if let err = error {
353
+ cb(nil, err.localizedDescription)
354
+ } else {
355
+ cb(["value": valueBase64, "characteristicUUID": charUUID, "serviceUUID": serviceUUID], nil)
356
+ }
357
+ }
358
+
359
+ // Subscription notification
360
+ if let wb = self.subscribeBridges[key] {
361
+ wb.bridge?.dispatchGlobalEvent("ble:characteristicChanged", payload: [
362
+ "deviceId": id,
363
+ "serviceUUID": serviceUUID,
364
+ "characteristicUUID": charUUID,
365
+ "value": valueBase64,
366
+ ])
367
+ }
368
+ }
369
+ }
370
+
371
+ nonisolated func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
372
+ Task { @MainActor in
373
+ let id = self.peripheralId(peripheral)
374
+ let serviceUUID = characteristic.service?.uuid.uuidString ?? ""
375
+ let charUUID = characteristic.uuid.uuidString
376
+ let key = "\(id):\(serviceUUID):\(charUUID)"
377
+ if let cb = self.writeCallbacks.removeValue(forKey: key) {
378
+ if let err = error {
379
+ cb(nil, err.localizedDescription)
380
+ } else {
381
+ cb(nil, nil)
382
+ }
383
+ }
384
+ }
385
+ }
386
+ }
387
+ #endif
@@ -0,0 +1,161 @@
1
+ #if canImport(UIKit)
2
+ import UIKit
3
+ import EventKit
4
+
5
+ /// Native module for calendar (EventKit) access.
6
+ ///
7
+ /// Methods:
8
+ /// - requestAccess() — request calendar access
9
+ /// - getEvents(startDate, endDate) — fetch events in a date range
10
+ /// - createEvent(title, startDate, endDate, notes?) — create a calendar event
11
+ /// - deleteEvent(eventId) — delete an event
12
+ /// - getCalendars() — list available calendars
13
+ final class CalendarModule: NativeModule {
14
+ var moduleName: String { "Calendar" }
15
+
16
+ private let eventStore = EKEventStore()
17
+
18
+ func invoke(method: String, args: [Any], callback: @escaping (Any?, String?) -> Void) {
19
+ switch method {
20
+ case "requestAccess":
21
+ if #available(iOS 17.0, *) {
22
+ eventStore.requestFullAccessToEvents { granted, error in
23
+ if let error = error {
24
+ callback(nil, error.localizedDescription)
25
+ } else {
26
+ callback(["granted": granted], nil)
27
+ }
28
+ }
29
+ } else {
30
+ eventStore.requestAccess(to: .event) { granted, error in
31
+ if let error = error {
32
+ callback(nil, error.localizedDescription)
33
+ } else {
34
+ callback(["granted": granted], nil)
35
+ }
36
+ }
37
+ }
38
+
39
+ case "getEvents":
40
+ guard let startMs = args[safe: 0] as? Double,
41
+ let endMs = args[safe: 1] as? Double else {
42
+ callback(nil, "CalendarModule: missing startDate/endDate (milliseconds)"); return
43
+ }
44
+ let startDate = Date(timeIntervalSince1970: startMs / 1000)
45
+ let endDate = Date(timeIntervalSince1970: endMs / 1000)
46
+ let predicate = eventStore.predicateForEvents(withStart: startDate, end: endDate, calendars: nil)
47
+ let events = eventStore.events(matching: predicate)
48
+ let result = events.map { eventToDict($0) }
49
+ callback(result, nil)
50
+
51
+ case "createEvent":
52
+ guard let title = args[safe: 0] as? String,
53
+ let startMs = args[safe: 1] as? Double,
54
+ let endMs = args[safe: 2] as? Double else {
55
+ callback(nil, "CalendarModule: missing title/startDate/endDate"); return
56
+ }
57
+ let notes = args[safe: 3] as? String
58
+ let calendarId = args[safe: 4] as? String
59
+
60
+ let event = EKEvent(eventStore: eventStore)
61
+ event.title = title
62
+ event.startDate = Date(timeIntervalSince1970: startMs / 1000)
63
+ event.endDate = Date(timeIntervalSince1970: endMs / 1000)
64
+ event.notes = notes
65
+
66
+ if let calId = calendarId,
67
+ let cal = eventStore.calendar(withIdentifier: calId) {
68
+ event.calendar = cal
69
+ } else {
70
+ event.calendar = eventStore.defaultCalendarForNewEvents
71
+ }
72
+
73
+ do {
74
+ try eventStore.save(event, span: .thisEvent)
75
+ callback(["eventId": event.eventIdentifier ?? ""], nil)
76
+ } catch {
77
+ callback(nil, error.localizedDescription)
78
+ }
79
+
80
+ case "deleteEvent":
81
+ guard let eventId = args[safe: 0] as? String else {
82
+ callback(nil, "CalendarModule: missing eventId"); return
83
+ }
84
+ guard let event = eventStore.event(withIdentifier: eventId) else {
85
+ callback(nil, "Event not found: \(eventId)"); return
86
+ }
87
+ do {
88
+ try eventStore.remove(event, span: .thisEvent)
89
+ callback(nil, nil)
90
+ } catch {
91
+ callback(nil, error.localizedDescription)
92
+ }
93
+
94
+ case "getCalendars":
95
+ let calendars = eventStore.calendars(for: .event)
96
+ let result = calendars.map { calendarToDict($0) }
97
+ callback(result, nil)
98
+
99
+ default:
100
+ callback(nil, "CalendarModule: Unknown method '\(method)'")
101
+ }
102
+ }
103
+
104
+ func invokeSync(method: String, args: [Any]) -> Any? { nil }
105
+
106
+ // MARK: - Helpers
107
+
108
+ private func eventToDict(_ event: EKEvent) -> [String: Any] {
109
+ var dict: [String: Any] = [
110
+ "id": event.eventIdentifier ?? "",
111
+ "title": event.title ?? "",
112
+ "startDate": (event.startDate?.timeIntervalSince1970 ?? 0) * 1000,
113
+ "endDate": (event.endDate?.timeIntervalSince1970 ?? 0) * 1000,
114
+ "isAllDay": event.isAllDay,
115
+ "calendarId": event.calendar?.calendarIdentifier ?? "",
116
+ ]
117
+ if let notes = event.notes { dict["notes"] = notes }
118
+ if let location = event.location { dict["location"] = location }
119
+ return dict
120
+ }
121
+
122
+ private func calendarToDict(_ calendar: EKCalendar) -> [String: Any] {
123
+ return [
124
+ "id": calendar.calendarIdentifier,
125
+ "title": calendar.title,
126
+ "color": hexString(from: calendar.cgColor),
127
+ "isImmutable": calendar.isImmutable,
128
+ "type": calendarTypeString(calendar.type),
129
+ ]
130
+ }
131
+
132
+ private func calendarTypeString(_ type: EKCalendarType) -> String {
133
+ switch type {
134
+ case .local: return "local"
135
+ case .calDAV: return "calDAV"
136
+ case .exchange: return "exchange"
137
+ case .subscription: return "subscription"
138
+ case .birthday: return "birthday"
139
+ @unknown default: return "unknown"
140
+ }
141
+ }
142
+
143
+ private func hexString(from cgColor: CGColor?) -> String {
144
+ guard let color = cgColor,
145
+ let components = color.components,
146
+ components.count >= 3 else { return "#000000" }
147
+ let r = Int(components[0] * 255)
148
+ let g = Int(components[1] * 255)
149
+ let b = Int(components[2] * 255)
150
+ return String(format: "#%02X%02X%02X", r, g, b)
151
+ }
152
+ }
153
+
154
+ // MARK: - Safe array subscript (shared)
155
+
156
+ private extension Array {
157
+ subscript(safe index: Int) -> Element? {
158
+ indices.contains(index) ? self[index] : nil
159
+ }
160
+ }
161
+ #endif