mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-05-01 06:22:39 +08:00
Merging cxxbridge and bridge packages
Reviewed By: javache Differential Revision: D5027875 fbshipit-source-id: 47e081069d4219bdb29f63ce8a78c1f31a590da7
This commit is contained in:
committed by
Facebook Github Bot
parent
31a0b8788f
commit
8b53a2b29b
@@ -0,0 +1,567 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.bridge;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import android.content.res.AssetManager;
|
||||
|
||||
import com.facebook.common.logging.FLog;
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.jni.HybridData;
|
||||
import com.facebook.proguard.annotations.DoNotStrip;
|
||||
import com.facebook.react.bridge.CatalystInstance;
|
||||
import com.facebook.react.bridge.JavaScriptModule;
|
||||
import com.facebook.react.bridge.JavaScriptModuleRegistry;
|
||||
import com.facebook.react.bridge.MemoryPressure;
|
||||
import com.facebook.react.bridge.NativeArray;
|
||||
import com.facebook.react.bridge.NativeModule;
|
||||
import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
|
||||
import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener;
|
||||
import com.facebook.react.bridge.queue.MessageQueueThread;
|
||||
import com.facebook.react.bridge.queue.QueueThreadExceptionHandler;
|
||||
import com.facebook.react.bridge.queue.ReactQueueConfiguration;
|
||||
import com.facebook.react.bridge.queue.ReactQueueConfigurationImpl;
|
||||
import com.facebook.react.bridge.queue.ReactQueueConfigurationSpec;
|
||||
import com.facebook.react.common.ReactConstants;
|
||||
import com.facebook.react.common.annotations.VisibleForTesting;
|
||||
import com.facebook.soloader.SoLoader;
|
||||
import com.facebook.systrace.Systrace;
|
||||
import com.facebook.systrace.TraceListener;
|
||||
|
||||
/**
|
||||
* This provides an implementation of the public CatalystInstance instance. It is public because
|
||||
* it is built by XReactInstanceManager which is in a different package.
|
||||
*/
|
||||
@DoNotStrip
|
||||
public class CatalystInstanceImpl implements CatalystInstance {
|
||||
|
||||
/* package */ static final String REACT_NATIVE_LIB = "reactnativejnifb";
|
||||
|
||||
static {
|
||||
SoLoader.loadLibrary(REACT_NATIVE_LIB);
|
||||
}
|
||||
|
||||
private static final AtomicInteger sNextInstanceIdForTrace = new AtomicInteger(1);
|
||||
|
||||
private static class PendingJSCall {
|
||||
|
||||
public String mModule;
|
||||
public String mMethod;
|
||||
public NativeArray mArguments;
|
||||
|
||||
public PendingJSCall(
|
||||
String module,
|
||||
String method,
|
||||
NativeArray arguments) {
|
||||
mModule = module;
|
||||
mMethod = method;
|
||||
mArguments = arguments;
|
||||
}
|
||||
}
|
||||
|
||||
// Access from any thread
|
||||
private final ReactQueueConfigurationImpl mReactQueueConfiguration;
|
||||
private final CopyOnWriteArrayList<NotThreadSafeBridgeIdleDebugListener> mBridgeIdleListeners;
|
||||
private final AtomicInteger mPendingJSCalls = new AtomicInteger(0);
|
||||
private final String mJsPendingCallsTitleForTrace =
|
||||
"pending_js_calls_instance" + sNextInstanceIdForTrace.getAndIncrement();
|
||||
private volatile boolean mDestroyed = false;
|
||||
private final TraceListener mTraceListener;
|
||||
private final JavaScriptModuleRegistry mJSModuleRegistry;
|
||||
private final JSBundleLoader mJSBundleLoader;
|
||||
private final ArrayList<PendingJSCall> mJSCallsPendingInit = new ArrayList<PendingJSCall>();
|
||||
private final Object mJSCallsPendingInitLock = new Object();
|
||||
|
||||
private final NativeModuleRegistry mJavaRegistry;
|
||||
private final NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
|
||||
private final MessageQueueThread mNativeModulesQueueThread;
|
||||
private final @Nullable MessageQueueThread mUIBackgroundQueueThread;
|
||||
private boolean mInitialized = false;
|
||||
private volatile boolean mAcceptCalls = false;
|
||||
|
||||
private boolean mJSBundleHasLoaded;
|
||||
private @Nullable String mSourceURL;
|
||||
|
||||
// C++ parts
|
||||
private final HybridData mHybridData;
|
||||
private native static HybridData initHybrid();
|
||||
|
||||
private CatalystInstanceImpl(
|
||||
final ReactQueueConfigurationSpec ReactQueueConfigurationSpec,
|
||||
final JavaScriptExecutor jsExecutor,
|
||||
final NativeModuleRegistry registry,
|
||||
final JavaScriptModuleRegistry jsModuleRegistry,
|
||||
final JSBundleLoader jsBundleLoader,
|
||||
NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
|
||||
FLog.d(ReactConstants.TAG, "Initializing React Xplat Bridge.");
|
||||
mHybridData = initHybrid();
|
||||
|
||||
mReactQueueConfiguration = ReactQueueConfigurationImpl.create(
|
||||
ReactQueueConfigurationSpec,
|
||||
new NativeExceptionHandler());
|
||||
mBridgeIdleListeners = new CopyOnWriteArrayList<>();
|
||||
mJavaRegistry = registry;
|
||||
mJSModuleRegistry = jsModuleRegistry;
|
||||
mJSBundleLoader = jsBundleLoader;
|
||||
mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
|
||||
mNativeModulesQueueThread = mReactQueueConfiguration.getNativeModulesQueueThread();
|
||||
mUIBackgroundQueueThread = mReactQueueConfiguration.getUIBackgroundQueueThread();
|
||||
mTraceListener = new JSProfilerTraceListener(this);
|
||||
|
||||
FLog.d(ReactConstants.TAG, "Initializing React Xplat Bridge before initializeBridge");
|
||||
initializeBridge(
|
||||
new BridgeCallback(this),
|
||||
jsExecutor,
|
||||
mReactQueueConfiguration.getJSQueueThread(),
|
||||
mNativeModulesQueueThread,
|
||||
mUIBackgroundQueueThread,
|
||||
mJavaRegistry.getJavaModules(this),
|
||||
mJavaRegistry.getCxxModules());
|
||||
FLog.d(ReactConstants.TAG, "Initializing React Xplat Bridge after initializeBridge");
|
||||
}
|
||||
|
||||
private static class BridgeCallback implements ReactCallback {
|
||||
// We do this so the callback doesn't keep the CatalystInstanceImpl alive.
|
||||
// In this case, the callback is held in C++ code, so the GC can't see it
|
||||
// and determine there's an inaccessible cycle.
|
||||
private final WeakReference<CatalystInstanceImpl> mOuter;
|
||||
|
||||
public BridgeCallback(CatalystInstanceImpl outer) {
|
||||
mOuter = new WeakReference<CatalystInstanceImpl>(outer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBatchComplete() {
|
||||
CatalystInstanceImpl impl = mOuter.get();
|
||||
if (impl != null) {
|
||||
impl.mJavaRegistry.onBatchComplete();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incrementPendingJSCalls() {
|
||||
CatalystInstanceImpl impl = mOuter.get();
|
||||
if (impl != null) {
|
||||
impl.incrementPendingJSCalls();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decrementPendingJSCalls() {
|
||||
CatalystInstanceImpl impl = mOuter.get();
|
||||
if (impl != null) {
|
||||
impl.decrementPendingJSCalls();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private native void initializeBridge(
|
||||
ReactCallback callback,
|
||||
JavaScriptExecutor jsExecutor,
|
||||
MessageQueueThread jsQueue,
|
||||
MessageQueueThread moduleQueue,
|
||||
MessageQueueThread uiBackgroundQueue,
|
||||
Collection<JavaModuleWrapper> javaModules,
|
||||
Collection<ModuleHolder> cxxModules);
|
||||
|
||||
/**
|
||||
* This API is used in situations where the JS bundle is being executed not on
|
||||
* the device, but on a host machine. In that case, we must provide two source
|
||||
* URLs for the JS bundle: One to be used on the device, and one to be used on
|
||||
* the remote debugging machine.
|
||||
*
|
||||
* @param deviceURL A source URL that is accessible from this device.
|
||||
* @param remoteURL A source URL that is accessible from the remote machine
|
||||
* executing the JS.
|
||||
*/
|
||||
/* package */ void setSourceURLs(String deviceURL, String remoteURL) {
|
||||
mSourceURL = deviceURL;
|
||||
jniSetSourceURL(remoteURL);
|
||||
}
|
||||
|
||||
/* package */ void loadScriptFromAssets(AssetManager assetManager, String assetURL) {
|
||||
mSourceURL = assetURL;
|
||||
jniLoadScriptFromAssets(assetManager, assetURL);
|
||||
}
|
||||
|
||||
/* package */ void loadScriptFromFile(String fileName, String sourceURL) {
|
||||
mSourceURL = sourceURL;
|
||||
jniLoadScriptFromFile(fileName, sourceURL);
|
||||
}
|
||||
|
||||
private native void jniSetSourceURL(String sourceURL);
|
||||
private native void jniLoadScriptFromAssets(AssetManager assetManager, String assetURL);
|
||||
private native void jniLoadScriptFromFile(String fileName, String sourceURL);
|
||||
|
||||
@Override
|
||||
public void runJSBundle() {
|
||||
Assertions.assertCondition(!mJSBundleHasLoaded, "JS bundle was already loaded!");
|
||||
mJSBundleHasLoaded = true;
|
||||
|
||||
// incrementPendingJSCalls();
|
||||
mJSBundleLoader.loadScript(CatalystInstanceImpl.this);
|
||||
|
||||
synchronized (mJSCallsPendingInitLock) {
|
||||
// Loading the bundle is queued on the JS thread, but may not have
|
||||
// run yet. It's safe to set this here, though, since any work it
|
||||
// gates will be queued on the JS thread behind the load.
|
||||
mAcceptCalls = true;
|
||||
|
||||
for (PendingJSCall call : mJSCallsPendingInit) {
|
||||
jniCallJSFunction(call.mModule, call.mMethod, call.mArguments);
|
||||
}
|
||||
mJSCallsPendingInit.clear();
|
||||
}
|
||||
|
||||
// This is registered after JS starts since it makes a JS call
|
||||
Systrace.registerListener(mTraceListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getSourceURL() {
|
||||
return mSourceURL;
|
||||
}
|
||||
|
||||
private native void jniCallJSFunction(
|
||||
String module,
|
||||
String method,
|
||||
NativeArray arguments);
|
||||
|
||||
@Override
|
||||
public void callFunction(
|
||||
final String module,
|
||||
final String method,
|
||||
final NativeArray arguments) {
|
||||
if (mDestroyed) {
|
||||
FLog.w(ReactConstants.TAG, "Calling JS function after bridge has been destroyed.");
|
||||
return;
|
||||
}
|
||||
if (!mAcceptCalls) {
|
||||
// Most of the time the instance is initialized and we don't need to acquire the lock
|
||||
synchronized (mJSCallsPendingInitLock) {
|
||||
if (!mAcceptCalls) {
|
||||
mJSCallsPendingInit.add(new PendingJSCall(module, method, arguments));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
jniCallJSFunction(module, method, arguments);
|
||||
}
|
||||
|
||||
private native void jniCallJSCallback(int callbackID, NativeArray arguments);
|
||||
|
||||
@Override
|
||||
public void invokeCallback(final int callbackID, final NativeArray arguments) {
|
||||
if (mDestroyed) {
|
||||
FLog.w(ReactConstants.TAG, "Invoking JS callback after bridge has been destroyed.");
|
||||
return;
|
||||
}
|
||||
|
||||
jniCallJSCallback(callbackID, arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys this catalyst instance, waiting for any other threads in ReactQueueConfiguration
|
||||
* (besides the UI thread) to finish running. Must be called from the UI thread so that we can
|
||||
* fully shut down other threads.
|
||||
*/
|
||||
@Override
|
||||
public void destroy() {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
|
||||
if (mDestroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: tell all APIs to shut down
|
||||
mDestroyed = true;
|
||||
mNativeModulesQueueThread.runOnQueue(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mJavaRegistry.notifyJSInstanceDestroy();
|
||||
boolean wasIdle = (mPendingJSCalls.getAndSet(0) == 0);
|
||||
if (!wasIdle && !mBridgeIdleListeners.isEmpty()) {
|
||||
for (NotThreadSafeBridgeIdleDebugListener listener : mBridgeIdleListeners) {
|
||||
listener.onTransitionToBridgeIdle();
|
||||
}
|
||||
}
|
||||
mHybridData.resetNative();
|
||||
}
|
||||
});
|
||||
|
||||
// This is a noop if the listener was not yet registered.
|
||||
Systrace.unregisterListener(mTraceListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDestroyed() {
|
||||
return mDestroyed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize all the native modules
|
||||
*/
|
||||
@VisibleForTesting
|
||||
@Override
|
||||
public void initialize() {
|
||||
Assertions.assertCondition(
|
||||
!mInitialized,
|
||||
"This catalyst instance has already been initialized");
|
||||
// We assume that the instance manager blocks on running the JS bundle. If
|
||||
// that changes, then we need to set mAcceptCalls just after posting the
|
||||
// task that will run the js bundle.
|
||||
Assertions.assertCondition(
|
||||
mAcceptCalls,
|
||||
"RunJSBundle hasn't completed.");
|
||||
mInitialized = true;
|
||||
mNativeModulesQueueThread.runOnQueue(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mJavaRegistry.notifyJSInstanceInitialized();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReactQueueConfiguration getReactQueueConfiguration() {
|
||||
return mReactQueueConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends JavaScriptModule> T getJSModule(Class<T> jsInterface) {
|
||||
return mJSModuleRegistry.getJavaScriptModule(this, jsInterface);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends NativeModule> boolean hasNativeModule(Class<T> nativeModuleInterface) {
|
||||
return mJavaRegistry.hasModule(nativeModuleInterface);
|
||||
}
|
||||
|
||||
// This is only ever called with UIManagerModule or CurrentViewerModule.
|
||||
@Override
|
||||
public <T extends NativeModule> T getNativeModule(Class<T> nativeModuleInterface) {
|
||||
return mJavaRegistry.getModule(nativeModuleInterface);
|
||||
}
|
||||
|
||||
// This is only used by com.facebook.react.modules.common.ModuleDataCleaner
|
||||
@Override
|
||||
public Collection<NativeModule> getNativeModules() {
|
||||
return mJavaRegistry.getAllModules();
|
||||
}
|
||||
|
||||
private native void handleMemoryPressureUiHidden();
|
||||
private native void handleMemoryPressureModerate();
|
||||
private native void handleMemoryPressureCritical();
|
||||
|
||||
@Override
|
||||
public void handleMemoryPressure(MemoryPressure level) {
|
||||
if (mDestroyed) {
|
||||
return;
|
||||
}
|
||||
switch (level) {
|
||||
case UI_HIDDEN:
|
||||
handleMemoryPressureUiHidden();
|
||||
break;
|
||||
case MODERATE:
|
||||
handleMemoryPressureModerate();
|
||||
break;
|
||||
case CRITICAL:
|
||||
handleMemoryPressureCritical();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a idle listener for this Catalyst instance. The listener will receive notifications
|
||||
* whenever the bridge transitions from idle to busy and vice-versa, where the busy state is
|
||||
* defined as there being some non-zero number of calls to JS that haven't resolved via a
|
||||
* onBatchComplete call. The listener should be purely passive and not affect application logic.
|
||||
*/
|
||||
@Override
|
||||
public void addBridgeIdleDebugListener(NotThreadSafeBridgeIdleDebugListener listener) {
|
||||
mBridgeIdleListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a NotThreadSafeBridgeIdleDebugListener previously added with
|
||||
* {@link #addBridgeIdleDebugListener}
|
||||
*/
|
||||
@Override
|
||||
public void removeBridgeIdleDebugListener(NotThreadSafeBridgeIdleDebugListener listener) {
|
||||
mBridgeIdleListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public native void setGlobalVariable(String propName, String jsonValue);
|
||||
|
||||
@Override
|
||||
public native long getJavaScriptContext();
|
||||
|
||||
// TODO mhorowitz: add mDestroyed checks to the next three methods
|
||||
|
||||
@Override
|
||||
public native boolean supportsProfiling();
|
||||
|
||||
@Override
|
||||
public native void startProfiler(String title);
|
||||
|
||||
@Override
|
||||
public native void stopProfiler(String title, String filename);
|
||||
|
||||
private void incrementPendingJSCalls() {
|
||||
int oldPendingCalls = mPendingJSCalls.getAndIncrement();
|
||||
boolean wasIdle = oldPendingCalls == 0;
|
||||
Systrace.traceCounter(
|
||||
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
|
||||
mJsPendingCallsTitleForTrace,
|
||||
oldPendingCalls + 1);
|
||||
if (wasIdle && !mBridgeIdleListeners.isEmpty()) {
|
||||
mNativeModulesQueueThread.runOnQueue(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (NotThreadSafeBridgeIdleDebugListener listener : mBridgeIdleListeners) {
|
||||
listener.onTransitionToBridgeBusy();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void decrementPendingJSCalls() {
|
||||
int newPendingCalls = mPendingJSCalls.decrementAndGet();
|
||||
// TODO(9604406): handle case of web workers injecting messages to main thread
|
||||
//Assertions.assertCondition(newPendingCalls >= 0);
|
||||
boolean isNowIdle = newPendingCalls == 0;
|
||||
Systrace.traceCounter(
|
||||
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
|
||||
mJsPendingCallsTitleForTrace,
|
||||
newPendingCalls);
|
||||
|
||||
if (isNowIdle && !mBridgeIdleListeners.isEmpty()) {
|
||||
mNativeModulesQueueThread.runOnQueue(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (NotThreadSafeBridgeIdleDebugListener listener : mBridgeIdleListeners) {
|
||||
listener.onTransitionToBridgeIdle();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void onNativeException(Exception e) {
|
||||
mNativeModuleCallExceptionHandler.handleException(e);
|
||||
mReactQueueConfiguration.getUIQueueThread().runOnQueue(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
destroy();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private class NativeExceptionHandler implements QueueThreadExceptionHandler {
|
||||
@Override
|
||||
public void handleException(Exception e) {
|
||||
// Any Exception caught here is because of something in JS. Even if it's a bug in the
|
||||
// framework/native code, it was triggered by JS and theoretically since we were able
|
||||
// to set up the bridge, JS could change its logic, reload, and not trigger that crash.
|
||||
onNativeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static class JSProfilerTraceListener implements TraceListener {
|
||||
// We do this so the callback doesn't keep the CatalystInstanceImpl alive.
|
||||
// In this case, Systrace will keep the registered listener around forever
|
||||
// if the CatalystInstanceImpl is not explicitly destroyed. These instances
|
||||
// can still leak, but they are at least small.
|
||||
private final WeakReference<CatalystInstanceImpl> mOuter;
|
||||
|
||||
public JSProfilerTraceListener(CatalystInstanceImpl outer) {
|
||||
mOuter = new WeakReference<CatalystInstanceImpl>(outer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTraceStarted() {
|
||||
CatalystInstanceImpl impl = mOuter.get();
|
||||
if (impl != null) {
|
||||
impl.getJSModule(com.facebook.react.bridge.Systrace.class).setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTraceStopped() {
|
||||
CatalystInstanceImpl impl = mOuter.get();
|
||||
if (impl != null) {
|
||||
impl.getJSModule(com.facebook.react.bridge.Systrace.class).setEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private @Nullable ReactQueueConfigurationSpec mReactQueueConfigurationSpec;
|
||||
private @Nullable JSBundleLoader mJSBundleLoader;
|
||||
private @Nullable NativeModuleRegistry mRegistry;
|
||||
private @Nullable JavaScriptModuleRegistry mJSModuleRegistry;
|
||||
private @Nullable JavaScriptExecutor mJSExecutor;
|
||||
private @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
|
||||
|
||||
public Builder setReactQueueConfigurationSpec(
|
||||
ReactQueueConfigurationSpec ReactQueueConfigurationSpec) {
|
||||
mReactQueueConfigurationSpec = ReactQueueConfigurationSpec;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setRegistry(NativeModuleRegistry registry) {
|
||||
mRegistry = registry;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setJSModuleRegistry(JavaScriptModuleRegistry jsModuleRegistry) {
|
||||
mJSModuleRegistry = jsModuleRegistry;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setJSBundleLoader(JSBundleLoader jsBundleLoader) {
|
||||
mJSBundleLoader = jsBundleLoader;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setJSExecutor(JavaScriptExecutor jsExecutor) {
|
||||
mJSExecutor = jsExecutor;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setNativeModuleCallExceptionHandler(
|
||||
NativeModuleCallExceptionHandler handler) {
|
||||
mNativeModuleCallExceptionHandler = handler;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CatalystInstanceImpl build() {
|
||||
return new CatalystInstanceImpl(
|
||||
Assertions.assertNotNull(mReactQueueConfigurationSpec),
|
||||
Assertions.assertNotNull(mJSExecutor),
|
||||
Assertions.assertNotNull(mRegistry),
|
||||
Assertions.assertNotNull(mJSModuleRegistry),
|
||||
Assertions.assertNotNull(mJSBundleLoader),
|
||||
Assertions.assertNotNull(mNativeModuleCallExceptionHandler));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user