Skip to content
This repository was archived by the owner on May 20, 2025. It is now read-only.

Commit 4494ef6

Browse files
committed
Merge pull request #275 from Microsoft/reload
Android reload refactor
2 parents 09aba10 + 6080728 commit 4494ef6

File tree

1 file changed

+69
-22
lines changed
  • android/app/src/main/java/com/microsoft/codepush/react

1 file changed

+69
-22
lines changed

android/app/src/main/java/com/microsoft/codepush/react/CodePush.java

Lines changed: 69 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.microsoft.codepush.react;
22

3+
import com.facebook.react.ReactActivity;
34
import com.facebook.react.ReactPackage;
45
import com.facebook.react.bridge.JavaScriptModule;
56
import com.facebook.react.bridge.LifecycleEventListener;
@@ -29,6 +30,10 @@
2930
import org.json.JSONException;
3031
import org.json.JSONObject;
3132

33+
import java.lang.ReflectiveOperationException;
34+
import java.lang.reflect.Field;
35+
import java.lang.reflect.Method;
36+
3237
import java.io.File;
3338
import java.io.IOException;
3439
import java.util.ArrayList;
@@ -101,7 +106,6 @@ public CodePush(String deploymentKey, Activity mainActivity, boolean isDebugMode
101106
throw new CodePushUnknownException("Unable to get package info for " + applicationContext.getPackageName(), e);
102107
}
103108

104-
initializeUpdateAfterRestart();
105109
if (currentInstance != null) {
106110
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.");
107111
}
@@ -147,7 +151,7 @@ public static String getBundleUrl(String assetsBundleFileName) {
147151

148152
return currentInstance.getBundleUrlInternal(assetsBundleFileName);
149153
}
150-
154+
151155
public String getBundleUrlInternal(String assetsBundleFileName) {
152156
this.assetsBundleFileName = assetsBundleFileName;
153157
String binaryJsBundleUrl = ASSETS_BUNDLE_PREFIX + assetsBundleFileName;
@@ -356,13 +360,74 @@ public void clearUpdates() {
356360
private class CodePushNativeModule extends ReactContextBaseJavaModule {
357361
private LifecycleEventListener lifecycleEventListener = null;
358362
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+
}
359376

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() {
361388
Intent intent = mainActivity.getIntent();
362389
mainActivity.finish();
363390
mainActivity.startActivity(intent);
391+
364392
currentInstance = null;
365393
}
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+
}
366431

367432
@ReactMethod
368433
public void downloadUpdate(final ReadableMap updatePackage, final Promise promise) {
@@ -597,24 +662,6 @@ public void downloadAndReplaceCurrentBundle(String remoteBundleUrl) {
597662
}
598663
}
599664
}
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-
}
618665
}
619666

620667
@Override
@@ -638,4 +685,4 @@ public List<Class<? extends JavaScriptModule>> createJSModules() {
638685
public List<ViewManager> createViewManagers(ReactApplicationContext reactApplicationContext) {
639686
return new ArrayList<>();
640687
}
641-
}
688+
}

0 commit comments

Comments
 (0)