Setting bridge up for sharing: allowing native modules to register after init

Reviewed By: javache

Differential Revision: D4945784

fbshipit-source-id: 80e7236e9ccd5d5c9a7fba7c96b98fc38b43a2fc
This commit is contained in:
Kathy Gray
2017-06-21 11:56:08 -07:00
committed by Facebook Github Bot
parent 1ae54b5108
commit 5c5410459e
13 changed files with 217 additions and 67 deletions

View File

@@ -287,6 +287,7 @@ public class ReactInstanceManager {
*
* Called from UI thread.
*/
@ThreadConfined(UI)
public void createReactContextInBackground() {
Log.d(ReactConstants.TAG, "ReactInstanceManager.createReactContextInBackground()");
Assertions.assertCondition(
@@ -299,6 +300,33 @@ public class ReactInstanceManager {
recreateReactContextInBackgroundInner();
}
@ThreadConfined(UI)
public void registerAdditionalPackages(List<ReactPackage> packages) {
if (packages == null || packages.isEmpty()) {
return;
}
// CatalystInstance hasn't been created, so add packages for later evaluation
if (!hasStartedCreatingInitialContext()) {
for (ReactPackage p : packages) {
if (!mPackages.contains(p)) {
mPackages.add(p);
}
}
return;
}
ReactContext context = getCurrentReactContext();
CatalystInstance catalystInstance = context != null ? context.getCatalystInstance() : null;
Assertions.assertNotNull(catalystInstance, "CatalystInstance null after hasStartedCreatingInitialContext true.");
final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext);
NativeModuleRegistry nativeModuleRegistry = processPackages(reactContext, packages, true);
catalystInstance.extendNativeModules(nativeModuleRegistry);
}
/**
* Recreate the react application and context. This should be called if configuration has
* changed or the developer has requested the app to be reloaded. It should only be called after
@@ -806,7 +834,6 @@ public class ReactInstanceManager {
if (!mSetupReactContextInBackgroundEnabled) {
UiThreadUtil.assertOnUiThread();
}
Assertions.assertCondition(mCurrentReactContext == null);
mCurrentReactContext = Assertions.assertNotNull(reactContext);
CatalystInstance catalystInstance =
Assertions.assertNotNull(reactContext.getCatalystInstance());
@@ -922,56 +949,23 @@ public class ReactInstanceManager {
Log.d(ReactConstants.TAG, "ReactInstanceManager.createReactContext()");
ReactMarker.logMarker(CREATE_REACT_CONTEXT_START);
final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext);
NativeModuleRegistryBuilder nativeModuleRegistryBuilder = new NativeModuleRegistryBuilder(
reactContext,
this,
mLazyNativeModulesEnabled);
if (mUseDeveloperSupport) {
reactContext.setNativeModuleCallExceptionHandler(mDevSupportManager);
}
ReactMarker.logMarker(PROCESS_PACKAGES_START);
Systrace.beginSection(
TRACE_TAG_REACT_JAVA_BRIDGE,
"createAndProcessCoreModulesPackage");
try {
CoreModulesPackage coreModulesPackage =
new CoreModulesPackage(
this,
mBackBtnHandler,
mUIImplementationProvider,
mLazyViewManagersEnabled);
processPackage(coreModulesPackage, nativeModuleRegistryBuilder);
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
}
// TODO(6818138): Solve use-case of native/js modules overriding
for (ReactPackage reactPackage : mPackages) {
Systrace.beginSection(
TRACE_TAG_REACT_JAVA_BRIDGE,
"createAndProcessCustomReactPackage");
try {
processPackage(reactPackage, nativeModuleRegistryBuilder);
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
}
}
ReactMarker.logMarker(PROCESS_PACKAGES_END);
ReactMarker.logMarker(BUILD_NATIVE_MODULE_REGISTRY_START);
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "buildNativeModuleRegistry");
NativeModuleRegistry nativeModuleRegistry;
try {
nativeModuleRegistry = nativeModuleRegistryBuilder.build();
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
ReactMarker.logMarker(BUILD_NATIVE_MODULE_REGISTRY_END);
}
CoreModulesPackage coreModulesPackage =
new CoreModulesPackage(
this,
mBackBtnHandler,
mUIImplementationProvider,
mLazyViewManagersEnabled);
mPackages.add(coreModulesPackage);
NativeModuleRegistry nativeModuleRegistry = processPackages(reactContext, mPackages, false);
NativeModuleCallExceptionHandler exceptionHandler = mNativeModuleCallExceptionHandler != null
? mNativeModuleCallExceptionHandler
: mDevSupportManager;
? mNativeModuleCallExceptionHandler
: mDevSupportManager;
CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder()
.setReactQueueConfigurationSpec(mUseSeparateUIBackgroundThread ?
ReactQueueConfigurationSpec.createWithSeparateUIBackgroundThread() :
@@ -1006,6 +1000,49 @@ public class ReactInstanceManager {
return reactContext;
}
private NativeModuleRegistry processPackages(
ReactApplicationContext reactContext,
List<ReactPackage> packages,
boolean checkAndUpdatePackageMembership) {
NativeModuleRegistryBuilder nativeModuleRegistryBuilder = new NativeModuleRegistryBuilder(
reactContext,
this,
mLazyNativeModulesEnabled);
ReactMarker.logMarker(PROCESS_PACKAGES_START);
// TODO(6818138): Solve use-case of native modules overriding
for (ReactPackage reactPackage : packages) {
if (checkAndUpdatePackageMembership && mPackages.contains(reactPackage)) {
continue;
}
Systrace.beginSection(
TRACE_TAG_REACT_JAVA_BRIDGE,
"createAndProcessCustomReactPackage");
try {
if (checkAndUpdatePackageMembership) {
mPackages.add(reactPackage);
}
processPackage(reactPackage, nativeModuleRegistryBuilder);
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
}
}
ReactMarker.logMarker(PROCESS_PACKAGES_END);
ReactMarker.logMarker(BUILD_NATIVE_MODULE_REGISTRY_START);
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "buildNativeModuleRegistry");
NativeModuleRegistry nativeModuleRegistry;
try {
nativeModuleRegistry = nativeModuleRegistryBuilder.build();
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
ReactMarker.logMarker(BUILD_NATIVE_MODULE_REGISTRY_END);
}
return nativeModuleRegistry;
}
private void processPackage(
ReactPackage reactPackage,
NativeModuleRegistryBuilder nativeModuleRegistryBuilder) {

View File

@@ -197,8 +197,8 @@ public class ReactInstanceManagerBuilder {
public ReactInstanceManagerBuilder setUseSeparateUIBackgroundThread(
boolean useSeparateUIBackgroundThread) {
mUseSeparateUIBackgroundThread = useSeparateUIBackgroundThread;
return this;
mUseSeparateUIBackgroundThread = useSeparateUIBackgroundThread;
return this;
}
public ReactInstanceManagerBuilder setMinNumShakes(int minNumShakes) {

View File

@@ -68,6 +68,12 @@ public interface CatalystInstance
<T extends NativeModule> T getNativeModule(Class<T> nativeModuleInterface);
Collection<NativeModule> getNativeModules();
/**
* This method permits a CatalystInstance to extend the known
* Native modules. This provided registry contains only the new modules to load.
*/
void extendNativeModules(NativeModuleRegistry modules);
/**
* 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

View File

@@ -157,6 +157,26 @@ public class CatalystInstanceImpl implements CatalystInstance {
}
}
/**
* This method and the native below permits a CatalystInstance to extend the known
* Native modules. This registry contains only the new modules to load. The
* registry {@code mNativeModuleRegistry} updates internally to contain all the new modules, and generates
* the new registry for extracting just the new collections.
*/
@Override
public void extendNativeModules(NativeModuleRegistry modules) {
//Extend the Java-visible registry of modules
mNativeModuleRegistry.registerModules(modules);
Collection<JavaModuleWrapper> javaModules = modules.getJavaModules(this);
Collection<ModuleHolder> cxxModules = modules.getCxxModules();
//Extend the Cxx-visible registry of modules wrapped in appropriate interfaces
jniExtendNativeModules(javaModules, cxxModules);
}
private native void jniExtendNativeModules(
Collection<JavaModuleWrapper> javaModules,
Collection<ModuleHolder> cxxModules);
private native void initializeBridge(
ReactCallback callback,
JavaScriptExecutor jsExecutor,

View File

@@ -13,6 +13,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import com.facebook.infer.annotation.Assertions;
import com.facebook.systrace.Systrace;
@@ -35,6 +36,21 @@ public class NativeModuleRegistry {
mBatchCompleteListenerModules = batchCompleteListenerModules;
}
/**
* Private getters for combining NativeModuleRegistrys
*/
private Map<Class<? extends NativeModule>, ModuleHolder> getModuleMap() {
return mModules;
}
private ReactApplicationContext getReactApplicationContext() {
return mReactApplicationContext;
}
private ArrayList<ModuleHolder> getBatchCompleteListenerModules() {
return mBatchCompleteListenerModules;
}
/* package */ Collection<JavaModuleWrapper> getJavaModules(
JSInstance jsInstance) {
ArrayList<JavaModuleWrapper> javaModules = new ArrayList<>();
@@ -58,6 +74,29 @@ public class NativeModuleRegistry {
return cxxModules;
}
/*
* Adds any new modules to the current module regsitry
*/
/* package */ void registerModules(NativeModuleRegistry newRegister) {
Assertions.assertCondition(mReactApplicationContext.equals(newRegister.getReactApplicationContext()),
"Extending native modules with non-matching application contexts.");
Map<Class<? extends NativeModule>, ModuleHolder> newModules = newRegister.getModuleMap();
ArrayList<ModuleHolder> batchCompleteListeners = newRegister.getBatchCompleteListenerModules();
for (Map.Entry<Class<? extends NativeModule>, ModuleHolder> entry : newModules.entrySet()) {
Class<? extends NativeModule> key = entry.getKey();
if (!mModules.containsKey(key)) {
ModuleHolder value = entry.getValue();
if (batchCompleteListeners.contains(value)) {
mBatchCompleteListenerModules.add(value);
}
mModules.put(key, value);
}
}
}
/* package */ void notifyJSInstanceDestroy() {
mReactApplicationContext.assertOnNativeModulesQueueThread();
Systrace.beginSection(