@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,181 @@
1
+ package com.vuenative.core
2
+
3
+ import android.Manifest
4
+ import android.app.NotificationChannel
5
+ import android.app.NotificationManager
6
+ import android.content.Context
7
+ import android.content.pm.PackageManager
8
+ import android.os.Build
9
+ import android.os.Handler
10
+ import android.os.Looper
11
+ import androidx.core.app.ActivityCompat
12
+ import androidx.core.app.NotificationCompat
13
+ import androidx.core.app.NotificationManagerCompat
14
+
15
+ /**
16
+ * Native module for local and remote (push) notifications.
17
+ *
18
+ * For push notifications, the host app must:
19
+ * 1. Add Firebase Messaging dependency to their app-level build.gradle
20
+ * 2. Create a FirebaseMessagingService subclass that calls
21
+ * NotificationsModule.onNewToken() and onPushReceived()
22
+ *
23
+ * Methods:
24
+ * - requestPermission() -> { status: "granted"|"denied" }
25
+ * - scheduleLocal(opts) -> { id }
26
+ * - cancel(id)
27
+ * - cancelAll()
28
+ * - registerForPush() -> true (no-op on Android; FCM auto-registers)
29
+ * - getToken() -> String? (returns cached FCM token)
30
+ *
31
+ * Global events:
32
+ * "notification:received" -- local notification tapped
33
+ * "push:token" { token }
34
+ * "push:received" { title, body, data, remote: true }
35
+ */
36
+ class NotificationsModule : NativeModule {
37
+ override val moduleName = "Notifications"
38
+
39
+ private var context: Context? = null
40
+ private var bridge: NativeBridge? = null
41
+ private val handler = Handler(Looper.getMainLooper())
42
+ private var notifIdCounter = 1
43
+
44
+ companion object {
45
+ private const val CHANNEL_ID = "vue_native_default"
46
+
47
+ /** Singleton reference so FirebaseMessagingService can call into this module. */
48
+ @Volatile
49
+ var instance: NotificationsModule? = null
50
+ private set
51
+ }
52
+
53
+ override fun initialize(context: Context, bridge: NativeBridge) {
54
+ this.context = context
55
+ this.bridge = bridge
56
+ instance = this
57
+ createDefaultChannel(context)
58
+ }
59
+
60
+ private fun createDefaultChannel(ctx: Context) {
61
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
62
+ val channel = NotificationChannel(
63
+ CHANNEL_ID,
64
+ "Notifications",
65
+ NotificationManager.IMPORTANCE_DEFAULT
66
+ ).apply {
67
+ description = "Vue Native app notifications"
68
+ }
69
+ ctx.getSystemService(NotificationManager::class.java)
70
+ ?.createNotificationChannel(channel)
71
+ }
72
+ }
73
+
74
+ // -------------------------------------------------------------------------
75
+ // Push token handling (called from FirebaseMessagingService in host app)
76
+ // -------------------------------------------------------------------------
77
+
78
+ /** Cached FCM token. Volatile because onNewToken() is called from FCM background thread
79
+ * while getToken() may be called from the module invocation thread. */
80
+ @Volatile
81
+ private var fcmToken: String? = null
82
+
83
+ /**
84
+ * Called by the host app's FirebaseMessagingService.onNewToken().
85
+ */
86
+ fun onNewToken(token: String) {
87
+ fcmToken = token
88
+ bridge?.dispatchGlobalEvent("push:token", mapOf("token" to token))
89
+ }
90
+
91
+ /**
92
+ * Called by the host app's FirebaseMessagingService.onMessageReceived().
93
+ */
94
+ fun onPushReceived(title: String, body: String, data: Map<String, String>) {
95
+ bridge?.dispatchGlobalEvent("push:received", mapOf(
96
+ "title" to title,
97
+ "body" to body,
98
+ "data" to data,
99
+ "remote" to true
100
+ ))
101
+ }
102
+
103
+ // -------------------------------------------------------------------------
104
+ // Module invocation
105
+ // -------------------------------------------------------------------------
106
+
107
+ override fun invoke(
108
+ method: String,
109
+ args: List<Any?>,
110
+ bridge: NativeBridge,
111
+ callback: (Any?, String?) -> Unit
112
+ ) {
113
+ when (method) {
114
+ "requestPermission" -> {
115
+ // Android <13: no runtime permission needed for notifications
116
+ // Android 13+: POST_NOTIFICATIONS must be granted via PermissionsModule
117
+ val granted = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
118
+ val ctx = context ?: run { callback(null, "Not initialized"); return }
119
+ ActivityCompat.checkSelfPermission(ctx, Manifest.permission.POST_NOTIFICATIONS) ==
120
+ PackageManager.PERMISSION_GRANTED
121
+ } else {
122
+ true
123
+ }
124
+ callback(mapOf("status" to if (granted) "granted" else "denied"), null)
125
+ }
126
+ "scheduleLocal" -> {
127
+ val ctx = context ?: run { callback(null, "Not initialized"); return }
128
+ val opts = args.getOrNull(0) as? Map<*, *>
129
+ ?: run { callback(null, "Invalid args — expected options object"); return }
130
+
131
+ val title = opts["title"]?.toString() ?: ""
132
+ val body = opts["body"]?.toString() ?: ""
133
+ val delaySeconds = (opts["delay"] as? Number)?.toLong() ?: 0L
134
+ val notifId = notifIdCounter++
135
+
136
+ val show = Runnable {
137
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU ||
138
+ ActivityCompat.checkSelfPermission(ctx, Manifest.permission.POST_NOTIFICATIONS)
139
+ == PackageManager.PERMISSION_GRANTED
140
+ ) {
141
+ val notification = NotificationCompat.Builder(ctx, CHANNEL_ID)
142
+ .setSmallIcon(android.R.drawable.ic_dialog_info)
143
+ .setContentTitle(title)
144
+ .setContentText(body)
145
+ .setPriority(NotificationCompat.PRIORITY_DEFAULT)
146
+ .setAutoCancel(true)
147
+ .build()
148
+ NotificationManagerCompat.from(ctx).notify(notifId, notification)
149
+ }
150
+ }
151
+
152
+ if (delaySeconds > 0) {
153
+ handler.postDelayed(show, delaySeconds * 1000L)
154
+ } else {
155
+ show.run()
156
+ }
157
+ callback(mapOf("id" to notifId), null)
158
+ }
159
+ "cancel" -> {
160
+ val ctx = context ?: run { callback(null, "Not initialized"); return }
161
+ val id = (args.getOrNull(0) as? Number)?.toInt()
162
+ ?: run { callback(null, "Invalid args — expected notification id"); return }
163
+ NotificationManagerCompat.from(ctx).cancel(id)
164
+ callback(null, null)
165
+ }
166
+ "cancelAll" -> {
167
+ val ctx = context ?: run { callback(null, "Not initialized"); return }
168
+ NotificationManagerCompat.from(ctx).cancelAll()
169
+ callback(null, null)
170
+ }
171
+ "registerForPush" -> {
172
+ // On Android, FCM auto-registers. This is a no-op for API parity with iOS.
173
+ callback(true, null)
174
+ }
175
+ "getToken" -> {
176
+ callback(fcmToken, null)
177
+ }
178
+ else -> callback(null, "Unknown method: $method")
179
+ }
180
+ }
181
+ }
@@ -0,0 +1,255 @@
1
+ package com.vuenative.core
2
+
3
+ import android.content.Context
4
+ import android.content.SharedPreferences
5
+ import android.util.Log
6
+ import okhttp3.*
7
+ import java.io.File
8
+ import java.io.FileOutputStream
9
+ import java.io.IOException
10
+ import java.security.MessageDigest
11
+
12
+ /**
13
+ * Native module for Over-The-Air (OTA) JS bundle updates.
14
+ *
15
+ * Methods:
16
+ * - checkForUpdate(serverUrl) — check for available updates
17
+ * - downloadUpdate(url, hash) — download a new bundle and verify integrity
18
+ * - applyUpdate() — swap to downloaded bundle on next launch
19
+ * - rollback() — revert to the embedded bundle
20
+ * - getCurrentVersion() — get current bundle version info
21
+ *
22
+ * Events:
23
+ * - ota:downloadProgress — payload: { progress, bytesDownloaded, totalBytes }
24
+ */
25
+ class OTAModule : NativeModule {
26
+ override val moduleName = "OTA"
27
+ private var appContext: Context? = null
28
+ private var bridgeRef: NativeBridge? = null
29
+ private var prefs: SharedPreferences? = null
30
+ private val client = OkHttpClient()
31
+
32
+ private val KEY_PREFIX = "vue_native_ota_"
33
+ private val KEY_CURRENT_VERSION = "${KEY_PREFIX}current_version"
34
+ private val KEY_BUNDLE_PATH = "${KEY_PREFIX}bundle_path"
35
+ private val KEY_PREVIOUS_BUNDLE_PATH = "${KEY_PREFIX}previous_bundle_path"
36
+ private val KEY_PREVIOUS_VERSION = "${KEY_PREFIX}previous_version"
37
+ private val KEY_PENDING_BUNDLE_PATH = "${KEY_PREFIX}pending_bundle_path"
38
+
39
+ override fun initialize(context: Context, bridge: NativeBridge) {
40
+ appContext = context.applicationContext
41
+ bridgeRef = bridge
42
+ prefs = context.getSharedPreferences("vue_native_ota", Context.MODE_PRIVATE)
43
+ }
44
+
45
+ override fun invoke(method: String, args: List<Any?>, bridge: NativeBridge, callback: (Any?, String?) -> Unit) {
46
+ val p = prefs ?: run { callback(null, "OTA not initialized"); return }
47
+
48
+ when (method) {
49
+ "checkForUpdate" -> {
50
+ val serverUrl = args.getOrNull(0)?.toString()
51
+ ?: run { callback(null, "checkForUpdate: missing serverUrl"); return }
52
+ checkForUpdate(serverUrl, p, callback)
53
+ }
54
+ "downloadUpdate" -> {
55
+ val url = args.getOrNull(0)?.toString()
56
+ ?: run { callback(null, "downloadUpdate: missing url"); return }
57
+ val expectedHash = args.getOrNull(1)?.toString()
58
+ downloadUpdate(url, expectedHash, p, callback)
59
+ }
60
+ "applyUpdate" -> applyUpdate(p, callback)
61
+ "rollback" -> rollback(p, callback)
62
+ "getCurrentVersion" -> getCurrentVersion(p, callback)
63
+ else -> callback(null, "OTAModule: Unknown method '$method'")
64
+ }
65
+ }
66
+
67
+ private fun checkForUpdate(serverUrl: String, prefs: SharedPreferences, callback: (Any?, String?) -> Unit) {
68
+ val currentVersion = prefs.getString(KEY_CURRENT_VERSION, "0") ?: "0"
69
+
70
+ val request = Request.Builder()
71
+ .url(serverUrl)
72
+ .header("X-Current-Version", currentVersion)
73
+ .header("X-Platform", "android")
74
+ .header("X-App-Id", appContext?.packageName ?: "unknown")
75
+ .get()
76
+ .build()
77
+
78
+ client.newCall(request).enqueue(object : Callback {
79
+ override fun onFailure(call: Call, e: IOException) {
80
+ callback(null, "Network error: ${e.message}")
81
+ }
82
+
83
+ override fun onResponse(call: Call, response: Response) {
84
+ try {
85
+ val body = response.body?.string() ?: run {
86
+ callback(null, "Empty response from update server")
87
+ return
88
+ }
89
+
90
+ val json = org.json.JSONObject(body)
91
+ val result = mapOf(
92
+ "updateAvailable" to (json.optBoolean("updateAvailable", false)),
93
+ "version" to json.optString("version", ""),
94
+ "downloadUrl" to json.optString("downloadUrl", ""),
95
+ "hash" to json.optString("hash", ""),
96
+ "size" to json.optInt("size", 0),
97
+ "releaseNotes" to json.optString("releaseNotes", ""),
98
+ )
99
+ callback(result, null)
100
+ } catch (e: Exception) {
101
+ callback(null, "Failed to parse update response: ${e.message}")
102
+ }
103
+ }
104
+ })
105
+ }
106
+
107
+ private fun downloadUpdate(
108
+ url: String,
109
+ expectedHash: String?,
110
+ prefs: SharedPreferences,
111
+ callback: (Any?, String?) -> Unit
112
+ ) {
113
+ val request = Request.Builder().url(url).build()
114
+
115
+ client.newCall(request).enqueue(object : Callback {
116
+ override fun onFailure(call: Call, e: IOException) {
117
+ callback(null, "Download failed: ${e.message}")
118
+ }
119
+
120
+ override fun onResponse(call: Call, response: Response) {
121
+ try {
122
+ val body = response.body ?: run {
123
+ callback(null, "Download failed: empty response")
124
+ return
125
+ }
126
+
127
+ val totalBytes = body.contentLength()
128
+ val ctx = appContext ?: run {
129
+ callback(null, "Context not available")
130
+ return
131
+ }
132
+
133
+ val otaDir = File(ctx.filesDir, "VueNativeOTA")
134
+ otaDir.mkdirs()
135
+ val bundleFile = File(otaDir, "bundle.js")
136
+
137
+ val source = body.source()
138
+ val outputStream = FileOutputStream(bundleFile)
139
+ val buffer = ByteArray(8192)
140
+ var bytesDownloaded = 0L
141
+
142
+ while (true) {
143
+ val read = source.read(buffer)
144
+ if (read == -1) break
145
+ outputStream.write(buffer, 0, read)
146
+ bytesDownloaded += read
147
+
148
+ val progress = if (totalBytes > 0) bytesDownloaded.toDouble() / totalBytes else 0.0
149
+ bridgeRef?.dispatchGlobalEvent("ota:downloadProgress", mapOf(
150
+ "progress" to progress,
151
+ "bytesDownloaded" to bytesDownloaded,
152
+ "totalBytes" to totalBytes,
153
+ ))
154
+ }
155
+
156
+ outputStream.close()
157
+ source.close()
158
+
159
+ // Verify hash if provided
160
+ if (!expectedHash.isNullOrEmpty()) {
161
+ val actualHash = sha256(bundleFile)
162
+ if (!actualHash.equals(expectedHash, ignoreCase = true)) {
163
+ bundleFile.delete()
164
+ callback(null, "Bundle integrity check failed. Expected: $expectedHash, got: $actualHash")
165
+ return
166
+ }
167
+ }
168
+
169
+ prefs.edit().putString(KEY_PENDING_BUNDLE_PATH, bundleFile.absolutePath).apply()
170
+
171
+ callback(mapOf(
172
+ "path" to bundleFile.absolutePath,
173
+ "size" to bytesDownloaded,
174
+ ), null)
175
+ } catch (e: Exception) {
176
+ callback(null, "Failed to save bundle: ${e.message}")
177
+ }
178
+ }
179
+ })
180
+ }
181
+
182
+ private fun applyUpdate(prefs: SharedPreferences, callback: (Any?, String?) -> Unit) {
183
+ val pendingPath = prefs.getString(KEY_PENDING_BUNDLE_PATH, null)
184
+ if (pendingPath == null || !File(pendingPath).exists()) {
185
+ callback(null, "No pending update to apply")
186
+ return
187
+ }
188
+
189
+ val editor = prefs.edit()
190
+
191
+ // Save current for rollback
192
+ val currentPath = prefs.getString(KEY_BUNDLE_PATH, null)
193
+ val currentVersion = prefs.getString(KEY_CURRENT_VERSION, null)
194
+ if (currentPath != null) editor.putString(KEY_PREVIOUS_BUNDLE_PATH, currentPath)
195
+ if (currentVersion != null) editor.putString(KEY_PREVIOUS_VERSION, currentVersion)
196
+
197
+ // Set new bundle as current
198
+ editor.putString(KEY_BUNDLE_PATH, pendingPath)
199
+ editor.remove(KEY_PENDING_BUNDLE_PATH)
200
+
201
+ // Increment version
202
+ val version = (prefs.getString(KEY_CURRENT_VERSION, "0")?.toIntOrNull() ?: 0) + 1
203
+ editor.putString(KEY_CURRENT_VERSION, version.toString())
204
+
205
+ editor.apply()
206
+
207
+ callback(mapOf("applied" to true), null)
208
+ }
209
+
210
+ private fun rollback(prefs: SharedPreferences, callback: (Any?, String?) -> Unit) {
211
+ val editor = prefs.edit()
212
+ val previousPath = prefs.getString(KEY_PREVIOUS_BUNDLE_PATH, null)
213
+
214
+ if (previousPath != null) {
215
+ editor.putString(KEY_BUNDLE_PATH, previousPath)
216
+ val prevVersion = prefs.getString(KEY_PREVIOUS_VERSION, null)
217
+ if (prevVersion != null) editor.putString(KEY_CURRENT_VERSION, prevVersion)
218
+ editor.remove(KEY_PREVIOUS_BUNDLE_PATH)
219
+ editor.remove(KEY_PREVIOUS_VERSION)
220
+ editor.apply()
221
+ callback(mapOf("rolledBack" to true, "toEmbedded" to false), null)
222
+ } else {
223
+ // Rollback to embedded
224
+ editor.remove(KEY_BUNDLE_PATH)
225
+ editor.remove(KEY_CURRENT_VERSION)
226
+ editor.apply()
227
+ callback(mapOf("rolledBack" to true, "toEmbedded" to true), null)
228
+ }
229
+ }
230
+
231
+ private fun getCurrentVersion(prefs: SharedPreferences, callback: (Any?, String?) -> Unit) {
232
+ val version = prefs.getString(KEY_CURRENT_VERSION, "embedded") ?: "embedded"
233
+ val bundlePath = prefs.getString(KEY_BUNDLE_PATH, null)
234
+ val isUsingOTA = bundlePath != null && File(bundlePath).exists()
235
+
236
+ callback(mapOf(
237
+ "version" to version,
238
+ "isUsingOTA" to isUsingOTA,
239
+ "bundlePath" to (bundlePath ?: ""),
240
+ ), null)
241
+ }
242
+
243
+ private fun sha256(file: File): String {
244
+ val digest = MessageDigest.getInstance("SHA-256")
245
+ file.inputStream().use { input ->
246
+ val buffer = ByteArray(8192)
247
+ while (true) {
248
+ val read = input.read(buffer)
249
+ if (read == -1) break
250
+ digest.update(buffer, 0, read)
251
+ }
252
+ }
253
+ return digest.digest().joinToString("") { "%02x".format(it) }
254
+ }
255
+ }
@@ -0,0 +1,147 @@
1
+ package com.vuenative.core
2
+
3
+ import android.content.Context
4
+ import android.os.Handler
5
+ import android.os.Looper
6
+ import android.view.Choreographer
7
+
8
+ /**
9
+ * Native module for performance profiling.
10
+ * Tracks FPS via Choreographer, memory usage via Runtime, and bridge operation counts.
11
+ * Dispatches `perf:metrics` global events every 1 second while profiling is active.
12
+ */
13
+ class PerformanceModule : NativeModule {
14
+ override val moduleName = "Performance"
15
+
16
+ private var bridge: NativeBridge? = null
17
+ private val mainHandler = Handler(Looper.getMainLooper())
18
+ private var isProfiling = false
19
+
20
+ // FPS tracking
21
+ private var frameCount = 0
22
+ private var lastFrameTimeNanos = 0L
23
+ private var currentFPS = 0.0
24
+
25
+ // Bridge operation count
26
+ private var bridgeOpsCount = 0
27
+
28
+ // Metrics timer
29
+ private var metricsRunnable: Runnable? = null
30
+
31
+ // Choreographer callback
32
+ private var frameCallback: Choreographer.FrameCallback? = null
33
+
34
+ override fun initialize(context: Context, bridge: NativeBridge) {
35
+ this.bridge = bridge
36
+ }
37
+
38
+ override fun invoke(
39
+ method: String,
40
+ args: List<Any?>,
41
+ bridge: NativeBridge,
42
+ callback: (result: Any?, error: String?) -> Unit
43
+ ) {
44
+ when (method) {
45
+ "startProfiling" -> startProfiling(callback)
46
+ "stopProfiling" -> stopProfiling(callback)
47
+ "getMetrics" -> callback(collectMetrics(), null)
48
+ else -> callback(null, "PerformanceModule: unknown method '$method'")
49
+ }
50
+ }
51
+
52
+ // ── Start / Stop ──────────────────────────────────────────────────────
53
+
54
+ private fun startProfiling(callback: (Any?, String?) -> Unit) {
55
+ if (isProfiling) { callback(true, null); return }
56
+ isProfiling = true
57
+ frameCount = 0
58
+ lastFrameTimeNanos = 0
59
+ currentFPS = 0.0
60
+ bridgeOpsCount = 0
61
+
62
+ mainHandler.post {
63
+ // Choreographer for FPS measurement
64
+ frameCallback = object : Choreographer.FrameCallback {
65
+ override fun doFrame(frameTimeNanos: Long) {
66
+ if (!isProfiling) return
67
+
68
+ if (lastFrameTimeNanos == 0L) {
69
+ lastFrameTimeNanos = frameTimeNanos
70
+ frameCount = 0
71
+ } else {
72
+ frameCount++
73
+ val elapsedNanos = frameTimeNanos - lastFrameTimeNanos
74
+ val elapsedSeconds = elapsedNanos / 1_000_000_000.0
75
+
76
+ // Calculate FPS every 0.5 seconds
77
+ if (elapsedSeconds >= 0.5) {
78
+ currentFPS = frameCount / elapsedSeconds
79
+ frameCount = 0
80
+ lastFrameTimeNanos = frameTimeNanos
81
+ }
82
+ }
83
+
84
+ Choreographer.getInstance().postFrameCallback(this)
85
+ }
86
+ }
87
+ Choreographer.getInstance().postFrameCallback(frameCallback!!)
88
+
89
+ // Periodic metrics dispatch (every 1 second)
90
+ metricsRunnable = object : Runnable {
91
+ override fun run() {
92
+ if (!isProfiling) return
93
+ dispatchMetrics()
94
+ mainHandler.postDelayed(this, 1000)
95
+ }
96
+ }
97
+ mainHandler.postDelayed(metricsRunnable!!, 1000)
98
+ }
99
+
100
+ callback(true, null)
101
+ }
102
+
103
+ private fun stopProfiling(callback: (Any?, String?) -> Unit) {
104
+ if (!isProfiling) { callback(true, null); return }
105
+ isProfiling = false
106
+
107
+ mainHandler.post {
108
+ frameCallback?.let { Choreographer.getInstance().removeFrameCallback(it) }
109
+ frameCallback = null
110
+ metricsRunnable?.let { mainHandler.removeCallbacks(it) }
111
+ metricsRunnable = null
112
+ }
113
+
114
+ callback(true, null)
115
+ }
116
+
117
+ // ── Metrics collection ────────────────────────────────────────────────
118
+
119
+ private fun collectMetrics(): Map<String, Any> {
120
+ val runtime = Runtime.getRuntime()
121
+ val usedMemory = (runtime.totalMemory() - runtime.freeMemory()).toDouble() / (1024 * 1024)
122
+
123
+ return mapOf(
124
+ "fps" to Math.round(currentFPS * 10.0) / 10.0,
125
+ "memoryMB" to Math.round(usedMemory * 100.0) / 100.0,
126
+ "bridgeOps" to bridgeOpsCount,
127
+ "timestamp" to System.currentTimeMillis()
128
+ )
129
+ }
130
+
131
+ private fun dispatchMetrics() {
132
+ if (!isProfiling) return
133
+ bridgeOpsCount++
134
+ val metrics = collectMetrics()
135
+ bridge?.dispatchGlobalEvent("perf:metrics", metrics)
136
+ }
137
+
138
+ override fun destroy() {
139
+ isProfiling = false
140
+ mainHandler.post {
141
+ frameCallback?.let { Choreographer.getInstance().removeFrameCallback(it) }
142
+ frameCallback = null
143
+ metricsRunnable?.let { mainHandler.removeCallbacks(it) }
144
+ metricsRunnable = null
145
+ }
146
+ }
147
+ }