@@ -83,6 +83,78 @@ private static String getDefaultBundleAssetName(Context application) {
8383 return bundleAssetName ;
8484 }
8585
86+ private static String toAssetUrl (String bundleAssetName ) {
87+ if (bundleAssetName == null || bundleAssetName .isEmpty ()) {
88+ return "assets://index.android.bundle" ;
89+ }
90+ if (bundleAssetName .startsWith ("assets://" )) {
91+ return bundleAssetName ;
92+ }
93+ return "assets://" + bundleAssetName ;
94+ }
95+
96+ private static JSBundleLoader createBundleLoader (Context application , String updateBundlePath , boolean loadAssetSynchronously ) {
97+ if (updateBundlePath != null ) {
98+ return JSBundleLoader .createFileLoader (updateBundlePath );
99+ }
100+ return JSBundleLoader .createAssetLoader (
101+ application ,
102+ toAssetUrl (getDefaultBundleAssetName (application )),
103+ loadAssetSynchronously
104+ );
105+ }
106+
107+ private static Object getReactHost (Activity currentActivity , Context application ) {
108+ if (currentActivity instanceof ReactActivity ) {
109+ try {
110+ Method getReactDelegateMethod = ReactActivity .class .getMethod ("getReactDelegate" );
111+ ReactDelegate reactDelegate = (ReactDelegate ) getReactDelegateMethod .invoke (currentActivity );
112+ if (reactDelegate != null ) {
113+ Field reactHostField = getCompatibleField (reactDelegate .getClass (), "reactHost" );
114+ reactHostField .setAccessible (true );
115+ Object reactHost = reactHostField .get (reactDelegate );
116+ if (reactHost != null ) {
117+ return reactHost ;
118+ }
119+ }
120+ } catch (Throwable ignored ) {
121+ }
122+ }
123+
124+ try {
125+ Method getReactHostMethod = application .getClass ().getMethod ("getReactHost" );
126+ return getReactHostMethod .invoke (application );
127+ } catch (Throwable ignored ) {
128+ }
129+
130+ return null ;
131+ }
132+
133+ private static void reloadReactHost (Object reactHost , JSBundleLoader loader ) throws Throwable {
134+ try {
135+ Field devSupportField = getCompatibleField (reactHost .getClass (), "useDevSupport" );
136+ devSupportField .setAccessible (true );
137+ devSupportField .set (reactHost , false );
138+ } catch (Throwable ignored ) {
139+ }
140+
141+ Field reactHostDelegateField = getCompatibleField (reactHost .getClass (), "reactHostDelegate" );
142+ reactHostDelegateField .setAccessible (true );
143+ Object reactHostDelegate = reactHostDelegateField .get (reactHost );
144+
145+ String bundleFieldName = "jsBundleLoader" ;
146+ if ("expo.modules.ExpoReactHostFactory.ExpoReactHostDelegate" .equals (reactHostDelegate .getClass ().getCanonicalName ())) {
147+ bundleFieldName = "_jsBundleLoader" ;
148+ }
149+
150+ Field jsBundleLoaderField = reactHostDelegate .getClass ().getDeclaredField (bundleFieldName );
151+ jsBundleLoaderField .setAccessible (true );
152+ jsBundleLoaderField .set (reactHostDelegate , loader );
153+
154+ Method reloadMethod = reactHost .getClass ().getMethod ("reload" , String .class );
155+ reloadMethod .invoke (reactHost , "react-native-update" );
156+ }
157+
86158 public static void downloadFullUpdate (UpdateContext updateContext , final ReadableMap options , final Promise promise ) {
87159 String url = options .getString ("updateUrl" );
88160 String hash = options .getString ("hash" );
@@ -178,14 +250,20 @@ public void run() {
178250
179251 final Context application = mContext .getApplicationContext ();
180252 String updateBundlePath = updateContext .getBundleUrl (application );
253+ final Activity currentActivity = mContext .getCurrentActivity ();
181254
182- JSBundleLoader loader ;
183-
184- if (updateBundlePath != null ) {
185- loader = JSBundleLoader .createFileLoader (updateBundlePath );
186- } else {
187- loader = JSBundleLoader .createAssetLoader (application , getDefaultBundleAssetName (application ), false );
255+ Object reactHost = getReactHost (currentActivity , application );
256+ if (reactHost != null ) {
257+ try {
258+ reloadReactHost (reactHost , createBundleLoader (application , updateBundlePath , true ));
259+ promise .resolve (true );
260+ return ;
261+ } catch (Throwable err ) {
262+ Log .e (NAME , "Failed to reload via ReactHost" , err );
263+ }
188264 }
265+
266+ JSBundleLoader loader = createBundleLoader (application , updateBundlePath , false );
189267 try {
190268 ReactInstanceManager instanceManager = updateContext .getCustomReactInstanceManager ();
191269
@@ -207,46 +285,16 @@ public void run() {
207285 promise .resolve (true );
208286
209287 } catch (Throwable err ) {
210- final Activity currentActivity = mContext .getCurrentActivity ();
211288 if (currentActivity == null ) {
212289 promise .reject (err );
213290 return ;
214291 }
215292 try {
216- java .lang .reflect .Method getReactDelegateMethod =
217- ReactActivity .class .getMethod ("getReactDelegate" );
218-
219- ReactDelegate reactDelegate = (ReactDelegate )
220- getReactDelegateMethod .invoke (currentActivity );
221-
222- Field reactHostField = getCompatibleField (ReactDelegate .class , "reactHost" );
223- reactHostField .setAccessible (true );
224- Object reactHost = reactHostField .get (reactDelegate );
225-
226- Field devSupport = getCompatibleField (reactHost .getClass (), "useDevSupport" );
227- devSupport .setAccessible (true );
228- devSupport .set (reactHost , false );
229-
230- // Access the ReactHostDelegate field (compatible with mReactHostDelegate/reactHostDelegate)
231- Field reactHostDelegateField = getCompatibleField (reactHost .getClass (), "reactHostDelegate" );
232- reactHostDelegateField .setAccessible (true );
233- Object reactHostDelegate = reactHostDelegateField .get (reactHost );
234-
235- String bundleFieldName = "jsBundleLoader" ;
236- if (reactHostDelegate .getClass ().getCanonicalName ().equals ("expo.modules.ExpoReactHostFactory.ExpoReactHostDelegate" )) {
237- bundleFieldName = "_jsBundleLoader" ;
293+ Object currentReactHost = getReactHost (currentActivity , application );
294+ if (currentReactHost == null ) {
295+ throw err ;
238296 }
239-
240- // Modify the jsBundleLoader field
241- Field jsBundleLoaderField = reactHostDelegate .getClass ().getDeclaredField (bundleFieldName );
242- jsBundleLoaderField .setAccessible (true );
243- jsBundleLoaderField .set (reactHostDelegate , loader );
244-
245- // Get the reload method with a String parameter
246- java .lang .reflect .Method reloadMethod = reactHost .getClass ().getMethod ("reload" , String .class );
247-
248- // Invoke the reload method with a reason
249- reloadMethod .invoke (reactHost , "react-native-update" );
297+ reloadReactHost (currentReactHost , createBundleLoader (application , updateBundlePath , true ));
250298 promise .resolve (true );
251299 } catch (Throwable e ) {
252300 currentActivity .runOnUiThread (new Runnable () {
0 commit comments