Skip to content

Commit

Permalink
Update the template to load the correct JS engine at runtime. (facebo…
Browse files Browse the repository at this point in the history
…ok#35095)

Summary:
Pull Request resolved: facebook#35095

This change will make sure that we load the correct JS engine at runtime,
by using the BuildConfig flag that RNGP sets for us.

This will solve a lot of noise in adb logcat for users seeing
stacktraces mentioning failing to load `jscexecutor` library.

This is also a breaking change, but as the API was not widely used nor
advertised in the template, we should be fine by just mentioning this in the release notes.

Changelog:
[Android] [Changed] - Update the template to load the correct JS engine at runtime

Reviewed By: cipolleschi

Differential Revision: D40710597

fbshipit-source-id: d59a7a52b22a9bf273ea89094c6620c3ecf6eb00
  • Loading branch information
cortinico authored and OlimpiaZurek committed May 22, 2023
1 parent 413fc2b commit 958a32a
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 44 deletions.
@@ -0,0 +1,18 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

package com.facebook.react;

/**
* An enum that specifies the algorithm to use when loading theJS Engine. {@link #JSC} will load
* JavaScriptCore first and fail if it is not available. {@link #HERMES} will load Hermes first and
* fail if it is not available.
*/
public enum JSEngineResolutionAlgorithm {
JSC,
HERMES
}
18 changes: 0 additions & 18 deletions ReactAndroid/src/main/java/com/facebook/react/JSInterpreter.java

This file was deleted.

Expand Up @@ -14,6 +14,7 @@
import android.app.Application;
import android.content.Context;
import androidx.annotation.Nullable;
import com.facebook.common.logging.FLog;
import com.facebook.hermes.reactexecutor.HermesExecutor;
import com.facebook.hermes.reactexecutor.HermesExecutorFactory;
import com.facebook.infer.annotation.Assertions;
Expand All @@ -40,6 +41,8 @@
/** Builder class for {@link ReactInstanceManager} */
public class ReactInstanceManagerBuilder {

private static final String TAG = ReactInstanceManagerBuilder.class.getSimpleName();

private final List<ReactPackage> mPackages = new ArrayList<>();

private @Nullable String mJSBundleAssetUrl;
Expand All @@ -64,7 +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;
private JSEngineResolutionAlgorithm jsEngineResolutionAlgorithm = null;

/* package protected */ ReactInstanceManagerBuilder() {}

Expand Down Expand Up @@ -118,28 +121,12 @@ public ReactInstanceManagerBuilder setJSBundleLoader(JSBundleLoader jsBundleLoad
}

/**
* 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
* Sets the JS Engine to load as either Hermes or JSC. If not set, the default is JSC with a
* Hermes fallback.
*/
public ReactInstanceManagerBuilder setJsEngineAsHermes(boolean hermesEnabled) {
if (hermesEnabled) {
setJSEngine(JSInterpreter.HERMES);
} else {
setJSEngine(JSInterpreter.JSC);
}
return this;
private void setJSEngineResolutionAlgorithm(
@Nullable JSEngineResolutionAlgorithm jsEngineResolutionAlgorithm) {
this.jsEngineResolutionAlgorithm = jsEngineResolutionAlgorithm;
}

/**
Expand Down Expand Up @@ -365,7 +352,11 @@ private JavaScriptExecutorFactory getDefaultJSExecutorFactory(

// if nothing is specified, use old loading method
// else load the required engine
if (jsInterpreter == JSInterpreter.OLD_LOGIC) {
if (jsEngineResolutionAlgorithm == null) {
FLog.w(
TAG,
"You're not setting the JS Engine Resolution Algorithm. "
+ "We'll try to load JSC first, and if it fails we'll fallback to Hermes");
try {
// If JSC is included, use it as normal
initializeSoLoaderIfNecessary(applicationContext);
Expand All @@ -378,7 +369,7 @@ private JavaScriptExecutorFactory getDefaultJSExecutorFactory(
HermesExecutor.loadLibrary();
return new HermesExecutorFactory();
}
} else if (jsInterpreter == JSInterpreter.HERMES) {
} else if (jsEngineResolutionAlgorithm == JSEngineResolutionAlgorithm.HERMES) {
HermesExecutor.loadLibrary();
return new HermesExecutorFactory();
} else {
Expand Down
Expand Up @@ -190,4 +190,12 @@ protected String getJSMainModuleName() {
* default ones, you'll want to include more packages here.
*/
protected abstract List<ReactPackage> getPackages();

/**
* Returns the {@link JSEngineResolutionAlgorithm} to be used when loading the JS engine. If null,
* will try to load JSC first and fallback to Hermes if JSC is not available.
*/
protected @Nullable JSEngineResolutionAlgorithm getJSEngineResolutionAlgorithm() {
return null;
}
}
Expand Up @@ -8,6 +8,7 @@
package com.facebook.react.defaults

import android.app.Application
import com.facebook.react.JSEngineResolutionAlgorithm
import com.facebook.react.ReactNativeHost
import com.facebook.react.ReactPackageTurboModuleManagerDelegate
import com.facebook.react.bridge.JSIModulePackage
Expand All @@ -20,8 +21,10 @@ import com.facebook.react.bridge.JSIModulePackage
* providing the default TurboModuleManagerDelegateBuilder and the default JSIModulePackage,
* provided the name of the dynamic library to load.
*/
abstract class DefaultReactNativeHost protected constructor(application: Application) :
ReactNativeHost(application) {
abstract class DefaultReactNativeHost
protected constructor(
application: Application,
) : ReactNativeHost(application) {

override fun getReactPackageTurboModuleManagerDelegateBuilder():
ReactPackageTurboModuleManagerDelegate.Builder? =
Expand All @@ -38,6 +41,13 @@ abstract class DefaultReactNativeHost protected constructor(application: Applica
null
}

override fun getJSEngineResolutionAlgorithm(): JSEngineResolutionAlgorithm? =
when (isHermesEnabled) {
true -> JSEngineResolutionAlgorithm.HERMES
false -> JSEngineResolutionAlgorithm.JSC
null -> null
}

/**
* Returns whether the user wants to use the New Architecture or not.
*
Expand All @@ -48,4 +58,14 @@ abstract class DefaultReactNativeHost protected constructor(application: Applica
*/
protected open val isNewArchEnabled: Boolean
get() = false

/**
* Returns whether the user wants to use Hermes.
*
* If true, the app will load the Hermes engine, and fail if not found. If false, the app will
* load the JSC engine, and fail if not found. If null, the app will attempt to load JSC first and
* fallback to Hermes if not found.
*/
protected open val isHermesEnabled: Boolean?
get() = null
}
2 changes: 2 additions & 0 deletions packages/rn-tester/android/app/build.gradle
Expand Up @@ -138,9 +138,11 @@ android {
productFlavors {
hermes {
dimension "vm"
buildConfigField("boolean", "IS_HERMES_ENABLED_IN_FLAVOR", "true")
}
jsc {
dimension "vm"
buildConfigField("boolean", "IS_HERMES_ENABLED_IN_FLAVOR", "false")
}
}

Expand Down
Expand Up @@ -115,6 +115,11 @@ public List<ViewManager> createViewManagers(
protected boolean isNewArchEnabled() {
return true;
}

@Override
protected Boolean isHermesEnabled() {
return BuildConfig.IS_HERMES_ENABLED_IN_FLAVOR;
}
};

@Override
Expand Down
Expand Up @@ -37,6 +37,11 @@ protected String getJSMainModuleName() {
protected boolean isNewArchEnabled() {
return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
}

@Override
protected Boolean isHermesEnabled() {
return BuildConfig.IS_HERMES_ENABLED;
}
};

@Override
Expand Down

0 comments on commit 958a32a

Please sign in to comment.