@thelacanians/vue-native-cli 0.4.3 → 0.4.5

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 (173) hide show
  1. package/dist/cli.js +102 -32
  2. package/native/android/README.md +205 -0
  3. package/native/android/VueNativeCore/build.gradle.kts +113 -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 +163 -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 +136 -0
  100. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/ErrorOverlayView.swift +89 -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 +906 -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 +90 -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 +149 -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 +109 -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 +250 -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 +174 -0
  134. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/NativeComponentFactory.swift +53 -0
  135. package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/Extensions.swift +31 -0
  136. package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/GestureWrapper.swift +107 -0
  137. package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/TouchableView.swift +136 -0
  138. package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/UIColor+Hex.swift +80 -0
  139. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AnimationModule.swift +283 -0
  140. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AppStateModule.swift +59 -0
  141. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AsyncStorageModule.swift +68 -0
  142. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AudioModule.swift +371 -0
  143. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/BackgroundTaskModule.swift +135 -0
  144. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/BiometryModule.swift +61 -0
  145. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/BluetoothModule.swift +379 -0
  146. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/CalendarModule.swift +154 -0
  147. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/CameraModule.swift +315 -0
  148. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/ClipboardModule.swift +33 -0
  149. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/ContactsModule.swift +173 -0
  150. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/DatabaseModule.swift +259 -0
  151. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/DeviceInfoModule.swift +34 -0
  152. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/FileSystemModule.swift +233 -0
  153. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/GeolocationModule.swift +147 -0
  154. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/HapticsModule.swift +50 -0
  155. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/IAPModule.swift +194 -0
  156. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/KeyboardModule.swift +31 -0
  157. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/LinkingModule.swift +42 -0
  158. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NativeModule.swift +28 -0
  159. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NativeModuleRegistry.swift +78 -0
  160. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NetworkModule.swift +62 -0
  161. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NotificationsModule.swift +215 -0
  162. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/OTAModule.swift +281 -0
  163. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/PerformanceModule.swift +141 -0
  164. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/PermissionsModule.swift +190 -0
  165. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/SecureStorageModule.swift +118 -0
  166. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/SensorsModule.swift +103 -0
  167. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/ShareModule.swift +48 -0
  168. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/SocialAuthModule.swift +256 -0
  169. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/WebSocketModule.swift +213 -0
  170. package/native/ios/VueNativeCore/Sources/VueNativeCore/Resources/vue-native-placeholder.js +8 -0
  171. package/native/ios/VueNativeCore/Sources/VueNativeCore/Styling/StyleEngine.swift +885 -0
  172. package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/JSRuntimeTests.swift +362 -0
  173. package/package.json +3 -2
