Skip to content

Commit

Permalink
Introduce BaseReactPackage class (#40775)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #40775

In this diff I'm introducing the BaseReactPackage class to the public API of React Native Android. the goal is for this class to replace TurboReactPackage, which will be Deprecated in the New Architecture

changelog: [internal] internal

Reviewed By: christophpurrer

Differential Revision: D50128456

fbshipit-source-id: a65e1eb0d81b94e442799226784f73f489eabb73
  • Loading branch information
mdvacca authored and facebook-github-bot committed Oct 10, 2023
1 parent 7b7f128 commit 7a31ecd
Show file tree
Hide file tree
Showing 2 changed files with 162 additions and 148 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/*
* 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;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.facebook.react.bridge.ModuleHolder;
import com.facebook.react.bridge.ModuleSpec;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.config.ReactFeatureFlags;
import com.facebook.react.module.model.ReactModuleInfo;
import com.facebook.react.module.model.ReactModuleInfoProvider;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import javax.inject.Provider;

/** Abstract class that supports lazy loading of NativeModules by default. */
public abstract class BaseReactPackage implements ReactPackage {

@Override
public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
throw new UnsupportedOperationException(
"createNativeModules method is not supported. Use getModule() method instead.");
}

/**
* The API needed for TurboModules. Given a module name, it returns an instance of {@link
* NativeModule} for the name
*
* @param name name of the Native Module
* @param reactContext {@link ReactApplicationContext} context for this
*/
@Override
public abstract @Nullable NativeModule getModule(
@NonNull String name, @NonNull ReactApplicationContext reactContext);

/**
* This is a temporary method till we implement TurboModules. Once we implement TurboModules, we
* will be able to directly call {@link BaseReactPackage#getModule(String,
* ReactApplicationContext)} This method will be removed when TurboModule implementation is
* complete
*
* @param reactContext
* @return
*/
/** package */
Iterable<ModuleHolder> getNativeModuleIterator(final ReactApplicationContext reactContext) {
final Set<Map.Entry<String, ReactModuleInfo>> entrySet =
getReactModuleInfoProvider().getReactModuleInfos().entrySet();
final Iterator<Map.Entry<String, ReactModuleInfo>> entrySetIterator = entrySet.iterator();
// This should ideally be an IteratorConvertor, but we don't have any internal library for it
return () ->
new Iterator<ModuleHolder>() {
@Nullable Map.Entry<String, ReactModuleInfo> nextEntry = null;

private void findNext() {
while (entrySetIterator.hasNext()) {
Map.Entry<String, ReactModuleInfo> entry = entrySetIterator.next();
ReactModuleInfo reactModuleInfo = entry.getValue();

// This Iterator is used to create the NativeModule registry. The NativeModule
// registry must not have TurboModules. Therefore, if TurboModules are enabled, and
// the current NativeModule is a TurboModule, we need to skip iterating over it.
if (ReactFeatureFlags.useTurboModules && reactModuleInfo.isTurboModule()) {
continue;
}

nextEntry = entry;
return;
}
nextEntry = null;
}

@Override
public boolean hasNext() {
if (nextEntry == null) {
findNext();
}
return nextEntry != null;
}

@Override
public ModuleHolder next() {
if (nextEntry == null) {
findNext();
}

if (nextEntry == null) {
throw new NoSuchElementException("ModuleHolder not found");
}

Map.Entry<String, ReactModuleInfo> entry = nextEntry;

// Advance iterator
findNext();
String name = entry.getKey();
ReactModuleInfo reactModuleInfo = entry.getValue();
return new ModuleHolder(reactModuleInfo, new ModuleHolderProvider(name, reactContext));
}

@Override
public void remove() {
throw new UnsupportedOperationException("Cannot remove native modules from the list");
}
};
}

/**
* @param reactContext react application context that can be used to create View Managers.
* @return list of module specs that can create the View Managers.
*/
protected List<ModuleSpec> getViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}

@Override
public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
List<ModuleSpec> viewManagerModuleSpecs = getViewManagers(reactContext);
if (viewManagerModuleSpecs == null || viewManagerModuleSpecs.isEmpty()) {
return Collections.emptyList();
}

List<ViewManager> viewManagers = new ArrayList<>();
for (ModuleSpec moduleSpec : viewManagerModuleSpecs) {
viewManagers.add((ViewManager) moduleSpec.getProvider().get());
}
return viewManagers;
}

public abstract ReactModuleInfoProvider getReactModuleInfoProvider();

