diff --git a/ReactAndroid/Android-prebuilt.mk b/ReactAndroid/Android-prebuilt.mk index 38fa1c01e5f..a1c4d31ab0c 100644 --- a/ReactAndroid/Android-prebuilt.mk +++ b/ReactAndroid/Android-prebuilt.mk @@ -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) diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle index 47ca5dfc72b..aaaecada49e 100644 --- a/ReactAndroid/build.gradle +++ b/ReactAndroid/build.gradle @@ -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") diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.h b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.h index 255a51a12f9..97d6cd3f180 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.h +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.h @@ -25,12 +25,12 @@ class CoreComponentsRegistry CoreComponentsRegistry(ComponentFactory *delegate); - private: - friend HybridBase; - static std::shared_ptr sharedProviderRegistry(); + private: + friend HybridBase; + const ComponentFactory *delegate_; static jni::local_ref initHybrid( diff --git a/packages/rn-tester/BUCK b/packages/rn-tester/BUCK index b62e80d495c..01653b05890 100644 --- a/packages/rn-tester/BUCK +++ b/packages/rn-tester/BUCK @@ -48,6 +48,7 @@ rn_library( [ "js", "NativeModuleExample", + "NativeComponentExample", "RCTTest", ], excludes = [ diff --git a/packages/rn-tester/android/app/build.gradle b/packages/rn-tester/android/app/build.gradle index a2de00ba8fe..6243d565237 100644 --- a/packages/rn-tester/android/app/build.gradle +++ b/packages/rn-tester/android/app/build.gradle @@ -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" } } diff --git a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.java b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.java index 643c4627618..70d834076ec 100644 --- a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.java +++ b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.java @@ -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 createNativeModules( + @NonNull ReactApplicationContext reactContext) { + return Collections.emptyList(); + } + + @NonNull + @Override + public List createViewManagers( + @NonNull ReactApplicationContext reactContext) { + return Collections.singletonList(new MyNativeViewManager()); + } }); } @@ -141,6 +160,7 @@ public class RNTesterApplication extends Application implements ReactApplication public JSIModuleProvider getJSIModuleProvider() { final ComponentFactory componentFactory = new ComponentFactory(); CoreComponentsRegistry.register(componentFactory); + RNTesterComponentsRegistry.register(componentFactory); final ReactInstanceManager reactInstanceManager = getReactInstanceManager(); ViewManagerRegistry viewManagerRegistry = diff --git a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterComponentsRegistry.java b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterComponentsRegistry.java new file mode 100644 index 00000000000..eeb4d17f75b --- /dev/null +++ b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterComponentsRegistry.java @@ -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); + } +} diff --git a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/component/MyNativeView.java b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/component/MyNativeView.java new file mode 100644 index 00000000000..0553abc6493 --- /dev/null +++ b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/component/MyNativeView.java @@ -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); + } +} diff --git a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/component/MyNativeViewManager.java b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/component/MyNativeViewManager.java new file mode 100644 index 00000000000..839d6ab4dbb --- /dev/null +++ b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/component/MyNativeViewManager.java @@ -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 + implements RNTMyNativeViewManagerInterface { + + public static final String REACT_CLASS = "RNTMyNativeView"; + + private final ViewManagerDelegate mDelegate; + + public MyNativeViewManager() { + mDelegate = new RNTMyNativeViewManagerDelegate<>(this); + } + + @Nullable + @Override + protected ViewManagerDelegate 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); + } +} diff --git a/packages/rn-tester/android/app/src/main/jni/Android.mk b/packages/rn-tester/android/app/src/main/jni/Android.mk index 61fd15a7939..b8d1baec531 100644 --- a/packages/rn-tester/android/app/src/main/jni/Android.mk +++ b/packages/rn-tester/android/app/src/main/jni/Android.mk @@ -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 diff --git a/packages/rn-tester/android/app/src/main/jni/OnLoad.cpp b/packages/rn-tester/android/app/src/main/jni/OnLoad.cpp index 2099a4ddcba..7c13f2cbc3d 100644 --- a/packages/rn-tester/android/app/src/main/jni/OnLoad.cpp +++ b/packages/rn-tester/android/app/src/main/jni/OnLoad.cpp @@ -7,6 +7,7 @@ #include +#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(); }); } diff --git a/packages/rn-tester/android/app/src/main/jni/RNTesterAppModuleProvider.cpp b/packages/rn-tester/android/app/src/main/jni/RNTesterAppModuleProvider.cpp index 93a8e029a12..4a93da8cfd2 100644 --- a/packages/rn-tester/android/app/src/main/jni/RNTesterAppModuleProvider.cpp +++ b/packages/rn-tester/android/app/src/main/jni/RNTesterAppModuleProvider.cpp @@ -7,9 +7,9 @@ #include "RNTesterAppModuleProvider.h" -#include #include #include +#include namespace facebook { namespace react { @@ -17,8 +17,7 @@ namespace react { std::shared_ptr RNTesterAppModuleProvider( const std::string moduleName, const JavaTurboModule::InitParams ¶ms) { - auto module = - PackagesRnTesterAndroidAppSpec_ModuleProvider(moduleName, params); + auto module = rntester_ModuleProvider(moduleName, params); if (module != nullptr) { return module; } diff --git a/packages/rn-tester/android/app/src/main/jni/RNTesterComponentsRegistry.cpp b/packages/rn-tester/android/app/src/main/jni/RNTesterComponentsRegistry.cpp new file mode 100644 index 00000000000..77404e8bbf0 --- /dev/null +++ b/packages/rn-tester/android/app/src/main/jni/RNTesterComponentsRegistry.cpp @@ -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 +#include +#include +#include +#include + +namespace facebook { +namespace react { + +RNTesterComponentsRegistry::RNTesterComponentsRegistry( + ComponentFactory *delegate) + : delegate_(delegate) {} + +std::shared_ptr +RNTesterComponentsRegistry::sharedProviderRegistry() { + auto providerRegistry = CoreComponentsRegistry::sharedProviderRegistry(); + + providerRegistry->add(concreteComponentDescriptorProvider< + RNTMyNativeViewComponentDescriptor>()); + + return providerRegistry; +} + +jni::local_ref +RNTesterComponentsRegistry::initHybrid( + jni::alias_ref, + 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(registry); + + mutableRegistry->setFallbackComponentDescriptor( + std::make_shared( + ComponentDescriptorParameters{ + eventDispatcher, contextContainer, nullptr})); + + return registry; + }; + + delegate->buildRegistryFunction = buildRegistryFunction; + return instance; +} + +void RNTesterComponentsRegistry::registerNatives() { + registerHybrid({ + makeNativeMethod("initHybrid", RNTesterComponentsRegistry::initHybrid), + }); +} + +} // namespace react +} // namespace facebook diff --git a/packages/rn-tester/android/app/src/main/jni/RNTesterComponentsRegistry.h b/packages/rn-tester/android/app/src/main/jni/RNTesterComponentsRegistry.h new file mode 100644 index 00000000000..3c0010eddd2 --- /dev/null +++ b/packages/rn-tester/android/app/src/main/jni/RNTesterComponentsRegistry.h @@ -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 +#include +#include +#include + +namespace facebook { +namespace react { + +class RNTesterComponentsRegistry + : public facebook::jni::HybridClass { + public: + constexpr static auto kJavaDescriptor = + "Lcom/facebook/react/uiapp/RNTesterComponentsRegistry;"; + + static void registerNatives(); + + RNTesterComponentsRegistry(ComponentFactory *delegate); + + private: + friend HybridBase; + + static std::shared_ptr + sharedProviderRegistry(); + + const ComponentFactory *delegate_; + + static jni::local_ref initHybrid( + jni::alias_ref, + ComponentFactory *delegate); +}; + +} // namespace react +} // namespace facebook diff --git a/packages/rn-tester/js/examples/NewArchitecture/NewArchitectureExample.js b/packages/rn-tester/js/examples/NewArchitecture/NewArchitectureExample.js new file mode 100644 index 00000000000..ccdd583000a --- /dev/null +++ b/packages/rn-tester/js/examples/NewArchitecture/NewArchitectureExample.js @@ -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 { + return ( + <> + + + ); + }, + }, +]; diff --git a/packages/rn-tester/js/utils/RNTesterList.android.js b/packages/rn-tester/js/utils/RNTesterList.android.js index 92cd28d26ea..726dd5c66b8 100644 --- a/packages/rn-tester/js/utils/RNTesterList.android.js +++ b/packages/rn-tester/js/utils/RNTesterList.android.js @@ -119,6 +119,11 @@ const Components: Array = [ category: 'Basic', module: require('../examples/View/ViewExample'), }, + { + key: 'NewArchitectureExample', + category: 'UI', + module: require('../examples/NewArchitecture/NewArchitectureExample'), + }, ]; const APIs: Array = [