@thelacanians/vue-native-cli 0.4.2 → 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 +43 -23
  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,207 @@
1
+ package com.vuenative.core
2
+
3
+ import android.content.Context
4
+ import android.os.Handler
5
+ import android.os.HandlerThread
6
+ import android.os.Looper
7
+ import android.util.Log
8
+ import com.eclipsesource.v8.V8
9
+ import com.eclipsesource.v8.JavaVoidCallback
10
+
11
+ /**
12
+ * Core JavaScript runtime. Wraps J2V8's V8 engine on a dedicated HandlerThread.
13
+ *
14
+ * Thread safety contract:
15
+ * - All V8 access happens exclusively on jsThread via jsHandler
16
+ * - Never pass J2V8 objects (V8Array, V8Object) across threads
17
+ * - All View operations happen on main thread via mainHandler
18
+ */
19
+ class JSRuntime(private val context: Context) {
20
+
21
+ companion object {
22
+ private const val TAG = "VueNative-JSRuntime"
23
+ }
24
+
25
+ /** Dedicated JS thread. All V8 operations run here. */
26
+ private val jsThread = HandlerThread("VueNative-JS").apply { start() }
27
+
28
+ /** Handler for posting work to the JS thread. */
29
+ val jsHandler = Handler(jsThread.looper)
30
+
31
+ /** Handler for posting work to the main (UI) thread. */
32
+ private val mainHandler = Handler(Looper.getMainLooper())
33
+
34
+ /** V8 runtime instance. Only access from jsThread. */
35
+ private var v8: V8? = null
36
+
37
+ /** Whether the runtime has been initialized. */
38
+ private var isInitialized = false
39
+
40
+ /** The NativeBridge instance — manages view registry and operations. */
41
+ val bridge = NativeBridge(context)
42
+
43
+ /** Startup time in milliseconds for performance.now(). */
44
+ val startTimeMs: Long = System.currentTimeMillis()
45
+
46
+ init {
47
+ // Wire bridge callbacks
48
+ bridge.onFireEvent = { nodeId, eventName, payloadJson ->
49
+ // Called on main thread — dispatch to JS
50
+ jsHandler.post {
51
+ try {
52
+ if (nodeId == -1 && eventName == "__callback__") {
53
+ // Native module async callback — route to __VN_resolveCallback
54
+ v8?.executeVoidScript(
55
+ "if(typeof __VN_resolveCallback==='function'){" +
56
+ "var _d=$payloadJson;" +
57
+ "__VN_resolveCallback(_d.callbackId,_d.result,_d.error);}"
58
+ )
59
+ } else {
60
+ v8?.executeVoidScript(
61
+ "if(typeof __VN_handleEvent==='function')" +
62
+ "__VN_handleEvent($nodeId,${encodeJs(eventName)},$payloadJson)"
63
+ )
64
+ }
65
+ } catch (e: Exception) {
66
+ Log.e(TAG, "Error dispatching event $eventName to JS", e)
67
+ }
68
+ }
69
+ }
70
+ bridge.onDispatchGlobalEvent = { eventName, payloadJson ->
71
+ jsHandler.post {
72
+ try {
73
+ v8?.executeVoidScript(
74
+ "if(typeof __VN_handleGlobalEvent==='function')" +
75
+ "__VN_handleGlobalEvent(${encodeJs(eventName)},${encodeJs(payloadJson)})"
76
+ )
77
+ } catch (e: Exception) {
78
+ Log.e(TAG, "Error dispatching global event $eventName", e)
79
+ }
80
+ }
81
+ }
82
+ }
83
+
84
+ /** Initialize the V8 runtime on the JS thread. Calls completion when ready. */
85
+ fun initialize(completion: (() -> Unit)? = null) {
86
+ jsHandler.post {
87
+ if (isInitialized) {
88
+ mainHandler.post { completion?.invoke() }
89
+ return@post
90
+ }
91
+ try {
92
+ v8 = V8.createV8Runtime()
93
+ JSPolyfills.register(this)
94
+ // Register __VN_flushOperations — JS calls this to send batched ops to native
95
+ v8?.registerJavaMethod(JavaVoidCallback { _, params ->
96
+ try {
97
+ val json = if (params.length() > 0) params.getString(0) else "[]"
98
+ bridge.processOperations(json)
99
+ } finally {
100
+ params.close()
101
+ }
102
+ }, "__VN_flushOperations")
103
+
104
+ // Register __VN_handleError — JS calls this to report errors to native
105
+ v8?.registerJavaMethod(JavaVoidCallback { _, params ->
106
+ try {
107
+ val errorJson = if (params.length() > 0) params.getString(0) else "{}"
108
+ Log.e(TAG, "[VueNative Error] $errorJson")
109
+ } finally {
110
+ params.close()
111
+ }
112
+ }, "__VN_handleError")
113
+
114
+ isInitialized = true
115
+ Log.d(TAG, "V8 runtime initialized")
116
+ mainHandler.post { completion?.invoke() }
117
+ } catch (e: Exception) {
118
+ Log.e(TAG, "Failed to initialize V8 runtime", e)
119
+ }
120
+ }
121
+ }
122
+
123
+ /** Load and execute a JavaScript bundle. Must be called after initialize().
124
+ * @param onComplete Optional callback invoked on main thread: (success, errorMessage). */
125
+ fun loadBundle(bundleCode: String, onComplete: ((Boolean, String?) -> Unit)? = null) {
126
+ jsHandler.post {
127
+ try {
128
+ v8?.executeVoidScript(bundleCode)
129
+ Log.d(TAG, "Bundle loaded successfully")
130
+ mainHandler.post { onComplete?.invoke(true, null) }
131
+ } catch (e: Exception) {
132
+ Log.e(TAG, "Error loading bundle", e)
133
+ val msg = e.message ?: "Unknown error"
134
+ mainHandler.post {
135
+ ErrorOverlayView.show(context, msg)
136
+ onComplete?.invoke(false, msg)
137
+ }
138
+ }
139
+ }
140
+ }
141
+
142
+ /** Post work to the JS thread. */
143
+ fun runOnJsThread(block: () -> Unit) {
144
+ jsHandler.post(block)
145
+ }
146
+
147
+ /** Post work to the main (UI) thread. */
148
+ fun runOnMainThread(block: () -> Unit) {
149
+ mainHandler.post(block)
150
+ }
151
+
152
+ /** Execute a void script on the JS thread. Safe to call from any thread. */
153
+ fun executeVoidScript(script: String) {
154
+ jsHandler.post {
155
+ try {
156
+ v8?.executeVoidScript(script)
157
+ } catch (e: Exception) {
158
+ Log.e(TAG, "Script error: ${e.message}")
159
+ }
160
+ }
161
+ }
162
+
163
+ /** Register a void Java method as a global JS function. Call from JS thread only. */
164
+ fun registerVoidCallback(name: String, callback: (Array<Any?>) -> Unit) {
165
+ jsHandler.post {
166
+ v8?.registerJavaMethod(JavaVoidCallback { _, params ->
167
+ try {
168
+ val args = Array<Any?>(params.length()) { i ->
169
+ when {
170
+ params.getType(i) == 1 -> params.getInteger(i) // INT
171
+ params.getType(i) == 2 -> params.getDouble(i) // DOUBLE
172
+ params.getType(i) == 3 -> params.getBoolean(i) // BOOLEAN
173
+ params.getType(i) == 4 -> params.getString(i) // STRING
174
+ else -> null
175
+ }
176
+ }
177
+ callback(args)
178
+ } finally {
179
+ params.close()
180
+ }
181
+ }, name)
182
+ }
183
+ }
184
+
185
+ /** Access raw V8 instance — only call from JS thread! */
186
+ fun withV8(block: (V8) -> Unit) {
187
+ jsHandler.post {
188
+ v8?.let(block)
189
+ }
190
+ }
191
+
192
+ /** Get raw V8 — ONLY call from JS thread. Returns null if not initialized. */
193
+ fun v8(): V8? = v8
194
+
195
+ /** Release the V8 runtime. */
196
+ fun release() {
197
+ jsHandler.post {
198
+ v8?.release(true)
199
+ v8 = null
200
+ isInitialized = false
201
+ }
202
+ jsThread.quitSafely()
203
+ }
204
+
205
+ private fun encodeJs(value: String): String =
206
+ "\"${value.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n").replace("\r", "\\r")}\""
207
+ }
@@ -0,0 +1,417 @@
1
+ package com.vuenative.core
2
+
3
+ import android.content.Context
4
+ import android.os.Handler
5
+ import android.os.Looper
6
+ import android.util.Log
7
+ import android.view.View
8
+ import android.view.ViewGroup
9
+ import org.json.JSONArray
10
+ import org.json.JSONObject
11
+
12
+ /**
13
+ * Receives batched JS operations, dispatches them to the native view system,
14
+ * and provides event firing back to JS.
15
+ */
16
+ class NativeBridge(private val context: Context) {
17
+
18
+ companion object {
19
+ private const val TAG = "VueNative-Bridge"
20
+
21
+ /** Operations that mutate the view tree and require a layout pass. */
22
+ private val treeMutationOps = setOf(
23
+ "create", "createText", "appendChild", "insertBefore", "removeChild",
24
+ "setRootView", "setText", "setElementText"
25
+ )
26
+ }
27
+
28
+ private val mainHandler = Handler(Looper.getMainLooper())
29
+
30
+ // -- View registry --
31
+ /** Maps node IDs to native Views. Accessed only on main thread. */
32
+ val nodeViews = mutableMapOf<Int, View>()
33
+
34
+ /** Maps node IDs to component type strings. Accessed only on main thread. */
35
+ val nodeTypes = mutableMapOf<Int, String>()
36
+
37
+ /** Maps "nodeId:eventName" to handler. Accessed only on main thread. */
38
+ val eventHandlers = mutableMapOf<String, (Any?) -> Unit>()
39
+
40
+ /** Reverse index: maps nodeId to the set of event keys registered for that node.
41
+ * Enables O(k) cleanup where k = handlers per node, instead of O(n) full scan. */
42
+ private val eventKeysPerNode = mutableMapOf<Int, MutableSet<String>>()
43
+
44
+ /** Maps child nodeId to parent nodeId. Accessed only on main thread. */
45
+ val nodeParents = mutableMapOf<Int, Int>()
46
+
47
+ /** Reverse index: maps parent nodeId to ordered list of child nodeIds. O(1) children lookup. */
48
+ val nodeChildren = mutableMapOf<Int, MutableList<Int>>()
49
+
50
+ /** The root view of the tree — set when __ROOT__ node is made the root view. */
51
+ var rootView: View? = null
52
+
53
+ /** The container view from the host Activity — where the root view is attached. */
54
+ var hostContainer: ViewGroup? = null
55
+
56
+ /** Called when native fires an event to JS (nodeId, eventName, payloadJson). */
57
+ var onFireEvent: ((nodeId: Int, eventName: String, payloadJson: String) -> Unit)? = null
58
+
59
+ /** Called when a module dispatches a global event to JS (eventName, payloadJson). */
60
+ var onDispatchGlobalEvent: ((eventName: String, payloadJson: String) -> Unit)? = null
61
+
62
+ private val componentRegistry: ComponentRegistry by lazy { ComponentRegistry.getInstance(context) }
63
+
64
+ // -------------------------------------------------------------------------
65
+ // Operation processing — called from JS thread
66
+ // -------------------------------------------------------------------------
67
+
68
+ /** Called from JS thread via __VN_flushOperations. Parses JSON and dispatches to main. */
69
+ fun processOperations(json: String) {
70
+ val operations: JSONArray = try {
71
+ JSONArray(json)
72
+ } catch (e: Exception) {
73
+ Log.e(TAG, "Failed to parse operations JSON: ${e.message}")
74
+ return
75
+ }
76
+
77
+ // Collect ops before dispatching to main thread
78
+ val ops = ArrayList<JSONObject>(operations.length())
79
+ for (i in 0 until operations.length()) {
80
+ ops.add(operations.getJSONObject(i))
81
+ }
82
+
83
+ mainHandler.post {
84
+ var hasMutations = false
85
+ for (op in ops) {
86
+ try {
87
+ val opName = op.optString("op")
88
+ if (!hasMutations && opName in treeMutationOps) {
89
+ hasMutations = true
90
+ }
91
+ handleOperation(op)
92
+ } catch (e: Exception) {
93
+ Log.e(TAG, "Error handling op '${op.optString("op")}': ${e.message}")
94
+ }
95
+ }
96
+ // Only trigger layout when the batch mutated the view tree
97
+ if (hasMutations) {
98
+ triggerLayout()
99
+ }
100
+ }
101
+ }
102
+
103
+ private fun handleOperation(op: JSONObject) {
104
+ val opName = op.getString("op")
105
+ val args = op.optJSONArray("args") ?: JSONArray()
106
+
107
+ when (opName) {
108
+ "create" -> handleCreate(args)
109
+ "createText" -> handleCreateText(args)
110
+ "setText" -> handleSetText(args)
111
+ "setElementText" -> handleSetElementText(args)
112
+ "updateProp" -> handleUpdateProp(args)
113
+ "updateStyle" -> handleUpdateStyle(args)
114
+ "appendChild" -> handleAppendChild(args)
115
+ "insertBefore" -> handleInsertBefore(args)
116
+ "removeChild" -> handleRemoveChild(args)
117
+ "setRootView" -> handleSetRootView(args)
118
+ "addEventListener" -> handleAddEventListener(args)
119
+ "removeEventListener" -> handleRemoveEventListener(args)
120
+ "invokeNativeModule" -> handleInvokeNativeModule(args)
121
+ "invokeNativeModuleSync" -> handleInvokeNativeModuleSync(args)
122
+ else -> Log.w(TAG, "Unknown operation: $opName")
123
+ }
124
+ }
125
+
126
+ private fun handleCreate(args: JSONArray) {
127
+ val nodeId = args.getInt(0)
128
+ val type = args.getString(1)
129
+ val view = componentRegistry.createView(type) ?: return
130
+ nodeViews[nodeId] = view
131
+ nodeTypes[nodeId] = type
132
+ }
133
+
134
+ private fun handleCreateText(args: JSONArray) {
135
+ // Text nodes — create a special "text node" view
136
+ val nodeId = args.getInt(0)
137
+ val text = args.getString(1)
138
+ val textView = VTextNodeView(context).apply { setText(text) }
139
+ nodeViews[nodeId] = textView
140
+ nodeTypes[nodeId] = "__TEXT__"
141
+ }
142
+
143
+ private fun handleSetText(args: JSONArray) {
144
+ val nodeId = args.getInt(0)
145
+ val text = args.getString(1)
146
+ val view = nodeViews[nodeId] ?: return
147
+ (view as? VTextNodeView)?.setText(text)
148
+ }
149
+
150
+ private fun handleSetElementText(args: JSONArray) {
151
+ val nodeId = args.getInt(0)
152
+ val text = args.getString(1)
153
+ val view = nodeViews[nodeId] ?: return
154
+ // Delegate to the factory
155
+ val factory = componentRegistry.factoryForType(nodeTypes[nodeId] ?: return) ?: return
156
+ factory.updateProp(view, "text", text)
157
+ }
158
+
159
+ private fun handleUpdateProp(args: JSONArray) {
160
+ val nodeId = args.getInt(0)
161
+ val key = args.getString(1)
162
+ val value = if (args.isNull(2)) null else args.get(2)
163
+ val view = nodeViews[nodeId] ?: return
164
+ val factory = componentRegistry.factoryForView(view) ?: return
165
+ factory.updateProp(view, key, value)
166
+ }
167
+
168
+ private fun handleUpdateStyle(args: JSONArray) {
169
+ val nodeId = args.getInt(0)
170
+ val styleObj = args.optJSONObject(1) ?: return
171
+ val view = nodeViews[nodeId] ?: return
172
+ val factory = componentRegistry.factoryForView(view) ?: return
173
+ val iter = styleObj.keys()
174
+ while (iter.hasNext()) {
175
+ val key = iter.next()
176
+ val value = if (styleObj.isNull(key)) null else styleObj.get(key)
177
+ factory.updateProp(view, key, value)
178
+ }
179
+ }
180
+
181
+ private fun handleAppendChild(args: JSONArray) {
182
+ val parentId = args.getInt(0)
183
+ val childId = args.getInt(1)
184
+ val parent = nodeViews[parentId] ?: return
185
+ val child = nodeViews[childId] ?: return
186
+ nodeParents[childId] = parentId
187
+ nodeChildren.getOrPut(parentId) { mutableListOf() }.add(childId)
188
+
189
+ val factory = componentRegistry.factoryForView(parent)
190
+ if (factory != null) {
191
+ val idx = (parent as? ViewGroup)?.childCount ?: 0
192
+ factory.insertChild(parent, child, idx)
193
+ } else {
194
+ (parent as? ViewGroup)?.addView(child)
195
+ }
196
+ }
197
+
198
+ private fun handleInsertBefore(args: JSONArray) {
199
+ val parentId = args.getInt(0)
200
+ val childId = args.getInt(1)
201
+ val anchorId = args.getInt(2)
202
+ val parent = nodeViews[parentId] ?: return
203
+ val child = nodeViews[childId] ?: return
204
+ val anchor = nodeViews[anchorId] ?: return
205
+ nodeParents[childId] = parentId
206
+ // Insert into nodeChildren at the correct position (before anchorId)
207
+ val siblings = nodeChildren.getOrPut(parentId) { mutableListOf() }
208
+ val anchorIndex = siblings.indexOf(anchorId)
209
+ if (anchorIndex >= 0) {
210
+ siblings.add(anchorIndex, childId)
211
+ } else {
212
+ siblings.add(childId)
213
+ }
214
+
215
+ val vg = parent as? ViewGroup ?: return
216
+ val anchorIdx = vg.indexOfChild(anchor)
217
+ val insertIdx = if (anchorIdx < 0) vg.childCount else anchorIdx
218
+
219
+ val factory = componentRegistry.factoryForView(parent)
220
+ if (factory != null) {
221
+ factory.insertChild(parent, child, insertIdx)
222
+ } else {
223
+ vg.addView(child, insertIdx)
224
+ }
225
+ }
226
+
227
+ private fun handleRemoveChild(args: JSONArray) {
228
+ val childId = args.getInt(0)
229
+ val child = nodeViews[childId] ?: return
230
+ val parentId = nodeParents[childId]
231
+ val parent = parentId?.let { nodeViews[it] }
232
+
233
+ if (parent != null) {
234
+ val factory = componentRegistry.factoryForView(parent)
235
+ if (factory != null) {
236
+ factory.removeChild(parent, child)
237
+ } else {
238
+ (parent as? ViewGroup)?.removeView(child)
239
+ }
240
+ } else {
241
+ (child.parent as? ViewGroup)?.removeView(child)
242
+ }
243
+
244
+ // Remove child from parent's nodeChildren list
245
+ if (parentId != null) {
246
+ nodeChildren[parentId]?.remove(childId)
247
+ }
248
+
249
+ // Recursively clean up descendants
250
+ cleanupNode(childId)
251
+ }
252
+
253
+ private fun cleanupNode(nodeId: Int) {
254
+ // Recursively clean up children using the reverse index (O(subtree) not O(n))
255
+ nodeChildren[nodeId]?.toList()?.forEach { cleanupNode(it) }
256
+ nodeParents.remove(nodeId)
257
+ // O(k) event cleanup via reverse index instead of O(n) full scan
258
+ eventKeysPerNode.remove(nodeId)?.forEach { key ->
259
+ eventHandlers.remove(key)
260
+ }
261
+ // Call destroyView on the factory to clean up factory-level state (e.g. VListFactory maps)
262
+ val view = nodeViews[nodeId]
263
+ if (view != null) {
264
+ val factory = componentRegistry.factoryForView(view)
265
+ factory?.destroyView(view)
266
+ }
267
+ nodeViews.remove(nodeId)
268
+ nodeTypes.remove(nodeId)
269
+ nodeChildren.remove(nodeId)
270
+ }
271
+
272
+ private fun handleSetRootView(args: JSONArray) {
273
+ val nodeId = args.getInt(0)
274
+ val view = nodeViews[nodeId] ?: return
275
+ rootView = view
276
+
277
+ val container = hostContainer ?: return
278
+ container.removeAllViews()
279
+ container.addView(
280
+ view,
281
+ ViewGroup.LayoutParams(
282
+ ViewGroup.LayoutParams.MATCH_PARENT,
283
+ ViewGroup.LayoutParams.MATCH_PARENT
284
+ )
285
+ )
286
+ }
287
+
288
+ private fun handleAddEventListener(args: JSONArray) {
289
+ val nodeId = args.getInt(0)
290
+ val eventName = args.getString(1)
291
+ val view = nodeViews[nodeId] ?: return
292
+ val factory = componentRegistry.factoryForView(view) ?: return
293
+
294
+ val key = "$nodeId:$eventName"
295
+
296
+ // Remove old handler first to prevent duplicate event firing (e.g. recycled node IDs)
297
+ if (eventHandlers.containsKey(key)) {
298
+ factory.removeEventListener(view, eventName)
299
+ eventHandlers.remove(key)
300
+ }
301
+
302
+ val handler: (Any?) -> Unit = { payload ->
303
+ val payloadJson = when (payload) {
304
+ null -> "null"
305
+ is Map<*, *> -> JSONObject(payload).toString()
306
+ is String -> JSONObject.quote(payload)
307
+ else -> payload.toString()
308
+ }
309
+ onFireEvent?.invoke(nodeId, eventName, payloadJson)
310
+ }
311
+
312
+ factory.addEventListener(view, eventName, handler)
313
+ eventHandlers[key] = handler
314
+ eventKeysPerNode.getOrPut(nodeId) { mutableSetOf() }.add(key)
315
+ }
316
+
317
+ private fun handleRemoveEventListener(args: JSONArray) {
318
+ val nodeId = args.getInt(0)
319
+ val eventName = args.getString(1)
320
+ val view = nodeViews[nodeId] ?: return
321
+ val factory = componentRegistry.factoryForView(view) ?: return
322
+ factory.removeEventListener(view, eventName)
323
+
324
+ val key = "$nodeId:$eventName"
325
+ eventHandlers.remove(key)
326
+ eventKeysPerNode[nodeId]?.remove(key)
327
+ }
328
+
329
+ private fun handleInvokeNativeModule(args: JSONArray) {
330
+ val moduleName = args.getString(0)
331
+ val methodName = args.getString(1)
332
+ val moduleArgs = buildArgsList(args.optJSONArray(2))
333
+ val callbackId = args.optInt(3, -1)
334
+
335
+ NativeModuleRegistry.getInstance(context).invoke(
336
+ moduleName, methodName, moduleArgs, this
337
+ ) { result, error ->
338
+ if (callbackId >= 0) {
339
+ val resultJson = when (result) {
340
+ null -> "null"
341
+ is Map<*, *> -> JSONObject(result).toString()
342
+ is List<*> -> JSONArray(result).toString()
343
+ is String -> JSONObject.quote(result)
344
+ is Boolean -> result.toString()
345
+ is Number -> result.toString()
346
+ else -> result.toString()
347
+ }
348
+ val errorJson = if (error != null) JSONObject.quote(error) else "null"
349
+ resolveCallbackInJs(callbackId, resultJson, errorJson)
350
+ }
351
+ }
352
+ }
353
+
354
+ private fun handleInvokeNativeModuleSync(args: JSONArray) {
355
+ val moduleName = args.getString(0)
356
+ val methodName = args.getString(1)
357
+ val moduleArgs = buildArgsList(args.optJSONArray(2))
358
+ try {
359
+ NativeModuleRegistry.getInstance(context).invokeSync(moduleName, methodName, moduleArgs, this)
360
+ } catch (e: Exception) {
361
+ Log.e(TAG, "Error in sync module invoke $moduleName.$methodName: ${e.message}")
362
+ }
363
+ }
364
+
365
+ private fun resolveCallbackInJs(callbackId: Int, resultJson: String, errorJson: String) {
366
+ onFireEvent?.invoke(-1, "__callback__",
367
+ "{\"callbackId\":$callbackId,\"result\":$resultJson,\"error\":$errorJson}")
368
+ }
369
+
370
+ private fun buildArgsList(arr: JSONArray?): List<Any?> {
371
+ arr ?: return emptyList()
372
+ return (0 until arr.length()).map { i ->
373
+ if (arr.isNull(i)) null else arr.get(i)
374
+ }
375
+ }
376
+
377
+ // -------------------------------------------------------------------------
378
+ // Registry management
379
+ // -------------------------------------------------------------------------
380
+
381
+ /** Clear all registries. Called during hot reload after JS teardown. Must run on main thread. */
382
+ fun clearAllRegistries() {
383
+ nodeViews.clear()
384
+ nodeTypes.clear()
385
+ eventHandlers.clear()
386
+ eventKeysPerNode.clear()
387
+ nodeParents.clear()
388
+ nodeChildren.clear()
389
+ rootView = null
390
+ }
391
+
392
+ // -------------------------------------------------------------------------
393
+ // Layout
394
+ // -------------------------------------------------------------------------
395
+
396
+ fun triggerLayout() {
397
+ rootView?.let { root ->
398
+ root.requestLayout()
399
+ }
400
+ }
401
+
402
+ // -------------------------------------------------------------------------
403
+ // Events: Native to JS
404
+ // -------------------------------------------------------------------------
405
+
406
+ /** Fire an event from a native view to the JS side. */
407
+ fun fireEvent(nodeId: Int, eventName: String, payload: Map<String, Any?>? = null) {
408
+ val payloadJson = if (payload != null) JSONObject(payload).toString() else "null"
409
+ onFireEvent?.invoke(nodeId, eventName, payloadJson)
410
+ }
411
+
412
+ /** Dispatch a global push event to JS. Called from modules. */
413
+ fun dispatchGlobalEvent(eventName: String, payload: Map<String, Any> = emptyMap()) {
414
+ val payloadJson = JSONObject(payload).toString()
415
+ onDispatchGlobalEvent?.invoke(eventName, payloadJson)
416
+ }
417
+ }
@@ -0,0 +1,76 @@
1
+ package com.vuenative.core
2
+
3
+ import android.content.Context
4
+ import android.view.View
5
+
6
+ /**
7
+ * Singleton registry mapping component type strings to factories.
8
+ * Also maps views to the factory that created them (via view tag).
9
+ */
10
+ class ComponentRegistry private constructor(private val context: Context) {
11
+
12
+ companion object {
13
+ @Volatile private var instance: ComponentRegistry? = null
14
+
15
+ fun getInstance(context: Context): ComponentRegistry {
16
+ return instance ?: synchronized(this) {
17
+ instance ?: ComponentRegistry(context.applicationContext).also {
18
+ instance = it
19
+ it.registerDefaults()
20
+ }
21
+ }
22
+ }
23
+ }
24
+
25
+ private val factories = mutableMapOf<String, NativeComponentFactory>()
26
+
27
+ private fun registerDefaults() {
28
+ register("VView", VViewFactory())
29
+ register("VText", VTextFactory())
30
+ register("VButton", VButtonFactory())
31
+ register("VInput", VInputFactory())
32
+ register("VSwitch", VSwitchFactory())
33
+ register("VActivityIndicator", VActivityIndicatorFactory())
34
+ register("VScrollView", VScrollViewFactory())
35
+ register("VImage", VImageFactory())
36
+ register("VKeyboardAvoiding", VKeyboardAvoidingFactory())
37
+ register("VSafeArea", VSafeAreaFactory())
38
+ register("VSlider", VSliderFactory())
39
+ register("VList", VListFactory())
40
+ register("VModal", VModalFactory())
41
+ register("VAlertDialog", VAlertDialogFactory())
42
+ register("VStatusBar", VStatusBarFactory())
43
+ register("VWebView", VWebViewFactory())
44
+ register("VProgressBar", VProgressBarFactory())
45
+ register("VPicker", VPickerFactory())
46
+ register("VSegmentedControl", VSegmentedControlFactory())
47
+ register("VActionSheet", VActionSheetFactory())
48
+ register("VRefreshControl", VRefreshControlFactory())
49
+ register("VPressable", VPressableFactory())
50
+ register("VSectionList", VSectionListFactory())
51
+ register("VCheckbox", VCheckboxFactory())
52
+ register("VRadio", VRadioFactory())
53
+ register("VDropdown", VDropdownFactory())
54
+ register("VVideo", VVideoFactory())
55
+ register("__ROOT__", VRootFactory())
56
+ }
57
+
58
+ fun register(type: String, factory: NativeComponentFactory) {
59
+ factories[type] = factory
60
+ }
61
+
62
+ fun createView(type: String): View? {
63
+ val factory = factories[type] ?: run {
64
+ android.util.Log.w("VueNative", "No factory for type: $type")
65
+ return null
66
+ }
67
+ val view = factory.createView(context)
68
+ view.setTag(TAG_FACTORY, factory)
69
+ return view
70
+ }
71
+
72
+ fun factoryForType(type: String): NativeComponentFactory? = factories[type]
73
+
74
+ fun factoryForView(view: View): NativeComponentFactory? =
75
+ view.getTag(TAG_FACTORY) as? NativeComponentFactory
76
+ }