Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions ReactAndroid/src/main/java/com/facebook/react/JSInterpreter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.facebook.react;

/**
* An enum that specifies the JS Engine to be used in the app
* Old Logic uses the legacy code
* JSC/HERMES loads the respective engine using the revamped logic
*/
public enum JSInterpreter {
OLD_LOGIC,
JSC,
HERMES
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import com.facebook.hermes.reactexecutor.HermesExecutor;
import com.facebook.hermes.reactexecutor.HermesExecutorFactory;
import com.facebook.infer.annotation.Assertions;
import com.facebook.logger.AirtelLogger;
import com.facebook.react.bridge.JSBundleLoader;
import com.facebook.react.bridge.JSIModulePackage;
import com.facebook.react.bridge.JavaScriptExecutorFactory;
Expand Down Expand Up @@ -66,6 +67,7 @@ public class ReactInstanceManagerBuilder {
private @Nullable Map<String, RequestHandler> mCustomPackagerCommandHandlers;
private @Nullable ReactPackageTurboModuleManagerDelegate.Builder mTMMDelegateBuilder;
private @Nullable SurfaceDelegateFactory mSurfaceDelegateFactory;
private JSInterpreter jsInterpreter = JSInterpreter.OLD_LOGIC;

/* package protected */ ReactInstanceManagerBuilder() {}

Expand Down Expand Up @@ -125,6 +127,31 @@ public ReactInstanceManagerBuilder setJSBundleLoader(JSBundleLoader jsBundleLoad
return this;
}

/**
* Sets the jsEngine as JSC or HERMES as per the setJsEngineAsHermes call
* Uses the enum {@link JSInterpreter}
* @param jsInterpreter
*/
private void setJSEngine(JSInterpreter jsInterpreter){
this.jsInterpreter = jsInterpreter;
}

/**
* Utility setter to set the required JSEngine as HERMES or JSC
* Defaults to OLD_LOGIC if not called by the host app
* @param hermesEnabled
* hermesEnabled = true sets the JS Engine as HERMES and JSC otherwise
*/
public ReactInstanceManagerBuilder setJsEngineAsHermes(boolean hermesEnabled){
if(hermesEnabled){
setJSEngine(JSInterpreter.HERMES);
}
else{
setJSEngine(JSInterpreter.JSC);
}
return this;
}

/**
* Path to your app's main module on Metro. This is used when reloading JS during development. All
* paths are relative to the root folder the packager is serving files from. Examples: {@code
Expand Down Expand Up @@ -344,42 +371,45 @@ public ReactInstanceManager build() {
}

private JavaScriptExecutorFactory getDefaultJSExecutorFactory(
String appName, String deviceName, Context applicationContext) {
try {
// If JSC is included, use it as normal
initializeSoLoaderIfNecessary(applicationContext);
JSCExecutor.loadLibrary();
return new JSCExecutorFactory(appName, deviceName);
} catch (UnsatisfiedLinkError jscE) {
// https://github.com/facebook/hermes/issues/78 shows that
// people who aren't trying to use Hermes are having issues.
// https://github.com/facebook/react-native/issues/25923#issuecomment-554295179
// includes the actual JSC error in at least one case.
//
// So, if "__cxa_bad_typeid" shows up in the jscE exception
// message, then we will assume that's the failure and just
// throw now.

if (jscE.getMessage().contains("__cxa_bad_typeid")) {
throw jscE;
}

// Otherwise use Hermes
String appName, String deviceName, Context applicationContext) {
// Relying solely on try catch block and loading jsc even when
// project is using hermes can lead to launch-time crashes especially in
// monorepo architectures and hybrid apps using both native android
// and react native.
// So we can use the value of enableHermes received by the constructor
// to decide which library to load at launch

// if nothing is specified, use old loading method
// else load the required engine
if (jsInterpreter == JSInterpreter.OLD_LOGIC) {
try {
// If JSC is included, use it as normal
initializeSoLoaderIfNecessary(applicationContext);
JSCExecutor.loadLibrary();
return new JSCExecutorFactory(appName, deviceName);
} catch (UnsatisfiedLinkError jscE) {
if (jscE.getMessage().contains("__cxa_bad_typeid")) {
throw jscE;
}
HermesExecutor.loadLibrary();
return new HermesExecutorFactory();
} catch (UnsatisfiedLinkError hermesE) {
// If we get here, either this is a JSC build, and of course
// Hermes failed (since it's not in the APK), or it's a Hermes
// build, and Hermes had a problem.

// We suspect this is a JSC issue (it's the default), so we
// will throw that exception, but we will print hermesE first,
// since it could be a Hermes issue and we don't want to
// swallow that.
hermesE.printStackTrace();
throw jscE;
}
} else if (jsInterpreter == JSInterpreter.HERMES) {
HermesExecutor.loadLibrary();
try {
AirtelLogger.getInstance().getLogBreadCrumb().invoke(AirtelLogger.getInstance().getBreadcrumbLoggerInstance(),
"ReactInstanceManagerBuilder", "Hermes loaded");
}
catch (Exception ignored){}
return new HermesExecutorFactory();
} else {
JSCExecutor.loadLibrary();
try {
AirtelLogger.getInstance().getLogBreadCrumb().invoke(AirtelLogger.getInstance().getBreadcrumbLoggerInstance(),
"ReactInstanceManagerBuilder", "JSC loaded");
}
catch (Exception ignored){}
return new JSCExecutorFactory(appName, deviceName);
}
}
}