private class ModuleHolderProvider implements Provider<NativeModule> {

private final String mName;
private final ReactApplicationContext mReactContext;

public ModuleHolderProvider(String name, ReactApplicationContext reactContext) {
mName = name;
mReactContext = reactContext;
}

@Override
public @Nullable NativeModule get() {
return getModule(mName, mReactContext);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,153 +7,8 @@

package com.facebook.react;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.facebook.react.bridge.ModuleHolder;
import com.facebook.react.bridge.ModuleSpec;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.config.ReactFeatureFlags;
import com.facebook.react.module.model.ReactModuleInfo;
import com.facebook.react.module.model.ReactModuleInfoProvider;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import javax.inject.Provider;
import com.facebook.react.common.annotations.DeprecatedInNewArchitecture;

/** This will eventually replace {@link LazyReactPackage} when TurboModules are finally done. */
public abstract class TurboReactPackage implements ReactPackage {

@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
throw new UnsupportedOperationException(
"createNativeModules method is not supported. Use getModule() method instead.");
}

/**
* The API needed for TurboModules. Given a module name, it returns an instance of {@link
* NativeModule} for the name
*
* @param name name of the Native Module
* @param reactContext {@link ReactApplicationContext} context for this
*/
@Override
public abstract @Nullable NativeModule getModule(
@NonNull String name, @NonNull ReactApplicationContext reactContext);

/**
* This is a temporary method till we implement TurboModules. Once we implement TurboModules, we
* will be able to directly call {@link TurboReactPackage#getModule(String,
* ReactApplicationContext)} This method will be removed when TurboModule implementation is
* complete
*
* @param reactContext
* @return
*/
/** package */
Iterable<ModuleHolder> getNativeModuleIterator(final ReactApplicationContext reactContext) {
final Set<Map.Entry<String, ReactModuleInfo>> entrySet =
getReactModuleInfoProvider().getReactModuleInfos().entrySet();
final Iterator<Map.Entry<String, ReactModuleInfo>> entrySetIterator = entrySet.iterator();
// This should ideally be an IteratorConvertor, but we don't have any internal library for it
return () ->
new Iterator<ModuleHolder>() {
@Nullable Map.Entry<String, ReactModuleInfo> nextEntry = null;

private void findNext() {
while (entrySetIterator.hasNext()) {
Map.Entry<String, ReactModuleInfo> entry = entrySetIterator.next();
ReactModuleInfo reactModuleInfo = entry.getValue();

// This Iterator is used to create the NativeModule registry. The NativeModule
// registry must not have TurboModules. Therefore, if TurboModules are enabled, and
// the current NativeModule is a TurboModule, we need to skip iterating over it.
if (ReactFeatureFlags.useTurboModules && reactModuleInfo.isTurboModule()) {
continue;
}

nextEntry = entry;
return;
}
nextEntry = null;
}

@Override
public boolean hasNext() {
if (nextEntry == null) {
findNext();
}
return nextEntry != null;
}

@Override
public ModuleHolder next() {
if (nextEntry == null) {
findNext();
}

if (nextEntry == null) {
throw new NoSuchElementException("ModuleHolder not found");
}

Map.Entry<String, ReactModuleInfo> entry = nextEntry;

// Advance iterator
findNext();
String name = entry.getKey();
ReactModuleInfo reactModuleInfo = entry.getValue();
return new ModuleHolder(reactModuleInfo, new ModuleHolderProvider(name, reactContext));
}

@Override
public void remove() {
throw new UnsupportedOperationException("Cannot remove native modules from the list");
}
};
}

/**
* @param reactContext react application context that can be used to create View Managers.
* @return list of module specs that can create the View Managers.
*/
protected List<ModuleSpec> getViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}

@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
List<ModuleSpec> viewManagerModuleSpecs = getViewManagers(reactContext);
if (viewManagerModuleSpecs == null || viewManagerModuleSpecs.isEmpty()) {
return Collections.emptyList();
}

List<ViewManager> viewManagers = new ArrayList<>();
for (ModuleSpec moduleSpec : viewManagerModuleSpecs) {
viewManagers.add((ViewManager) moduleSpec.getProvider().get());
}
return viewManagers;
}

public abstract ReactModuleInfoProvider getReactModuleInfoProvider();

private class ModuleHolderProvider implements Provider<NativeModule> {

private final String mName;
private final ReactApplicationContext mReactContext;

public ModuleHolderProvider(String name, ReactApplicationContext reactContext) {
mName = name;
mReactContext = reactContext;
}

@Override
public NativeModule get() {
return getModule(mName, mReactContext);
}
}
}
@DeprecatedInNewArchitecture(message = "Use BaseReactPackage instead")
public abstract class TurboReactPackage extends BaseReactPackage {}

0 comments on commit 7a31ecd

Please sign in to comment.