@@ -0,0 +1,379 @@
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: - BLE Manager
119
+
120
+ @MainActor
121
+ private final class BLEManager: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate {
122
+ static let shared = BLEManager()
123
+
124
+ private var centralManager: CBCentralManager?
125
+ private var discoveredPeripherals: [String: CBPeripheral] = [:]
126
+ private var connectedPeripherals: [String: CBPeripheral] = [:]
127
+
128
+ private struct WeakBridge { weak var bridge: NativeBridge? }
129
+ private var scanBridge: WeakBridge?
130
+ private var connectCallbacks: [String: (Any?, String?) -> Void] = [:]
131
+ private var readCallbacks: [String: (Any?, String?) -> Void] = [:]
132
+ private var writeCallbacks: [String: (Any?, String?) -> Void] = [:]
133
+ private var subscribeBridges: [String: WeakBridge] = [:]
134
+
135
+ // MARK: Setup
136
+
137
+ private func ensureManager() {
138
+ guard centralManager == nil else { return }
139
+ centralManager = CBCentralManager(delegate: self, queue: nil)
140
+ }
141
+
142
+ // MARK: Public interface
143
+
144
+ func getState() -> String {
145
+ ensureManager()
146
+ return stateString(centralManager?.state ?? .unknown)
147
+ }
148
+
149
+ func startScan(serviceUUIDs: [String]?, bridge: NativeBridge?) {
150
+ ensureManager()
151
+ scanBridge = WeakBridge(bridge: bridge)
152
+ let uuids = serviceUUIDs?.map { CBUUID(string: $0) }
153
+ centralManager?.scanForPeripherals(withServices: uuids, options: [
154
+ CBCentralManagerScanOptionAllowDuplicatesKey: false
155
+ ])
156
+ }
157
+
158
+ func stopScan() {
159
+ centralManager?.stopScan()
160
+ scanBridge = nil
161
+ }
162
+
163
+ func connect(deviceId: String, bridge: NativeBridge?, callback: @escaping (Any?, String?) -> Void) {
164
+ guard let peripheral = discoveredPeripherals[deviceId] else {
165
+ callback(nil, "Device not found: \(deviceId)"); return
166
+ }
167
+ connectCallbacks[deviceId] = callback
168
+ scanBridge = WeakBridge(bridge: bridge)
169
+ peripheral.delegate = self
170
+ centralManager?.connect(peripheral, options: nil)
171
+ }
172
+
173
+ func disconnect(deviceId: String, callback: @escaping (Any?, String?) -> Void) {
174
+ guard let peripheral = connectedPeripherals[deviceId] else {
175
+ callback(nil, "Device not connected: \(deviceId)"); return
176
+ }
177
+ centralManager?.cancelPeripheralConnection(peripheral)
178
+ callback(nil, nil)
179
+ }
180
+
181
+ func readCharacteristic(deviceId: String, serviceUUID: String, charUUID: String, callback: @escaping (Any?, String?) -> Void) {
182
+ guard let peripheral = connectedPeripherals[deviceId] else {
183
+ callback(nil, "Device not connected: \(deviceId)"); return
184
+ }
185
+ guard let char = findCharacteristic(peripheral: peripheral, serviceUUID: serviceUUID, charUUID: charUUID) else {
186
+ callback(nil, "Characteristic not found: \(charUUID)"); return
187
+ }
188
+ let key = "\(deviceId):\(serviceUUID):\(charUUID)"
189
+ readCallbacks[key] = callback
190
+ peripheral.readValue(for: char)
191
+ }
192
+
193
+ func writeCharacteristic(deviceId: String, serviceUUID: String, charUUID: String, dataBase64: String, callback: @escaping (Any?, String?) -> Void) {
194
+ guard let peripheral = connectedPeripherals[deviceId] else {
195
+ callback(nil, "Device not connected: \(deviceId)"); return
196
+ }
197
+ guard let char = findCharacteristic(peripheral: peripheral, serviceUUID: serviceUUID, charUUID: charUUID) else {
198
+ callback(nil, "Characteristic not found: \(charUUID)"); return
199
+ }
200
+ guard let data = Data(base64Encoded: dataBase64) else {
201
+ callback(nil, "Invalid base64 data"); return
202
+ }
203
+ let key = "\(deviceId):\(serviceUUID):\(charUUID)"
204
+ writeCallbacks[key] = callback
205
+ let writeType: CBCharacteristicWriteType = char.properties.contains(.writeWithoutResponse) ? .withoutResponse : .withResponse
206
+ peripheral.writeValue(data, for: char, type: writeType)
207
+ if writeType == .withoutResponse {
208
+ writeCallbacks.removeValue(forKey: key)
209
+ callback(nil, nil)
210
+ }
211
+ }
212
+
213
+ func subscribeToCharacteristic(deviceId: String, serviceUUID: String, charUUID: String, bridge: NativeBridge?, callback: @escaping (Any?, String?) -> Void) {
214
+ guard let peripheral = connectedPeripherals[deviceId] else {
215
+ callback(nil, "Device not connected: \(deviceId)"); return
216
+ }
217
+ guard let char = findCharacteristic(peripheral: peripheral, serviceUUID: serviceUUID, charUUID: charUUID) else {
218
+ callback(nil, "Characteristic not found: \(charUUID)"); return
219
+ }
220
+ let key = "\(deviceId):\(serviceUUID):\(charUUID)"
221
+ subscribeBridges[key] = WeakBridge(bridge: bridge)
222
+ peripheral.setNotifyValue(true, for: char)
223
+ callback(nil, nil)
224
+ }
225
+
226
+ func unsubscribeFromCharacteristic(deviceId: String, serviceUUID: String, charUUID: String, callback: @escaping (Any?, String?) -> Void) {
227
+ guard let peripheral = connectedPeripherals[deviceId] else {
228
+ callback(nil, "Device not connected: \(deviceId)"); return
229
+ }
230
+ guard let char = findCharacteristic(peripheral: peripheral, serviceUUID: serviceUUID, charUUID: charUUID) else {
231
+ callback(nil, "Characteristic not found: \(charUUID)"); return
232
+ }
233
+ let key = "\(deviceId):\(serviceUUID):\(charUUID)"
234
+ subscribeBridges.removeValue(forKey: key)
235
+ peripheral.setNotifyValue(false, for: char)
236
+ callback(nil, nil)
237
+ }
238
+
239
+ // MARK: Helpers
240
+
241
+ private func findCharacteristic(peripheral: CBPeripheral, serviceUUID: String, charUUID: String) -> CBCharacteristic? {
242
+ let sUUID = CBUUID(string: serviceUUID)
243
+ let cUUID = CBUUID(string: charUUID)
244
+ guard let service = peripheral.services?.first(where: { $0.uuid == sUUID }) else { return nil }
245
+ return service.characteristics?.first(where: { $0.uuid == cUUID })
246
+ }
247
+
248
+ private func stateString(_ state: CBManagerState) -> String {
249
+ switch state {
250
+ case .poweredOn: return "poweredOn"
251
+ case .poweredOff: return "poweredOff"
252
+ case .unauthorized: return "unauthorized"
253
+ case .unsupported: return "unsupported"
254
+ case .resetting: return "resetting"
255
+ case .unknown: return "unknown"
256
+ @unknown default: return "unknown"
257
+ }
258
+ }
259
+
260
+ private func peripheralId(_ peripheral: CBPeripheral) -> String {
261
+ peripheral.identifier.uuidString
262
+ }
263
+
264
+ // MARK: CBCentralManagerDelegate
265
+
266
+ nonisolated func centralManagerDidUpdateState(_ central: CBCentralManager) {
267
+ Task { @MainActor in
268
+ let state = self.stateString(central.state)
269
+ self.scanBridge?.bridge?.dispatchGlobalEvent("ble:stateChanged", payload: ["state": state])
270
+ }
271
+ }
272
+
273
+ nonisolated func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) {
274
+ Task { @MainActor in
275
+ let id = self.peripheralId(peripheral)
276
+ self.discoveredPeripherals[id] = peripheral
277
+ let payload: [String: Any] = [
278
+ "id": id,
279
+ "name": peripheral.name ?? "",
280
+ "rssi": RSSI.intValue,
281
+ ]
282
+ self.scanBridge?.bridge?.dispatchGlobalEvent("ble:deviceFound", payload: payload)
283
+ }
284
+ }
285
+
286
+ nonisolated func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
287
+ Task { @MainActor in
288
+ let id = self.peripheralId(peripheral)
289
+ self.connectedPeripherals[id] = peripheral
290
+ peripheral.discoverServices(nil)
291
+ let payload: [String: Any] = ["id": id, "name": peripheral.name ?? ""]
292
+ self.scanBridge?.bridge?.dispatchGlobalEvent("ble:connected", payload: payload)
293
+ if let cb = self.connectCallbacks.removeValue(forKey: id) {
294
+ cb(payload, nil)
295
+ }
296
+ }
297
+ }
298
+
299
+ nonisolated func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
300
+ Task { @MainActor in
301
+ let id = self.peripheralId(peripheral)
302
+ self.connectedPeripherals.removeValue(forKey: id)
303
+ let payload: [String: Any] = ["id": id, "name": peripheral.name ?? ""]
304
+ self.scanBridge?.bridge?.dispatchGlobalEvent("ble:disconnected", payload: payload)
305
+ }
306
+ }
307
+
308
+ nonisolated func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
309
+ Task { @MainActor in
310
+ let id = self.peripheralId(peripheral)
311
+ let msg = error?.localizedDescription ?? "Connection failed"
312
+ if let cb = self.connectCallbacks.removeValue(forKey: id) {
313
+ cb(nil, msg)
314
+ }
315
+ self.scanBridge?.bridge?.dispatchGlobalEvent("ble:error", payload: ["message": msg, "deviceId": id])
316
+ }
317
+ }
318
+
319
+ // MARK: CBPeripheralDelegate
320
+
321
+ nonisolated func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
322
+ guard error == nil else { return }
323
+ Task { @MainActor in
324
+ for service in peripheral.services ?? [] {
325
+ peripheral.discoverCharacteristics(nil, for: service)
326
+ }
327
+ }
328
+ }
329
+
330
+ nonisolated func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
331
+ // Characteristics are now available for read/write/subscribe
332
+ }
333
+
334
+ nonisolated func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
335
+ Task { @MainActor in
336
+ let id = self.peripheralId(peripheral)
337
+ let serviceUUID = characteristic.service?.uuid.uuidString ?? ""
338
+ let charUUID = characteristic.uuid.uuidString
339
+ let key = "\(id):\(serviceUUID):\(charUUID)"
340
+ let valueBase64 = characteristic.value?.base64EncodedString() ?? ""
341
+
342
+ // One-shot read callback
343
+ if let cb = self.readCallbacks.removeValue(forKey: key) {
344
+ if let err = error {
345
+ cb(nil, err.localizedDescription)
346
+ } else {
347
+ cb(["value": valueBase64, "characteristicUUID": charUUID, "serviceUUID": serviceUUID], nil)
348
+ }
349
+ }
350
+
351
+ // Subscription notification
352
+ if let wb = self.subscribeBridges[key] {
353
+ wb.bridge?.dispatchGlobalEvent("ble:characteristicChanged", payload: [
354
+ "deviceId": id,
355
+ "serviceUUID": serviceUUID,
356
+ "characteristicUUID": charUUID,
357
+ "value": valueBase64,
358
+ ])
359
+ }
360
+ }
361
+ }
362
+
363
+ nonisolated func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
364
+ Task { @MainActor in
365
+ let id = self.peripheralId(peripheral)
366
+ let serviceUUID = characteristic.service?.uuid.uuidString ?? ""
367
+ let charUUID = characteristic.uuid.uuidString
368
+ let key = "\(id):\(serviceUUID):\(charUUID)"
369
+ if let cb = self.writeCallbacks.removeValue(forKey: key) {
370
+ if let err = error {
371
+ cb(nil, err.localizedDescription)
372
+ } else {
373
+ cb(nil, nil)
374
+ }
375
+ }
376
+ }
377
+ }
378
+ }
379
+ #endif
@@ -0,0 +1,154 @@
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
+ #endif