Adding a Custom Fabric Component to RNTester (#32640)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/32640

This Diff shows how an application can provide a custom Fabric Components Registry.
The idea is to extend the CoreComponentsRegistry from rncore to provide the extra
components that are generated from RNTester.

Please note that this Diff can't be shipped as it is and should be rebased on top of:
- D32493605 (aa4da248c1) As the CLANGFORMAT is disabled for RNTester at the moment
- D32045059 (d29f3d2a6b) and D32128979 as they're effectively adding the sample component and the iOS code.

Changelog:
[Internal][Added] - Adding a Custom Fabric Component to RNTester

Reviewed By: ShikaSD

Differential Revision: D32498360

fbshipit-source-id: 1a737359498dddb571c8a445bec18e5dbcf53e04
This commit is contained in:
Nicola Corti 2021-11-22 08:13:00 -08:00 коммит произвёл Facebook GitHub Bot
Родитель 19bca222dc
Коммит 2162bce44b
16 изменённых файлов: 342 добавлений и 12 удалений

Просмотреть файл

@ -3,10 +3,10 @@
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
# This configuration provides access to most common React Native prebuilt .so files
# This configuration provides access to most common React Native prebuilt .so and .a files
# to avoid recompiling each of the libraries outside of ReactAndroid NDK compilation.
# Hosting app's/library's Android.mk can include this Android-prebuilt.mk file to
# get access to those .so to depend on.
# get access to those libraries to depend on.
# NOTES:
# * Currently, it assumes building React Native from source.
# * Not every .so is listed here (yet).
@ -19,7 +19,7 @@ THIRD_PARTY_NDK_DIR := $(REACT_ANDROID_BUILD_DIR)/third-party-ndk
REACT_ANDROID_SRC_DIR := $(REACT_ANDROID_DIR)/src/main
REACT_COMMON_DIR := $(REACT_ANDROID_DIR)/../ReactCommon
REACT_GENERATED_SRC_DIR := $(REACT_ANDROID_BUILD_DIR)/generated/source
# Note: this only have .so, not .a
# Note: this have both .so and .a files
REACT_NDK_EXPORT_DIR := $(PROJECT_BUILD_DIR)/react-ndk/exported
# fb
@ -165,6 +165,22 @@ LOCAL_EXPORT_C_INCLUDES := \
$(REACT_COMMON_DIR)/react/renderer/components/view
include $(PREBUILT_SHARED_LIBRARY)
# fabricjni
include $(CLEAR_VARS)
LOCAL_MODULE := fabricjni
LOCAL_SRC_FILES := $(REACT_NDK_EXPORT_DIR)/$(TARGET_ARCH_ABI)/libfabricjni.so
LOCAL_EXPORT_C_INCLUDES := \
$(REACT_ANDROID_SRC_DIR)/java/com/facebook/react/fabric/jni
include $(PREBUILT_SHARED_LIBRARY)
# react_render_componentregistry
include $(CLEAR_VARS)
LOCAL_MODULE := react_render_componentregistry
LOCAL_SRC_FILES := $(REACT_NDK_EXPORT_DIR)/$(TARGET_ARCH_ABI)/libreact_render_componentregistry.so
LOCAL_EXPORT_C_INCLUDES := \
$(REACT_COMMON_DIR)/react/renderer/componentregistry
include $(PREBUILT_SHARED_LIBRARY)
# jsi
include $(CLEAR_VARS)
LOCAL_MODULE := jsi
@ -183,3 +199,13 @@ include $(PREBUILT_SHARED_LIBRARY)
# fbjni
include $(FIRST_PARTY_NDK_DIR)/fbjni/Android.mk
#### Static Libraries
# runtimeexecutor
include $(CLEAR_VARS)
LOCAL_MODULE := runtimeexecutor
LOCAL_SRC_FILES := $(REACT_NDK_EXPORT_DIR)/$(TARGET_ARCH_ABI)/libruntimeexecutor.a
LOCAL_C_INCLUDES := $(REACT_COMMON_DIR)/runtimeexecutor
LOCAL_EXPORT_C_INCLUDES := $(REACT_COMMON_DIR)/runtimeexecutor
include $(PREBUILT_STATIC_LIBRARY)

Просмотреть файл

@ -238,6 +238,11 @@ tasks.register("packageReactNdkLibsForBuck") {
tasks.register("packageReactNdkDebugLibsForBuck", Copy) {
dependsOn("mergeDebugNativeLibs")
// Static libraries (.a) are copied from the obj/local folder
from("$buildDir/intermediates/ndkBuild/debug/obj/local/") {
include '**/*.a'
}
// Shared libraries (.so) are copied from the merged_native_libs folder instead
from("$buildDir/intermediates/merged_native_libs/debug/out/lib/")
exclude("**/libjsc.so")
exclude("**/libhermes.so")
@ -246,6 +251,11 @@ tasks.register("packageReactNdkDebugLibsForBuck", Copy) {
tasks.register("packageReactNdkReleaseLibsForBuck", Copy) {
dependsOn("mergeReleaseNativeLibs")
// Static libraries (.a) are copied from the obj/local folder
from("$buildDir/intermediates/ndkBuild/debug/obj/local/") {
include '**/*.a'
}
// Shared libraries (.so) are copied from the merged_native_libs folder instead
from("$buildDir/intermediates/merged_native_libs/release/out/lib/")
exclude("**/libjsc.so")
exclude("**/libhermes.so")

Просмотреть файл

@ -25,12 +25,12 @@ class CoreComponentsRegistry
CoreComponentsRegistry(ComponentFactory *delegate);
private:
friend HybridBase;
static std::shared_ptr<ComponentDescriptorProviderRegistry const>
sharedProviderRegistry();
private:
friend HybridBase;
const ComponentFactory *delegate_;
static jni::local_ref<jhybriddata> initHybrid(

Просмотреть файл

@ -48,6 +48,7 @@ rn_library(
[
"js",
"NativeModuleExample",
"NativeComponentExample",
"RCTTest",
],
excludes = [

Просмотреть файл

@ -88,6 +88,7 @@ react {
// Codegen Configs
jsRootDir = file("$rootDir/packages/rn-tester")
libraryName = "rntester"
useJavaGenerator = System.getenv("USE_CODEGEN_JAVAPOET")?.toBoolean() ?: false
}
@ -275,7 +276,7 @@ if (enableCodegen) {
"REACT_ANDROID_DIR=$reactAndroidProjectDir",
"REACT_ANDROID_BUILD_DIR=$reactAndroidBuildDir"
cFlags "-Wall", "-Werror", "-fexceptions", "-frtti", "-DWITH_INSPECTOR=1"
cppFlags "-std=c++1y"
cppFlags "-std=c++17"
targets "rntester_appmodules"
}
}

Просмотреть файл

@ -9,6 +9,7 @@ package com.facebook.react.uiapp;
import android.app.Application;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.facebook.fbreact.specs.SampleTurboModule;
import com.facebook.react.ReactApplication;
@ -33,12 +34,15 @@ import com.facebook.react.fabric.FabricJSIModuleProvider;
import com.facebook.react.module.model.ReactModuleInfo;
import com.facebook.react.module.model.ReactModuleInfoProvider;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.react.uiapp.component.MyNativeViewManager;
import com.facebook.react.uimanager.ViewManager;
import com.facebook.react.uimanager.ViewManagerRegistry;
import com.facebook.react.views.text.ReactFontManager;
import com.facebook.soloader.SoLoader;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -104,6 +108,21 @@ public class RNTesterApplication extends Application implements ReactApplication
}
};
}
},
new ReactPackage() {
@NonNull
@Override
public List<NativeModule> createNativeModules(
@NonNull ReactApplicationContext reactContext) {
return Collections.emptyList();
}
@NonNull
@Override
public List<ViewManager> createViewManagers(
@NonNull ReactApplicationContext reactContext) {
return Collections.singletonList(new MyNativeViewManager());
}
});
}
@ -141,6 +160,7 @@ public class RNTesterApplication extends Application implements ReactApplication
public JSIModuleProvider<UIManager> getJSIModuleProvider() {
final ComponentFactory componentFactory = new ComponentFactory();
CoreComponentsRegistry.register(componentFactory);
RNTesterComponentsRegistry.register(componentFactory);
final ReactInstanceManager reactInstanceManager = getReactInstanceManager();
ViewManagerRegistry viewManagerRegistry =

Просмотреть файл

@ -0,0 +1,35 @@
/*
* Copyright (c) Facebook, Inc. and its 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.uiapp;
import com.facebook.jni.HybridData;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.fabric.ComponentFactory;
import com.facebook.soloader.SoLoader;
@DoNotStrip
public class RNTesterComponentsRegistry {
static {
SoLoader.loadLibrary("fabricjni");
}
@DoNotStrip private final HybridData mHybridData;
@DoNotStrip
private native HybridData initHybrid(ComponentFactory componentFactory);
@DoNotStrip
private RNTesterComponentsRegistry(ComponentFactory componentFactory) {
mHybridData = initHybrid(componentFactory);
}
@DoNotStrip
public static RNTesterComponentsRegistry register(ComponentFactory componentFactory) {
return new RNTesterComponentsRegistry(componentFactory);
}
}

Просмотреть файл

@ -0,0 +1,18 @@
/*
* Copyright (c) Facebook, Inc. and its 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.uiapp.component;
import android.content.Context;
import android.view.View;
class MyNativeView extends View {
public MyNativeView(Context context) {
super(context);
}
}

Просмотреть файл

@ -0,0 +1,70 @@
/*
* Copyright (c) Facebook, Inc. and its 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.uiapp.component;
import android.graphics.Color;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.ViewManagerDelegate;
import com.facebook.react.uimanager.ViewProps;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.viewmanagers.RNTMyNativeViewManagerDelegate;
import com.facebook.react.viewmanagers.RNTMyNativeViewManagerInterface;
/** View manager for {@link MyNativeView} components. */
@ReactModule(name = MyNativeViewManager.REACT_CLASS)
public class MyNativeViewManager extends SimpleViewManager<MyNativeView>
implements RNTMyNativeViewManagerInterface<MyNativeView> {
public static final String REACT_CLASS = "RNTMyNativeView";
private final ViewManagerDelegate<MyNativeView> mDelegate;
public MyNativeViewManager() {
mDelegate = new RNTMyNativeViewManagerDelegate<>(this);
}
@Nullable
@Override
protected ViewManagerDelegate<MyNativeView> getDelegate() {
return mDelegate;
}
@NonNull
@Override
public String getName() {
return REACT_CLASS;
}
@NonNull
@Override
protected MyNativeView createViewInstance(@NonNull ThemedReactContext reactContext) {
return new MyNativeView(reactContext);
}
@Override
public void receiveCommand(
@NonNull MyNativeView view, String commandName, @Nullable ReadableArray args) {
mDelegate.receiveCommand(view, commandName, args);
}
@Override
public void callNativeMethodToChangeBackgroundColor(MyNativeView view, String color) {
view.setBackgroundColor(Color.parseColor(color));
}
@Override
@ReactProp(name = ViewProps.OPACITY, defaultFloat = 1.f)
public void setOpacity(@NonNull MyNativeView view, float opacity) {
super.setOpacity(view, opacity);
}
}

Просмотреть файл

@ -9,6 +9,7 @@ include $(REACT_ANDROID_DIR)/Android-prebuilt.mk
# SampleNativeModule
include $(REACT_COMMON_DIR)/react/nativemodule/samples/platform/android/Android.mk
include $(GENERATED_SRC_DIR)/codegen/jni/Android.mk
LOCAL_PATH := $(THIS_DIR)
@ -18,8 +19,9 @@ LOCAL_MODULE := rntester_appmodules
LOCAL_C_INCLUDES := $(LOCAL_PATH) $(GENERATED_SRC_DIR)/codegen/jni
LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp) $(wildcard $(GENERATED_SRC_DIR)/codegen/jni/*.cpp)
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) $(GENERATED_SRC_DIR)/codegen/jni
LOCAL_SHARED_LIBRARIES := libfbjni libglog libfolly_json libyoga libreact_nativemodule_core libturbomodulejsijni librrc_view libreact_render_core libreact_render_graphics libreact_codegen_rncore
LOCAL_STATIC_LIBRARIES := libsampleturbomodule
LOCAL_SHARED_LIBRARIES := libfbjni libglog libfolly_json libfolly_futures libyoga libreact_nativemodule_core libturbomodulejsijni librrc_view libreact_render_core libreact_render_graphics libreact_codegen_rncore libfabricjni libreact_render_componentregistry libreact_debug libreact_render_debug libreact_codegen_rntester
LOCAL_STATIC_LIBRARIES := libsampleturbomodule libruntimeexecutor
LOCAL_CFLAGS := \
-DLOG_TAG=\"ReactNative\"
LOCAL_CFLAGS += -fexceptions -frtti -std=c++17 -Wall

Просмотреть файл

@ -7,6 +7,7 @@
#include <fbjni/fbjni.h>
#include "RNTesterComponentsRegistry.h"
#include "RNTesterTurboModuleManagerDelegate.h"
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
@ -14,5 +15,6 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
// TODO: dvacca ramanpreet unify this with the way
// "ComponentDescriptorFactory" is defined in Fabric
facebook::react::RNTesterTurboModuleManagerDelegate::registerNatives();
facebook::react::RNTesterComponentsRegistry::registerNatives();
});
}

Просмотреть файл

@ -7,9 +7,9 @@
#include "RNTesterAppModuleProvider.h"
#include <PackagesRnTesterAndroidAppSpec.h>
#include <ReactCommon/SampleTurboModuleSpec.h>
#include <rncore.h>
#include <rntester.h>
namespace facebook {
namespace react {
@ -17,8 +17,7 @@ namespace react {
std::shared_ptr<TurboModule> RNTesterAppModuleProvider(
const std::string moduleName,
const JavaTurboModule::InitParams &params) {
auto module =
PackagesRnTesterAndroidAppSpec_ModuleProvider(moduleName, params);
auto module = rntester_ModuleProvider(moduleName, params);
if (module != nullptr) {
return module;
}

Просмотреть файл

@ -0,0 +1,69 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "RNTesterComponentsRegistry.h"
#include <CoreComponentsRegistry.h>
#include <fbjni/fbjni.h>
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
#include <react/renderer/components/rncore/ComponentDescriptors.h>
#include <react/renderer/components/rntester/ComponentDescriptors.h>
namespace facebook {
namespace react {
RNTesterComponentsRegistry::RNTesterComponentsRegistry(
ComponentFactory *delegate)
: delegate_(delegate) {}
std::shared_ptr<ComponentDescriptorProviderRegistry const>
RNTesterComponentsRegistry::sharedProviderRegistry() {
auto providerRegistry = CoreComponentsRegistry::sharedProviderRegistry();
providerRegistry->add(concreteComponentDescriptorProvider<
RNTMyNativeViewComponentDescriptor>());
return providerRegistry;
}
jni::local_ref<RNTesterComponentsRegistry::jhybriddata>
RNTesterComponentsRegistry::initHybrid(
jni::alias_ref<jclass>,
ComponentFactory *delegate) {
auto instance = makeCxxInstance(delegate);
auto buildRegistryFunction =
[](EventDispatcher::Weak const &eventDispatcher,
ContextContainer::Shared const &contextContainer)
-> ComponentDescriptorRegistry::Shared {
auto registry = RNTesterComponentsRegistry::sharedProviderRegistry()
->createComponentDescriptorRegistry(
{eventDispatcher, contextContainer});
auto mutableRegistry =
std::const_pointer_cast<ComponentDescriptorRegistry>(registry);
mutableRegistry->setFallbackComponentDescriptor(
std::make_shared<UnimplementedNativeViewComponentDescriptor>(
ComponentDescriptorParameters{
eventDispatcher, contextContainer, nullptr}));
return registry;
};
delegate->buildRegistryFunction = buildRegistryFunction;
return instance;
}
void RNTesterComponentsRegistry::registerNatives() {
registerHybrid({
makeNativeMethod("initHybrid", RNTesterComponentsRegistry::initHybrid),
});
}
} // namespace react
} // namespace facebook

Просмотреть файл

@ -0,0 +1,42 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <ComponentFactory.h>
#include <fbjni/fbjni.h>
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
#include <react/renderer/componentregistry/ComponentDescriptorRegistry.h>
namespace facebook {
namespace react {
class RNTesterComponentsRegistry
: public facebook::jni::HybridClass<RNTesterComponentsRegistry> {
public:
constexpr static auto kJavaDescriptor =
"Lcom/facebook/react/uiapp/RNTesterComponentsRegistry;";
static void registerNatives();
RNTesterComponentsRegistry(ComponentFactory *delegate);
private:
friend HybridBase;
static std::shared_ptr<ComponentDescriptorProviderRegistry const>
sharedProviderRegistry();
const ComponentFactory *delegate_;
static jni::local_ref<jhybriddata> initHybrid(
jni::alias_ref<jclass>,
ComponentFactory *delegate);
};
} // namespace react
} // namespace facebook

Просмотреть файл

@ -0,0 +1,30 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow
*/
'use strict';
import * as React from 'react';
import MyNativeView from '../../../NativeComponentExample/js/MyNativeView';
exports.title = 'New Architecture Examples';
exports.description = 'Test a component in the New Architecture';
exports.examples = [
{
title: 'New Architecture Renderer',
description: 'Click to change background and opacity',
render(): React.Element<any> {
return (
<>
<MyNativeView />
</>
);
},
},
];

Просмотреть файл

@ -119,6 +119,11 @@ const Components: Array<RNTesterModuleInfo> = [
category: 'Basic',
module: require('../examples/View/ViewExample'),
},
{
key: 'NewArchitectureExample',
category: 'UI',
module: require('../examples/NewArchitecture/NewArchitectureExample'),
},
];
const APIs: Array<RNTesterModuleInfo> = [