1
1
package com .microsoft .codepush .react ;
2
2
3
+ import com .facebook .react .ReactActivity ;
3
4
import com .facebook .react .ReactPackage ;
4
5
import com .facebook .react .bridge .JavaScriptModule ;
5
6
import com .facebook .react .bridge .LifecycleEventListener ;
29
30
import org .json .JSONException ;
30
31
import org .json .JSONObject ;
31
32
33
+ import java .lang .ReflectiveOperationException ;
34
+ import java .lang .reflect .Field ;
35
+ import java .lang .reflect .Method ;
36
+
32
37
import java .io .File ;
33
38
import java .io .IOException ;
34
39
import java .util .ArrayList ;
@@ -101,7 +106,6 @@ public CodePush(String deploymentKey, Activity mainActivity, boolean isDebugMode
101
106
throw new CodePushUnknownException ("Unable to get package info for " + applicationContext .getPackageName (), e );
102
107
}
103
108
104
- initializeUpdateAfterRestart ();
105
109
if (currentInstance != null ) {
106
110
CodePushUtils .log ("More than one CodePush instance has been initialized. Please use the instance method codePush.getBundleUrlInternal() to get the correct bundleURL for a particular instance." );
107
111
}
@@ -147,7 +151,7 @@ public static String getBundleUrl(String assetsBundleFileName) {
147
151
148
152
return currentInstance .getBundleUrlInternal (assetsBundleFileName );
149
153
}
150
-
154
+
151
155
public String getBundleUrlInternal (String assetsBundleFileName ) {
152
156
this .assetsBundleFileName = assetsBundleFileName ;
153
157
String binaryJsBundleUrl = ASSETS_BUNDLE_PREFIX + assetsBundleFileName ;
@@ -356,13 +360,74 @@ public void clearUpdates() {
356
360
private class CodePushNativeModule extends ReactContextBaseJavaModule {
357
361
private LifecycleEventListener lifecycleEventListener = null ;
358
362
private int minimumBackgroundDuration = 0 ;
363
+
364
+ public CodePushNativeModule (ReactApplicationContext reactContext ) {
365
+ super (reactContext );
366
+ }
367
+
368
+ @ Override
369
+ public Map <String , Object > getConstants () {
370
+ final Map <String , Object > constants = new HashMap <>();
371
+ constants .put ("codePushInstallModeImmediate" , CodePushInstallMode .IMMEDIATE .getValue ());
372
+ constants .put ("codePushInstallModeOnNextRestart" , CodePushInstallMode .ON_NEXT_RESTART .getValue ());
373
+ constants .put ("codePushInstallModeOnNextResume" , CodePushInstallMode .ON_NEXT_RESUME .getValue ());
374
+ return constants ;
375
+ }
359
376
360
- private void loadBundle () {
377
+ @ Override
378
+ public String getName () {
379
+ return "CodePush" ;
380
+ }
381
+
382
+ @ Override
383
+ public void initialize () {
384
+ CodePush .this .initializeUpdateAfterRestart ();
385
+ }
386
+
387
+ private void loadBundleLegacy () {
361
388
Intent intent = mainActivity .getIntent ();
362
389
mainActivity .finish ();
363
390
mainActivity .startActivity (intent );
391
+
364
392
currentInstance = null ;
365
393
}
394
+
395
+ private void loadBundle () {
396
+ try {
397
+ // #1) Get the private ReactInstanceManager, which is what includes
398
+ // the logic to reload the current React context.
399
+ Field instanceManagerField = ReactActivity .class .getDeclaredField ("mReactInstanceManager" );
400
+ instanceManagerField .setAccessible (true ); // Make a private field accessible
401
+ final Object instanceManager = instanceManagerField .get (mainActivity );
402
+
403
+ // #2) Update the locally stored JS bundle file path
404
+ String latestJSBundleFile = CodePush .this .getBundleUrlInternal (CodePush .this .assetsBundleFileName );
405
+ Field jsBundleField = instanceManager .getClass ().getDeclaredField ("mJSBundleFile" );
406
+ jsBundleField .setAccessible (true );
407
+ jsBundleField .set (instanceManager , latestJSBundleFile );
408
+
409
+ // #3) Get the context creation method and fire it on the UI thread (which RN enforces)
410
+ final Method recreateMethod = instanceManager .getClass ().getMethod ("recreateReactContextInBackground" );
411
+ mainActivity .runOnUiThread (new Runnable () {
412
+ @ Override
413
+ public void run () {
414
+ try {
415
+ recreateMethod .invoke (instanceManager );
416
+ }
417
+ catch (ReflectiveOperationException e ) {
418
+ // The recreation method threw an unknown exception
419
+ // so just simply fallback to restarting the Activity
420
+ loadBundleLegacy ();
421
+ }
422
+ }
423
+ });
424
+ }
425
+ catch (ReflectiveOperationException e ) {
426
+ // Our reflection logic failed somewhere
427
+ // so fall back to restarting the Activity
428
+ loadBundleLegacy ();
429
+ }
430
+ }
366
431
367
432
@ ReactMethod
368
433
public void downloadUpdate (final ReadableMap updatePackage , final Promise promise ) {
@@ -597,24 +662,6 @@ public void downloadAndReplaceCurrentBundle(String remoteBundleUrl) {
597
662
}
598
663
}
599
664
}
600
-
601
- @ Override
602
- public Map <String , Object > getConstants () {
603
- final Map <String , Object > constants = new HashMap <>();
604
- constants .put ("codePushInstallModeImmediate" , CodePushInstallMode .IMMEDIATE .getValue ());
605
- constants .put ("codePushInstallModeOnNextRestart" , CodePushInstallMode .ON_NEXT_RESTART .getValue ());
606
- constants .put ("codePushInstallModeOnNextResume" , CodePushInstallMode .ON_NEXT_RESUME .getValue ());
607
- return constants ;
608
- }
609
-
610
- public CodePushNativeModule (ReactApplicationContext reactContext ) {
611
- super (reactContext );
612
- }
613
-
614
- @ Override
615
- public String getName () {
616
- return "CodePush" ;
617
- }
618
665
}
619
666
620
667
@ Override
@@ -638,4 +685,4 @@ public List<Class<? extends JavaScriptModule>> createJSModules() {
638
685
public List <ViewManager > createViewManagers (ReactApplicationContext reactApplicationContext ) {
639
686
return new ArrayList <>();
640
687
}
641
- }
688
+ }
0 commit comments