@@ -4,7 +4,16 @@ import android.app.Application
44import com.facebook.react.ReactHost
55import com.facebook.react.ReactNativeHost
66import com.facebook.react.ReactPackage
7+ import com.facebook.react.bridge.JSBundleLoader
8+ import com.facebook.react.bridge.JSBundleLoaderDelegate
9+ import com.facebook.react.common.annotations.UnstableReactNativeAPI
10+ import com.facebook.react.defaults.DefaultComponentsRegistry
11+ import com.facebook.react.defaults.DefaultReactHostDelegate
12+ import com.facebook.react.defaults.DefaultTurboModuleManagerDelegate
713import com.facebook.react.devsupport.interfaces.RedBoxHandler
14+ import com.facebook.react.fabric.ComponentFactory
15+ import com.facebook.react.runtime.ReactHostImpl
16+ import com.facebook.react.runtime.hermes.HermesInstance
817import com.facebook.react.soloader.OpenSourceMergedSoMapping
918import com.facebook.soloader.SoLoader
1019import com.mendix.mendixnative.error.ErrorHandler
@@ -16,7 +25,6 @@ import com.mendix.mendixnative.react.splash.MendixSplashScreenPresenter
1625import com.mendixnative.MendixNativePackage
1726import java.util.*
1827import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
19- import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
2028
2129import com.facebook.react.defaults.DefaultReactNativeHost
2230
@@ -56,8 +64,55 @@ abstract class MendixReactApplication : Application(), MendixApplication, ErrorH
5664 override val isHermesEnabled: Boolean = true
5765 }
5866
59- override val reactHost: ReactHost
60- get() = getDefaultReactHost(applicationContext, reactNativeHost)
67+ /* *
68+ * Build the [ReactHost] ourselves instead of using [DefaultReactHost.getDefaultReactHost],
69+ * because that factory evaluates [ReactNativeHost.getJSBundleFile] once at creation time and
70+ * bakes the result into a fixed [JSBundleLoader]. After an OTA update deploys a new bundle,
71+ * a subsequent [ReactHost.reload] would still load the stale bundle.
72+ *
73+ * By providing a **dynamic** [JSBundleLoader] whose [JSBundleLoader.loadScript] calls
74+ * [getJSBundleFile] on every invocation, each reload picks up the latest bundle path —
75+ * whether it comes from OTA, a custom [JSBundleFileProvider], or the default asset bundle.
76+ */
77+ @OptIn(UnstableReactNativeAPI ::class )
78+ override val reactHost: ReactHost by lazy {
79+ val dynamicBundleLoader = object : JSBundleLoader () {
80+ override fun loadScript (delegate : JSBundleLoaderDelegate ): String {
81+ val bundle = jsBundleFile
82+ if (bundle != null ) {
83+ if (bundle.startsWith(" assets://" )) {
84+ delegate.loadScriptFromAssets(assets, bundle, true )
85+ } else {
86+ delegate.loadScriptFromFile(bundle, bundle, false )
87+ }
88+ return bundle
89+ }
90+ val defaultBundle = " assets://index.android.bundle"
91+ delegate.loadScriptFromAssets(assets, defaultBundle, true )
92+ return defaultBundle
93+ }
94+ }
95+
96+ val hostPackages: MutableList <ReactPackage > = ArrayList (this @MendixReactApplication.packages)
97+ applyInternalPackageAugmentations(hostPackages)
98+
99+ val delegate = DefaultReactHostDelegate (
100+ jsMainModulePath = " index" ,
101+ jsBundleLoader = dynamicBundleLoader,
102+ reactPackages = hostPackages,
103+ jsRuntimeFactory = HermesInstance (),
104+ turboModuleManagerDelegateBuilder = DefaultTurboModuleManagerDelegate .Builder (),
105+ )
106+ val componentFactory = ComponentFactory ()
107+ DefaultComponentsRegistry .register(componentFactory)
108+ ReactHostImpl (
109+ applicationContext,
110+ delegate,
111+ componentFactory,
112+ true /* allowPackagerServerAccess */ ,
113+ useDeveloperSupport,
114+ )
115+ }
61116
62117 /* *
63118 * Apply internal augmentations to packages (e.g., attach presenters) without instantiating
0 commit comments