diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java index 4e84fdab2..022e7826c 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java @@ -22,6 +22,7 @@ import android.widget.FrameLayout; import com.facebook.infer.annotation.Assertions; import com.facebook.react.ReactInstanceManager; +import com.facebook.react.ReactInstanceManagerBuilder; import com.facebook.react.ReactRootView; import com.facebook.react.bridge.ReactContext; import com.facebook.react.common.LifecycleState; @@ -149,7 +150,7 @@ public class ReactAppTestActivity extends FragmentActivity implements final CountDownLatch currentLayoutEvent = mLayoutEvent = new CountDownLatch(1); mBridgeIdleSignaler = new ReactBridgeIdleSignaler(); - ReactInstanceManager.Builder builder = + ReactInstanceManagerBuilder builder = ReactTestHelper.getReactTestFactory().getReactInstanceManagerBuilder() .setApplication(getApplication()) .setBundleAssetName(bundleName) diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestFactory.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestFactory.java index 42877cdd8..f77aa1665 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestFactory.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestFactory.java @@ -10,7 +10,7 @@ package com.facebook.react.testing; import android.content.Context; -import com.facebook.react.ReactInstanceManager; +import com.facebook.react.ReactInstanceManagerBuilder; import com.facebook.react.bridge.CatalystInstance; import com.facebook.react.bridge.NativeModule; @@ -23,5 +23,5 @@ public interface ReactTestFactory { } ReactInstanceEasyBuilder getCatalystInstanceBuilder(); - ReactInstanceManager.Builder getReactInstanceManagerBuilder(); + ReactInstanceManagerBuilder getReactInstanceManagerBuilder(); } diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java index 5542d7a3a..269cc43fe 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java @@ -22,6 +22,7 @@ import android.view.ViewGroup; import com.facebook.react.EagerModuleProvider; import com.facebook.react.ReactInstanceManager; +import com.facebook.react.ReactInstanceManagerBuilder; import com.facebook.react.bridge.CatalystInstance; import com.facebook.react.bridge.JavaScriptModuleRegistry; import com.facebook.react.bridge.ModuleSpec; @@ -103,7 +104,7 @@ public class ReactTestHelper { } @Override - public ReactInstanceManager.Builder getReactInstanceManagerBuilder() { + public ReactInstanceManagerBuilder getReactInstanceManagerBuilder() { return ReactInstanceManager.builder(); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java index 517ffb464..1dfee1776 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java @@ -11,25 +11,17 @@ package com.facebook.react; import javax.annotation.Nullable; -import java.util.ArrayList; import java.util.List; import android.app.Activity; -import android.app.Application; import android.content.Intent; -import com.facebook.infer.annotation.Assertions; -import com.facebook.react.bridge.NativeModuleCallExceptionHandler; -import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContext; -import com.facebook.react.common.annotations.VisibleForTesting; import com.facebook.react.common.LifecycleState; -import com.facebook.react.cxxbridge.JSBundleLoader; +import com.facebook.react.common.annotations.VisibleForTesting; import com.facebook.react.devsupport.DevSupportManager; -import com.facebook.react.devsupport.RedBoxHandler; import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; -import com.facebook.react.uimanager.UIImplementationProvider; import com.facebook.react.uimanager.ViewManager; /** @@ -200,219 +192,7 @@ public abstract class ReactInstanceManager { /** * Creates a builder that is capable of creating an instance of {@link ReactInstanceManagerImpl}. */ - public static Builder builder() { - return new Builder(); - } - - /** - * Builder class for {@link ReactInstanceManagerImpl} - */ - public static class Builder { - - protected final List mPackages = new ArrayList<>(); - - protected @Nullable String mJSBundleAssetUrl; - protected @Nullable JSBundleLoader mJSBundleLoader; - protected @Nullable String mJSMainModuleName; - protected @Nullable NotThreadSafeBridgeIdleDebugListener mBridgeIdleDebugListener; - protected @Nullable Application mApplication; - protected boolean mUseDeveloperSupport; - protected @Nullable LifecycleState mInitialLifecycleState; - protected @Nullable UIImplementationProvider mUIImplementationProvider; - protected @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler; - protected JSCConfig mJSCConfig = JSCConfig.EMPTY; - protected @Nullable Activity mCurrentActivity; - protected @Nullable DefaultHardwareBackBtnHandler mDefaultHardwareBackBtnHandler; - protected @Nullable RedBoxHandler mRedBoxHandler; - protected boolean mLazyNativeModulesEnabled; - protected boolean mLazyViewManagersEnabled; - - protected Builder() { - } - - /** - * Sets a provider of {@link UIImplementation}. - * Uses default provider if null is passed. - */ - public Builder setUIImplementationProvider( - @Nullable UIImplementationProvider uiImplementationProvider) { - mUIImplementationProvider = uiImplementationProvider; - return this; - } - - /** - * Name of the JS bundle file to be loaded from application's raw assets. - * Example: {@code "index.android.js"} - */ - public Builder setBundleAssetName(String bundleAssetName) { - mJSBundleAssetUrl = (bundleAssetName == null ? null : "assets://" + bundleAssetName); - mJSBundleLoader = null; - return this; - } - - /** - * Path to the JS bundle file to be loaded from the file system. - * - * Example: {@code "assets://index.android.js" or "/sdcard/main.jsbundle"} - */ - public Builder setJSBundleFile(String jsBundleFile) { - if (jsBundleFile.startsWith("assets://")) { - mJSBundleAssetUrl = jsBundleFile; - mJSBundleLoader = null; - return this; - } - return setJSBundleLoader(JSBundleLoader.createFileLoader(jsBundleFile)); - } - - /** - * Bundle loader to use when setting up JS environment. This supersedes - * prior invcations of {@link setJSBundleFile} and {@link setBundleAssetName}. - * - * Example: {@code JSBundleLoader.createFileLoader(application, bundleFile)} - */ - public Builder setJSBundleLoader(JSBundleLoader jsBundleLoader) { - mJSBundleLoader = jsBundleLoader; - mJSBundleAssetUrl = null; - return this; - } - - /** - * Path to your app's main module on the packager server. This is used when - * reloading JS during development. All paths are relative to the root folder - * the packager is serving files from. - * Examples: - * {@code "index.android"} or - * {@code "subdirectory/index.android"} - */ - public Builder setJSMainModuleName(String jsMainModuleName) { - mJSMainModuleName = jsMainModuleName; - return this; - } - - public Builder addPackage(ReactPackage reactPackage) { - mPackages.add(reactPackage); - return this; - } - - public Builder setBridgeIdleDebugListener( - NotThreadSafeBridgeIdleDebugListener bridgeIdleDebugListener) { - mBridgeIdleDebugListener = bridgeIdleDebugListener; - return this; - } - - /** - * Required. This must be your {@code Application} instance. - */ - public Builder setApplication(Application application) { - mApplication = application; - return this; - } - - public Builder setCurrentActivity(Activity activity) { - mCurrentActivity = activity; - return this; - } - - public Builder setDefaultHardwareBackBtnHandler( - DefaultHardwareBackBtnHandler defaultHardwareBackBtnHandler) { - mDefaultHardwareBackBtnHandler = defaultHardwareBackBtnHandler; - return this; - } - - /** - * When {@code true}, developer options such as JS reloading and debugging are enabled. - * Note you still have to call {@link #showDevOptionsDialog} to show the dev menu, - * e.g. when the device Menu button is pressed. - */ - public Builder setUseDeveloperSupport(boolean useDeveloperSupport) { - mUseDeveloperSupport = useDeveloperSupport; - return this; - } - - /** - * Sets the initial lifecycle state of the host. For example, if the host is already resumed at - * creation time, we wouldn't expect an onResume call until we get an onPause call. - */ - public Builder setInitialLifecycleState(LifecycleState initialLifecycleState) { - mInitialLifecycleState = initialLifecycleState; - return this; - } - - /** - * Set the exception handler for all native module calls. If not set, the default - * {@link DevSupportManager} will be used, which shows a redbox in dev mode and rethrows - * (crashes the app) in prod mode. - */ - public Builder setNativeModuleCallExceptionHandler(NativeModuleCallExceptionHandler handler) { - mNativeModuleCallExceptionHandler = handler; - return this; - } - - public Builder setJSCConfig(JSCConfig jscConfig) { - mJSCConfig = jscConfig; - return this; - } - - public Builder setRedBoxHandler(@Nullable RedBoxHandler redBoxHandler) { - mRedBoxHandler = redBoxHandler; - return this; - } - - public Builder setLazyNativeModulesEnabled(boolean lazyNativeModulesEnabled) { - mLazyNativeModulesEnabled = lazyNativeModulesEnabled; - return this; - } - - public Builder setLazyViewManagersEnabled(boolean lazyViewManagersEnabled) { - mLazyViewManagersEnabled = lazyViewManagersEnabled; - return this; - } - - /** - * Instantiates a new {@link ReactInstanceManagerImpl}. - * Before calling {@code build}, the following must be called: - * - */ - public ReactInstanceManager build() { - Assertions.assertNotNull( - mApplication, - "Application property has not been set with this builder"); - - Assertions.assertCondition( - mUseDeveloperSupport || mJSBundleAssetUrl != null || mJSBundleLoader != null, - "JS Bundle File or Asset URL has to be provided when dev support is disabled"); - - Assertions.assertCondition( - mJSMainModuleName != null || mJSBundleAssetUrl != null || mJSBundleLoader != null, - "Either MainModuleName or JS Bundle File needs to be provided"); - - if (mUIImplementationProvider == null) { - // create default UIImplementationProvider if the provided one is null. - mUIImplementationProvider = new UIImplementationProvider(); - } - - return new XReactInstanceManagerImpl( - mApplication, - mCurrentActivity, - mDefaultHardwareBackBtnHandler, - (mJSBundleLoader == null && mJSBundleAssetUrl != null) ? - JSBundleLoader.createAssetLoader(mApplication, mJSBundleAssetUrl) : mJSBundleLoader, - mJSMainModuleName, - mPackages, - mUseDeveloperSupport, - mBridgeIdleDebugListener, - Assertions.assertNotNull(mInitialLifecycleState, "Initial lifecycle state was not set"), - mUIImplementationProvider, - mNativeModuleCallExceptionHandler, - mJSCConfig, - mRedBoxHandler, - mLazyNativeModulesEnabled, - mLazyViewManagersEnabled); - } + public static ReactInstanceManagerBuilder builder() { + return new ReactInstanceManagerBuilder(); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.java new file mode 100644 index 000000000..d848f1559 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.java @@ -0,0 +1,235 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +package com.facebook.react; + +import javax.annotation.Nullable; + +import java.util.ArrayList; +import java.util.List; + +import android.app.Activity; +import android.app.Application; + +import com.facebook.infer.annotation.Assertions; +import com.facebook.react.bridge.NativeModuleCallExceptionHandler; +import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener; +import com.facebook.react.common.LifecycleState; +import com.facebook.react.cxxbridge.JSBundleLoader; +import com.facebook.react.devsupport.DevSupportManager; +import com.facebook.react.devsupport.RedBoxHandler; +import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; +import com.facebook.react.uimanager.UIImplementationProvider; + +/** + * Builder class for {@link ReactInstanceManager} + */ +public class ReactInstanceManagerBuilder { + + protected final List mPackages = new ArrayList<>(); + + protected @Nullable String mJSBundleAssetUrl; + protected @Nullable JSBundleLoader mJSBundleLoader; + protected @Nullable String mJSMainModuleName; + protected @Nullable NotThreadSafeBridgeIdleDebugListener mBridgeIdleDebugListener; + protected @Nullable Application mApplication; + protected boolean mUseDeveloperSupport; + protected @Nullable LifecycleState mInitialLifecycleState; + protected @Nullable UIImplementationProvider mUIImplementationProvider; + protected @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler; + protected JSCConfig mJSCConfig = JSCConfig.EMPTY; + protected @Nullable Activity mCurrentActivity; + protected @Nullable DefaultHardwareBackBtnHandler mDefaultHardwareBackBtnHandler; + protected @Nullable RedBoxHandler mRedBoxHandler; + protected boolean mLazyNativeModulesEnabled; + protected boolean mLazyViewManagersEnabled; + + /* package protected */ ReactInstanceManagerBuilder() { + } + + /** + * Sets a provider of {@link UIImplementation}. + * Uses default provider if null is passed. + */ + public ReactInstanceManagerBuilder setUIImplementationProvider( + @Nullable UIImplementationProvider uiImplementationProvider) { + mUIImplementationProvider = uiImplementationProvider; + return this; + } + + /** + * Name of the JS bundle file to be loaded from application's raw assets. + * Example: {@code "index.android.js"} + */ + public ReactInstanceManagerBuilder setBundleAssetName(String bundleAssetName) { + mJSBundleAssetUrl = (bundleAssetName == null ? null : "assets://" + bundleAssetName); + mJSBundleLoader = null; + return this; + } + + /** + * Path to the JS bundle file to be loaded from the file system. + * + * Example: {@code "assets://index.android.js" or "/sdcard/main.jsbundle"} + */ + public ReactInstanceManagerBuilder setJSBundleFile(String jsBundleFile) { + if (jsBundleFile.startsWith("assets://")) { + mJSBundleAssetUrl = jsBundleFile; + mJSBundleLoader = null; + return this; + } + return setJSBundleLoader(JSBundleLoader.createFileLoader(jsBundleFile)); + } + + /** + * Bundle loader to use when setting up JS environment. This supersedes + * prior invcations of {@link setJSBundleFile} and {@link setBundleAssetName}. + * + * Example: {@code JSBundleLoader.createFileLoader(application, bundleFile)} + */ + public ReactInstanceManagerBuilder setJSBundleLoader(JSBundleLoader jsBundleLoader) { + mJSBundleLoader = jsBundleLoader; + mJSBundleAssetUrl = null; + return this; + } + + /** + * Path to your app's main module on the packager server. This is used when + * reloading JS during development. All paths are relative to the root folder + * the packager is serving files from. + * Examples: + * {@code "index.android"} or + * {@code "subdirectory/index.android"} + */ + public ReactInstanceManagerBuilder setJSMainModuleName(String jsMainModuleName) { + mJSMainModuleName = jsMainModuleName; + return this; + } + + public ReactInstanceManagerBuilder addPackage(ReactPackage reactPackage) { + mPackages.add(reactPackage); + return this; + } + + public ReactInstanceManagerBuilder setBridgeIdleDebugListener( + NotThreadSafeBridgeIdleDebugListener bridgeIdleDebugListener) { + mBridgeIdleDebugListener = bridgeIdleDebugListener; + return this; + } + + /** + * Required. This must be your {@code Application} instance. + */ + public ReactInstanceManagerBuilder setApplication(Application application) { + mApplication = application; + return this; + } + + public ReactInstanceManagerBuilder setCurrentActivity(Activity activity) { + mCurrentActivity = activity; + return this; + } + + public ReactInstanceManagerBuilder setDefaultHardwareBackBtnHandler( + DefaultHardwareBackBtnHandler defaultHardwareBackBtnHandler) { + mDefaultHardwareBackBtnHandler = defaultHardwareBackBtnHandler; + return this; + } + + /** + * When {@code true}, developer options such as JS reloading and debugging are enabled. + * Note you still have to call {@link #showDevOptionsDialog} to show the dev menu, + * e.g. when the device Menu button is pressed. + */ + public ReactInstanceManagerBuilder setUseDeveloperSupport(boolean useDeveloperSupport) { + mUseDeveloperSupport = useDeveloperSupport; + return this; + } + + /** + * Sets the initial lifecycle state of the host. For example, if the host is already resumed at + * creation time, we wouldn't expect an onResume call until we get an onPause call. + */ + public ReactInstanceManagerBuilder setInitialLifecycleState( + LifecycleState initialLifecycleState) { + mInitialLifecycleState = initialLifecycleState; + return this; + } + + /** + * Set the exception handler for all native module calls. If not set, the default + * {@link DevSupportManager} will be used, which shows a redbox in dev mode and rethrows + * (crashes the app) in prod mode. + */ + public ReactInstanceManagerBuilder setNativeModuleCallExceptionHandler( + NativeModuleCallExceptionHandler handler) { + mNativeModuleCallExceptionHandler = handler; + return this; + } + + public ReactInstanceManagerBuilder setJSCConfig(JSCConfig jscConfig) { + mJSCConfig = jscConfig; + return this; + } + + public ReactInstanceManagerBuilder setRedBoxHandler(@Nullable RedBoxHandler redBoxHandler) { + mRedBoxHandler = redBoxHandler; + return this; + } + + public ReactInstanceManagerBuilder setLazyNativeModulesEnabled(boolean lazyNativeModulesEnabled) { + mLazyNativeModulesEnabled = lazyNativeModulesEnabled; + return this; + } + + public ReactInstanceManagerBuilder setLazyViewManagersEnabled(boolean lazyViewManagersEnabled) { + mLazyViewManagersEnabled = lazyViewManagersEnabled; + return this; + } + + /** + * Instantiates a new {@link ReactInstanceManagerImpl}. + * Before calling {@code build}, the following must be called: + * + */ + public ReactInstanceManager build() { + Assertions.assertNotNull( + mApplication, + "Application property has not been set with this builder"); + + Assertions.assertCondition( + mUseDeveloperSupport || mJSBundleAssetUrl != null || mJSBundleLoader != null, + "JS Bundle File or Asset URL has to be provided when dev support is disabled"); + + Assertions.assertCondition( + mJSMainModuleName != null || mJSBundleAssetUrl != null || mJSBundleLoader != null, + "Either MainModuleName or JS Bundle File needs to be provided"); + + if (mUIImplementationProvider == null) { + // create default UIImplementationProvider if the provided one is null. + mUIImplementationProvider = new UIImplementationProvider(); + } + + return new XReactInstanceManagerImpl( + mApplication, + mCurrentActivity, + mDefaultHardwareBackBtnHandler, + (mJSBundleLoader == null && mJSBundleAssetUrl != null) ? + JSBundleLoader.createAssetLoader(mApplication, mJSBundleAssetUrl) : mJSBundleLoader, + mJSMainModuleName, + mPackages, + mUseDeveloperSupport, + mBridgeIdleDebugListener, + Assertions.assertNotNull(mInitialLifecycleState, "Initial lifecycle state was not set"), + mUIImplementationProvider, + mNativeModuleCallExceptionHandler, + mJSCConfig, + mRedBoxHandler, + mLazyNativeModulesEnabled, + mLazyViewManagersEnabled); + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactNativeHost.java b/ReactAndroid/src/main/java/com/facebook/react/ReactNativeHost.java index 57d7b45fc..5a4e56370 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactNativeHost.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactNativeHost.java @@ -63,7 +63,7 @@ public abstract class ReactNativeHost { } protected ReactInstanceManager createReactInstanceManager() { - ReactInstanceManager.Builder builder = ReactInstanceManager.builder() + ReactInstanceManagerBuilder builder = ReactInstanceManager.builder() .setApplication(mApplication) .setJSMainModuleName(getJSMainModuleName()) .setUseDeveloperSupport(getUseDeveloperSupport())