From db391a500cc150a73e9f222ff764b318439cfe83 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Wed, 14 Feb 2018 11:26:39 -0800 Subject: [PATCH] Allow installing JS binding via the RN Android bridge Reviewed By: fkgozali Differential Revision: D6979072 fbshipit-source-id: 8b4ac3769496a6a6fe3dd9ee2aac64b66604c413 --- .../facebook/react/ReactInstanceManager.java | 47 ++++++++++--------- .../react/ReactInstanceManagerBuilder.java | 12 ++++- .../com/facebook/react/ReactNativeHost.java | 6 +++ .../facebook/react/bridge/BridgeListener.java | 14 ++++++ .../react/bridge/CatalystInstanceImpl.java | 21 +++++++-- 5 files changed, 74 insertions(+), 26 deletions(-) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/bridge/BridgeListener.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java index f1b8584c0..834fa4acb 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java @@ -45,13 +45,13 @@ import com.facebook.debug.tags.ReactDebugOverlayTags; import com.facebook.infer.annotation.Assertions; import com.facebook.infer.annotation.ThreadConfined; import com.facebook.infer.annotation.ThreadSafe; +import com.facebook.react.bridge.BridgeListener; import com.facebook.react.bridge.CatalystInstance; import com.facebook.react.bridge.CatalystInstanceImpl; import com.facebook.react.bridge.JSBundleLoader; import com.facebook.react.bridge.JavaJSExecutor; import com.facebook.react.bridge.JavaScriptExecutor; import com.facebook.react.bridge.JavaScriptExecutorFactory; -import com.facebook.react.bridge.NativeArray; import com.facebook.react.bridge.NativeModuleCallExceptionHandler; import com.facebook.react.bridge.NativeModuleRegistry; import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener; @@ -124,6 +124,7 @@ public class ReactInstanceManager { */ void onReactContextInitialized(ReactContext context); } + private final List mAttachedRootViews = Collections.synchronizedList( new ArrayList()); @@ -156,6 +157,7 @@ public class ReactInstanceManager { private final @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler; private final boolean mLazyNativeModulesEnabled; private final boolean mDelayViewManagerClassLoadsEnabled; + private final @Nullable BridgeListener mBridgeListener; private class ReactContextInitParams { private final JavaScriptExecutorFactory mJsExecutorFactory; @@ -185,25 +187,26 @@ public class ReactInstanceManager { } /* package */ ReactInstanceManager( - Context applicationContext, - @Nullable Activity currentActivity, - @Nullable DefaultHardwareBackBtnHandler defaultHardwareBackBtnHandler, - JavaScriptExecutorFactory javaScriptExecutorFactory, - @Nullable JSBundleLoader bundleLoader, - @Nullable String jsMainModulePath, - List packages, - boolean useDeveloperSupport, - @Nullable NotThreadSafeBridgeIdleDebugListener bridgeIdleDebugListener, - LifecycleState initialLifecycleState, - UIImplementationProvider uiImplementationProvider, - NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler, - @Nullable RedBoxHandler redBoxHandler, - boolean lazyNativeModulesEnabled, - boolean lazyViewManagersEnabled, - boolean delayViewManagerClassLoadsEnabled, - @Nullable DevBundleDownloadListener devBundleDownloadListener, - int minNumShakes, - int minTimeLeftInFrameForNonBatchedOperationMs) { + Context applicationContext, + @Nullable Activity currentActivity, + @Nullable DefaultHardwareBackBtnHandler defaultHardwareBackBtnHandler, + JavaScriptExecutorFactory javaScriptExecutorFactory, + @Nullable JSBundleLoader bundleLoader, + @Nullable String jsMainModulePath, + List packages, + boolean useDeveloperSupport, + @Nullable NotThreadSafeBridgeIdleDebugListener bridgeIdleDebugListener, + LifecycleState initialLifecycleState, + UIImplementationProvider uiImplementationProvider, + NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler, + @Nullable RedBoxHandler redBoxHandler, + boolean lazyNativeModulesEnabled, + boolean lazyViewManagersEnabled, + boolean delayViewManagerClassLoadsEnabled, + @Nullable DevBundleDownloadListener devBundleDownloadListener, + int minNumShakes, + int minTimeLeftInFrameForNonBatchedOperationMs, + @Nullable BridgeListener bridgeListener) { Log.d(ReactConstants.TAG, "ReactInstanceManager.ctor()"); initializeSoLoaderIfNecessary(applicationContext); @@ -252,6 +255,7 @@ public class ReactInstanceManager { } mPackages.addAll(packages); } + mBridgeListener = bridgeListener; // Instantiate ReactChoreographer in UI thread. ReactChoreographer.initialize(); @@ -1100,7 +1104,8 @@ public class ReactInstanceManager { .setJSExecutor(jsExecutor) .setRegistry(nativeModuleRegistry) .setJSBundleLoader(jsBundleLoader) - .setNativeModuleCallExceptionHandler(exceptionHandler); + .setNativeModuleCallExceptionHandler(exceptionHandler) + .setBridgeListener(mBridgeListener); ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_START); // CREATE_CATALYST_INSTANCE_END is in JSCExecutor.cpp diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.java index ab5315b06..5f9042093 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.java @@ -7,6 +7,8 @@ import static com.facebook.react.modules.systeminfo.AndroidInfoHelpers.getFriend import android.app.Activity; import android.app.Application; import com.facebook.infer.annotation.Assertions; +import com.facebook.react.bridge.BridgeListener; +import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.JSBundleLoader; import com.facebook.react.bridge.JSCJavaScriptExecutorFactory; import com.facebook.react.bridge.JavaScriptExecutorFactory; @@ -48,6 +50,7 @@ public class ReactInstanceManagerBuilder { private @Nullable JavaScriptExecutorFactory mJavaScriptExecutorFactory; private int mMinNumShakes = 1; private int mMinTimeLeftInFrameForNonBatchedOperationMs = -1; + private @Nullable BridgeListener mBridgeListener; /* package protected */ ReactInstanceManagerBuilder() { } @@ -62,6 +65,12 @@ public class ReactInstanceManagerBuilder { return this; } + public ReactInstanceManagerBuilder setBridgeListener( + @Nullable BridgeListener listener) { + mBridgeListener = listener; + return this; + } + /** * Factory for desired implementation of JavaScriptExecutor. */ @@ -280,6 +289,7 @@ public class ReactInstanceManagerBuilder { mDelayViewManagerClassLoadsEnabled, mDevBundleDownloadListener, mMinNumShakes, - mMinTimeLeftInFrameForNonBatchedOperationMs); + mMinTimeLeftInFrameForNonBatchedOperationMs, + mBridgeListener); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactNativeHost.java b/ReactAndroid/src/main/java/com/facebook/react/ReactNativeHost.java index 1c12e913e..734597e83 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactNativeHost.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactNativeHost.java @@ -16,6 +16,7 @@ import java.util.List; import android.app.Application; import com.facebook.infer.annotation.Assertions; +import com.facebook.react.bridge.BridgeListener; import com.facebook.react.bridge.JavaScriptExecutorFactory; import com.facebook.react.bridge.ReactMarker; import com.facebook.react.bridge.ReactMarkerConstants; @@ -76,6 +77,7 @@ public abstract class ReactNativeHost { .setRedBoxHandler(getRedBoxHandler()) .setJavaScriptExecutorFactory(getJavaScriptExecutorFactory()) .setUIImplementationProvider(getUIImplementationProvider()) + .setBridgeListener(getBridgeListener()) .setInitialLifecycleState(LifecycleState.BEFORE_CREATE); for (ReactPackage reactPackage : getPackages()) { @@ -122,6 +124,10 @@ public abstract class ReactNativeHost { return new UIImplementationProvider(); } + protected @Nullable BridgeListener getBridgeListener() { + return null; + } + /** * Returns the name of the main module. Determines the URL used to fetch the JS bundle * from the packager server. It is only used when dev support is enabled. diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/BridgeListener.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/BridgeListener.java new file mode 100644 index 000000000..d39c72b50 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/BridgeListener.java @@ -0,0 +1,14 @@ +package com.facebook.react.bridge; + +/** + * Interface to listen to bridge events. + */ +public interface BridgeListener { + + /** + * Called right after the RN Bridge is initialized + * @param catalystInstance {@link CatalystInstance} bridge + */ + void onBridgeStarted(CatalystInstance catalystInstance); + +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java index 7afc565c2..fe3cef73f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java @@ -100,7 +100,8 @@ public class CatalystInstanceImpl implements CatalystInstance { final JavaScriptExecutor jsExecutor, final NativeModuleRegistry nativeModuleRegistry, final JSBundleLoader jsBundleLoader, - NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) { + NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler, + final BridgeListener bridgeListener) { Log.d(ReactConstants.TAG, "Initializing React Xplat Bridge."); mHybridData = initHybrid(); @@ -126,6 +127,9 @@ public class CatalystInstanceImpl implements CatalystInstance { Log.d(ReactConstants.TAG, "Initializing React Xplat Bridge after initializeBridge"); mJavaScriptContextHolder = new JavaScriptContextHolder(getJavaScriptContext()); + if (bridgeListener != null) { + bridgeListener.onBridgeStarted(this); + } } private static class BridgeCallback implements ReactCallback { @@ -134,8 +138,8 @@ public class CatalystInstanceImpl implements CatalystInstance { // and determine there's an inaccessible cycle. private final WeakReference mOuter; - public BridgeCallback(CatalystInstanceImpl outer) { - mOuter = new WeakReference(outer); + BridgeCallback(CatalystInstanceImpl outer) { + mOuter = new WeakReference<>(outer); } @Override @@ -553,6 +557,8 @@ public class CatalystInstanceImpl implements CatalystInstance { private @Nullable NativeModuleRegistry mRegistry; private @Nullable JavaScriptExecutor mJSExecutor; private @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler; + private @Nullable BridgeListener mBridgeListener; + public Builder setReactQueueConfigurationSpec( ReactQueueConfigurationSpec ReactQueueConfigurationSpec) { @@ -581,13 +587,20 @@ public class CatalystInstanceImpl implements CatalystInstance { return this; } + public Builder setBridgeListener( + BridgeListener listener) { + mBridgeListener = listener; + return this; + } + public CatalystInstanceImpl build() { return new CatalystInstanceImpl( Assertions.assertNotNull(mReactQueueConfigurationSpec), Assertions.assertNotNull(mJSExecutor), Assertions.assertNotNull(mRegistry), Assertions.assertNotNull(mJSBundleLoader), - Assertions.assertNotNull(mNativeModuleCallExceptionHandler)); + Assertions.assertNotNull(mNativeModuleCallExceptionHandler), + mBridgeListener); } } }