From 96d84dbbe59bf7142bd695a295c28f89d4a644a1 Mon Sep 17 00:00:00 2001 From: Christoph Purrer Date: Mon, 7 Nov 2022 08:53:13 -0800 Subject: [PATCH] react-native code-gen > Add a C++ only TurboModule example (for Android/iOS/macOS/Windows) (#35138) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/35138 Changelog: [General][Added] - Add a C++ only TurboModule example (for Android/iOS/macOS/Windows) react-native@0.69 introduced a new bridging layer to ease integration for pure C++ TurboModules using C++ std:: types directly instead of the lower level jsi:: types: https://github.com/facebook/react-native/tree/v0.69.0/ReactCommon/react/bridging This bridging layer can be used in JSI functions or more conveniently in C++ TurboModules. Here is a example of an C++ only TurboModule which will work on Android and iOS and macOS/Windows (using microsoft/react-native-macos|windows) only using flow/TypeScript and standard C++ types. C++ only TurboModules are very handy as they do not require to work with JSI APIs - instead std:: or custom C++ can by used. Differential Revision: D39011736 fbshipit-source-id: ae51d375c2056b977c27a9141a681101df68e211 --- packages/rn-tester/BUCK | 40 ++++ .../NativeCxxModuleExample.cpp | 110 +++++++++ .../NativeCxxModuleExample.h | 66 ++++++ .../NativeCxxModuleExample.js | 61 +++++ .../NativeCxxModuleExample.podspec | 38 +++ .../NativeCxxModuleExample_ConstantsStruct.h | 37 +++ .../NativeCxxModuleExample_ObjectStruct.h | 52 ++++ .../NativeCxxModuleExample_ValueStruct.h | 50 ++++ packages/rn-tester/Podfile | 1 + packages/rn-tester/Podfile.lock | 122 +++++----- .../RNTester/RNTesterTurboModuleProvider.mm | 9 +- .../NativeCxxModuleExampleExample.js | 222 ++++++++++++++++++ .../TurboModule/TurboCxxModuleExample.js | 27 +++ .../js/utils/RNTesterList.android.js | 5 + .../rn-tester/js/utils/RNTesterList.ios.js | 4 + 15 files changed, 789 insertions(+), 55 deletions(-) create mode 100644 packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.cpp create mode 100644 packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.h create mode 100644 packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.js create mode 100644 packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.podspec create mode 100644 packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample_ConstantsStruct.h create mode 100644 packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample_ObjectStruct.h create mode 100644 packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample_ValueStruct.h create mode 100644 packages/rn-tester/js/examples/TurboModule/NativeCxxModuleExampleExample.js create mode 100644 packages/rn-tester/js/examples/TurboModule/TurboCxxModuleExample.js diff --git a/packages/rn-tester/BUCK b/packages/rn-tester/BUCK index 610c5247756e3e..31c036170b9848 100644 --- a/packages/rn-tester/BUCK +++ b/packages/rn-tester/BUCK @@ -1,3 +1,4 @@ +load("@fbsource//tools/build_defs:glob_defs.bzl", "subdir_glob") load("@fbsource//xplat/hermes/defs:hermes.bzl", "HERMES_BYTECODE_VERSION") load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native") load("//tools/build_defs:fb_xplat_platform_specific_rule.bzl", "fb_xplat_platform_specific_rule") @@ -10,6 +11,7 @@ load("//tools/build_defs/apple:flag_defs.bzl", "get_objc_arc_preprocessor_flags" load("//tools/build_defs/oss:metro_defs.bzl", "rn_library") load( "//tools/build_defs/oss:rn_defs.bzl", + "ANDROID", "APPLE", "YOGA_APPLE_TARGET", "js_library_glob", @@ -49,6 +51,7 @@ rn_library( srcs = js_library_glob( [ "js", + "NativeCxxModuleExample", "NativeModuleExample", "NativeComponentExample", "RCTTest", @@ -319,3 +322,40 @@ rn_xplat_cxx_library2( "//xplat/js/react-native-github:RCTFabricComponentViewsBase", ], ) + +rn_xplat_cxx_library2( + name = "NativeCxxModuleExample", + srcs = glob(["NativeCxxModuleExample/*.cpp"]), + header_namespace = "", + exported_headers = subdir_glob( + [ + ("NativeCxxModuleExample", "*.h"), + ], + prefix = "NativeCxxModuleExample", + ), + fbandroid_compiler_flags = [ + "-fexceptions", + "-frtti", + ], + platforms = (ANDROID, APPLE), + visibility = ["PUBLIC"], + deps = [ + ":NativeCxxModuleExampleSpecJSI", + ], +) + +rn_library( + name = "NativeCxxModuleExampleSpec", + srcs = glob(["NativeCxxModuleExample/*.js"]), + codegen_modules = True, + labels = [ + "pfh:ReactNative_CommonInfrastructurePlaceholder", + ], + native_module_android_package_name = "com.facebook.fbreact.specs", + native_module_spec_name = "NativeCxxModuleExampleSpec", + visibility = ["PUBLIC"], + deps = [ + "//xplat/js/RKJSModules/vendor/react:react", + "//xplat/js/react-native-github:react-native", + ], +) diff --git a/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.cpp b/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.cpp new file mode 100644 index 00000000000000..78c9c1e3a27c17 --- /dev/null +++ b/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.cpp @@ -0,0 +1,110 @@ +/* + * 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. + */ + +#include "NativeCxxModuleExample.h" + +namespace facebook::react { + +NativeCxxModuleExample::NativeCxxModuleExample( + std::shared_ptr jsInvoker) + : NativeCxxModuleExampleCxxSpec(std::move(jsInvoker)) {} + +void NativeCxxModuleExample::getValueWithCallback( + jsi::Runtime &rt, + AsyncCallback callback) { + callback({"value from callback!"}); +} + +std::vector> NativeCxxModuleExample::getArray( + jsi::Runtime &rt, + std::vector> arg) { + return arg; +} + +bool NativeCxxModuleExample::getBool(jsi::Runtime &rt, bool arg) { + return arg; +} + +ConstantsStruct NativeCxxModuleExample::getConstants(jsi::Runtime &rt) { + return ConstantsStruct{true, 69, "react-native"}; +} + +int32_t NativeCxxModuleExample::getEnum(jsi::Runtime &rt, int32_t arg) { + return arg; +} + +std::map> NativeCxxModuleExample::getMap( + jsi::Runtime &rt, + std::map> arg) { + return arg; +} + +double NativeCxxModuleExample::getNumber(jsi::Runtime &rt, double arg) { + return arg; +} + +ObjectStruct NativeCxxModuleExample::getObject( + jsi::Runtime &rt, + ObjectStruct arg) { + return arg; +} + +std::set NativeCxxModuleExample::getSet( + jsi::Runtime &rt, + std::set arg) { + return arg; +} + +std::string NativeCxxModuleExample::getString( + jsi::Runtime &rt, + std::string arg) { + return arg; +} + +std::string NativeCxxModuleExample::getUnion( + jsi::Runtime &rt, + float x, + std::string y, + jsi::Object z) { + std::string result = "x: " + std::to_string(x) + ", y: " + y + ", z: { "; + if (z.hasProperty(rt, "value")) { + result += "value: "; + result += std::to_string(z.getProperty(rt, "value").getNumber()); + } else if (z.hasProperty(rt, "low")) { + result += "low: "; + result += z.getProperty(rt, "low").getString(rt).utf8(rt); + } + result += " }"; + return result; +} + +ValueStruct NativeCxxModuleExample::getValue( + jsi::Runtime &rt, + double x, + std::string y, + ObjectStruct z) { + ValueStruct result{x, y, z}; + return result; +} + +AsyncPromise NativeCxxModuleExample::getValueWithPromise( + jsi::Runtime &rt, + bool error) { + auto promise = AsyncPromise(rt, jsInvoker_); + if (error) { + promise.reject("intentional promise rejection"); + } else { + promise.resolve("result!"); + } + return promise; +} + +void NativeCxxModuleExample::voidFunc(jsi::Runtime &rt) { + // Nothing to do +} + +} // namespace facebook::react diff --git a/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.h b/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.h new file mode 100644 index 00000000000000..62f99ae2b73b58 --- /dev/null +++ b/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.h @@ -0,0 +1,66 @@ +/* + * 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. + */ + +#pragma once + +#if __has_include() +#include +#else +#include +#endif +#include +#include +#include +#include +#include "NativeCxxModuleExample_ConstantsStruct.h" +#include "NativeCxxModuleExample_ObjectStruct.h" +#include "NativeCxxModuleExample_ValueStruct.h" + +namespace facebook::react { + +class NativeCxxModuleExample + : public NativeCxxModuleExampleCxxSpec { + public: + NativeCxxModuleExample(std::shared_ptr jsInvoker); + + void getValueWithCallback( + jsi::Runtime &rt, + AsyncCallback callback); + + std::vector> getArray( + jsi::Runtime &rt, + std::vector> arg); + + bool getBool(jsi::Runtime &rt, bool arg); + + ConstantsStruct getConstants(jsi::Runtime &rt); + + int32_t getEnum(jsi::Runtime &rt, int32_t arg); + + std::map> getMap( + jsi::Runtime &rt, + std::map> arg); + + double getNumber(jsi::Runtime &rt, double arg); + + ObjectStruct getObject(jsi::Runtime &rt, ObjectStruct arg); + + std::set getSet(jsi::Runtime &rt, std::set arg); + + std::string getString(jsi::Runtime &rt, std::string arg); + + std::string getUnion(jsi::Runtime &rt, float x, std::string y, jsi::Object z); + + ValueStruct + getValue(jsi::Runtime &rt, double x, std::string y, ObjectStruct z); + + AsyncPromise getValueWithPromise(jsi::Runtime &rt, bool error); + + void voidFunc(jsi::Runtime &rt); +}; + +} // namespace facebook::react diff --git a/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.js b/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.js new file mode 100644 index 00000000000000..8d27ab6650d85e --- /dev/null +++ b/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.js @@ -0,0 +1,61 @@ +/** + * 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. + * + * @flow strict-local + * @format + */ + +import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport'; + +import {TurboModuleRegistry} from 'react-native'; + +/** Flow enum support will be added when the sun rises in the west +export enum EnumInt { + A = 23, + B = 42, +} +*/ + +export type UnionFloat = 1.44 | 2.88 | 5.76; +export type UnionString = 'One' | 'Two' | 'Three'; +export type UnionObject = {value: number} | {low: string}; + +export type ObjectStruct = $ReadOnly<{ + a: number, + b: string, + c?: ?string, +}>; + +export type ValueStruct = $ReadOnly<{ + x: number, + y: string, + z: ObjectStruct, +}>; + +export interface Spec extends TurboModule { + +getArray: (arg: Array) => Array; + +getBool: (arg: boolean) => boolean; + +getConstants: () => {| + const1: boolean, + const2: number, + const3: string, + |}; + +getEnum: (arg: number /*EnumInt*/) => number /*EnumInt*/; + +getMap: (arg: {[key: string]: ?number}) => {[key: string]: ?number}; + +getNumber: (arg: number) => number; + +getObject: (arg: ObjectStruct) => ObjectStruct; + +getSet: (arg: Array) => Array; + +getString: (arg: string) => string; + +getUnion: (x: UnionFloat, y: UnionString, z: UnionObject) => string; + +getValue: (x: number, y: string, z: ObjectStruct) => ObjectStruct; + +getValueWithCallback: (callback: (value: string) => void) => void; + +getValueWithPromise: (error: boolean) => Promise; + +voidFunc: () => void; +} + +export default (TurboModuleRegistry.get( + 'NativeCxxModuleExampleCxx', +): ?Spec); diff --git a/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.podspec b/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.podspec new file mode 100644 index 00000000000000..a8714eaa559858 --- /dev/null +++ b/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.podspec @@ -0,0 +1,38 @@ +# 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. + +require "json" + +package = JSON.parse(File.read(File.join(__dir__, "../package.json"))) + +Pod::Spec.new do |s| + s.name = "NativeCxxModuleExample" + s.version = package["version"] + s.summary = package["description"] + s.description = "NativeCxxModuleExample" + s.homepage = "https://github.com/facebook/react-native.git" + s.license = "MIT" + s.platforms = { :ios => "12.4" } + s.compiler_flags = '-Wno-nullability-completeness' + s.author = "Meta Platforms, Inc. and its affiliates" + s.source = { :git => "https://github.com/facebook/react-native.git", :tag => "#{s.version}" } + s.source_files = "**/*.{h,cpp}" + s.requires_arc = true + s.pod_target_xcconfig = { + "USE_HEADERMAP" => "YES", + "CLANG_CXX_LANGUAGE_STANDARD" => "c++17" + } + + install_modules_dependencies(s) + + s.dependency "ReactCommon/turbomodule/core" + + # Enable codegen for this library + use_react_native_codegen!(s, { + :react_native_path => "../../..", + :js_srcs_dir => "./", + :library_type => "modules", + }) +end diff --git a/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample_ConstantsStruct.h b/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample_ConstantsStruct.h new file mode 100644 index 00000000000000..4966c69d23551f --- /dev/null +++ b/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample_ConstantsStruct.h @@ -0,0 +1,37 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include + +namespace facebook::react { + +struct ConstantsStruct { + bool const1; + int32_t const2; + std::string const3; + bool operator==(const ConstantsStruct &other) const { + return const1 == other.const1 && const2 == other.const2 && + const3 == other.const3; + } +}; + +template <> +struct Bridging { + static jsi::Object toJs(jsi::Runtime &rt, const ConstantsStruct &value) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, "const1", bridging::toJs(rt, value.const1)); + result.setProperty(rt, "const2", bridging::toJs(rt, value.const2)); + result.setProperty(rt, "const3", bridging::toJs(rt, value.const3)); + return result; + } +}; + +} // namespace facebook::react diff --git a/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample_ObjectStruct.h b/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample_ObjectStruct.h new file mode 100644 index 00000000000000..e430a3cb36f5a0 --- /dev/null +++ b/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample_ObjectStruct.h @@ -0,0 +1,52 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include + +namespace facebook::react { + +struct ObjectStruct { + int32_t a; + std::string b; + std::optional c; + bool operator==(const ObjectStruct &other) const { + return a == other.a && b == other.b && c == other.c; + } +}; + +template <> +struct Bridging { + static ObjectStruct fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + ObjectStruct result{ + bridging::fromJs(rt, value.getProperty(rt, "a"), jsInvoker), + bridging::fromJs( + rt, value.getProperty(rt, "b"), jsInvoker), + bridging::fromJs>( + rt, value.getProperty(rt, "c"), jsInvoker)}; + + return result; + } + + static jsi::Object toJs(jsi::Runtime &rt, const ObjectStruct &value) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, "a", bridging::toJs(rt, value.a)); + result.setProperty(rt, "b", bridging::toJs(rt, value.b)); + if (value.c) { + result.setProperty(rt, "c", bridging::toJs(rt, value.c.value())); + } + return result; + } +}; + +} // namespace facebook::react diff --git a/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample_ValueStruct.h b/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample_ValueStruct.h new file mode 100644 index 00000000000000..7e44c92113b274 --- /dev/null +++ b/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample_ValueStruct.h @@ -0,0 +1,50 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include +#include "NativeCxxModuleExample_ObjectStruct.h" + +namespace facebook::react { + +struct ValueStruct { + double x; + std::string y; + ObjectStruct z; + bool operator==(const ValueStruct &other) const { + return x == other.x && y == other.y && z == other.z; + } +}; + +template <> +struct Bridging { + static ValueStruct fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + ValueStruct result{ + bridging::fromJs(rt, value.getProperty(rt, "x"), jsInvoker), + bridging::fromJs( + rt, value.getProperty(rt, "y"), jsInvoker), + bridging::fromJs( + rt, value.getProperty(rt, "z"), jsInvoker)}; + return result; + } + + static jsi::Object toJs(jsi::Runtime &rt, const ValueStruct &value) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, "x", bridging::toJs(rt, value.x)); + result.setProperty(rt, "y", bridging::toJs(rt, value.y)); + result.setProperty(rt, "z", bridging::toJs(rt, value.z)); + return result; + } +}; + +} // namespace facebook::react diff --git a/packages/rn-tester/Podfile b/packages/rn-tester/Podfile index 45ff904de3b762..fed1c8ad6c7163 100644 --- a/packages/rn-tester/Podfile +++ b/packages/rn-tester/Podfile @@ -48,6 +48,7 @@ def pods(target_name, options = {}, use_flipper: !IN_CI && !USE_FRAMEWORKS) # RNTester native modules and components pod 'ScreenshotManager', :path => "NativeModuleExample" + pod 'NativeCxxModuleExample', :path => "NativeCxxModuleExample" end target 'RNTester' do diff --git a/packages/rn-tester/Podfile.lock b/packages/rn-tester/Podfile.lock index 1207d1bfa8a33a..b9e82771509cc5 100644 --- a/packages/rn-tester/Podfile.lock +++ b/packages/rn-tester/Podfile.lock @@ -73,14 +73,25 @@ PODS: - FlipperKit/FlipperKitNetworkPlugin - fmt (6.2.1) - glog (0.3.5) - - hermes-engine (1000.0.0): - - hermes-engine/Hermes (= 1000.0.0) - - hermes-engine/JSI (= 1000.0.0) - - hermes-engine/Public (= 1000.0.0) - - hermes-engine/Hermes (1000.0.0) - - hermes-engine/JSI (1000.0.0) - - hermes-engine/Public (1000.0.0) - libevent (2.1.12) + - MyNativeView (0.0.1): + - RCT-Folly (= 2021.07.22.00) + - RCTRequired + - RCTTypeSafety + - React-Codegen + - React-Core + - React-RCTFabric + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - NativeCxxModuleExample (0.0.1): + - RCT-Folly (= 2021.07.22.00) + - RCTRequired + - RCTTypeSafety + - React-Codegen + - React-Core + - React-RCTFabric + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core - OpenSSL-Universal (1.1.1100) - RCT-Folly (2021.07.22.00): - boost @@ -98,12 +109,6 @@ PODS: - DoubleConversion - fmt (~> 6.2.1) - glog - - RCT-Folly/Futures (2021.07.22.00): - - boost - - DoubleConversion - - fmt (~> 6.2.1) - - glog - - libevent - RCTRequired (1000.0.0) - RCTTypeSafety (1000.0.0): - FBLazyVector (= 1000.0.0) @@ -122,21 +127,19 @@ PODS: - React-RCTSettings (= 1000.0.0) - React-RCTText (= 1000.0.0) - React-RCTVibration (= 1000.0.0) - - React-bridging (1000.0.0): - - RCT-Folly (= 2021.07.22.00) - - React-jsi (= 1000.0.0) - React-callinvoker (1000.0.0) - React-Codegen (1000.0.0): - FBReactNativeSpec (= 1000.0.0) - - hermes-engine (= 1000.0.0) - RCT-Folly (= 2021.07.22.00) - RCTRequired (= 1000.0.0) - RCTTypeSafety (= 1000.0.0) - React-Core (= 1000.0.0) - React-graphics (= 1000.0.0) + - React-jsc (= 1000.0.0) - React-jsi (= 1000.0.0) - React-jsiexecutor (= 1000.0.0) - React-rncore (= 1000.0.0) + - ReactCommon/turbomodule/bridging (= 1000.0.0) - ReactCommon/turbomodule/core (= 1000.0.0) - React-Core (1000.0.0): - glog @@ -615,19 +618,14 @@ PODS: - React-graphics (1000.0.0): - RCT-Folly/Fabric (= 2021.07.22.00) - React-Core/Default (= 1000.0.0) - - React-hermes (1000.0.0): - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - RCT-Folly/Futures (= 2021.07.22.00) - - React-cxxreact (= 1000.0.0) - - React-jsidynamic (= 1000.0.0) - - React-jsiexecutor (= 1000.0.0) - - React-jsinspector (= 1000.0.0) - - React-perflogger (= 1000.0.0) - - React-jsi (1000.0.0): - - hermes-engine + - React-jsc (1000.0.0): + - React-jsc/Default (= 1000.0.0) + - React-jsi (= 1000.0.0) + - React-jsc/Default (1000.0.0): + - React-jsi (= 1000.0.0) + - React-jsc/Fabric (1000.0.0): + - React-jsi (= 1000.0.0) + - React-jsi (1000.0.0) - React-jsidynamic (1000.0.0): - boost (= 1.76.0) - DoubleConversion @@ -660,6 +658,8 @@ PODS: - RCTRequired - RCTTypeSafety - React-Core + - React-graphics + - React-RCTFabric - ReactCommon/turbomodule/core - React-RCTBlob (1000.0.0): - RCT-Folly (= 2021.07.22.00) @@ -724,11 +724,20 @@ PODS: - React-rncore (1000.0.0) - React-runtimeexecutor (1000.0.0): - React-jsi (= 1000.0.0) + - ReactCommon/turbomodule/bridging (1000.0.0): + - DoubleConversion + - glog + - RCT-Folly (= 2021.07.22.00) + - React-callinvoker (= 1000.0.0) + - React-Core (= 1000.0.0) + - React-cxxreact (= 1000.0.0) + - React-jsi (= 1000.0.0) + - React-logger (= 1000.0.0) + - React-perflogger (= 1000.0.0) - ReactCommon/turbomodule/core (1000.0.0): - DoubleConversion - glog - RCT-Folly (= 2021.07.22.00) - - React-bridging (= 1000.0.0) - React-callinvoker (= 1000.0.0) - React-Core (= 1000.0.0) - React-cxxreact (= 1000.0.0) @@ -740,7 +749,6 @@ PODS: - DoubleConversion - glog - RCT-Folly (= 2021.07.22.00) - - React-bridging (= 1000.0.0) - React-callinvoker (= 1000.0.0) - React-Core (= 1000.0.0) - React-cxxreact (= 1000.0.0) @@ -750,7 +758,13 @@ PODS: - ReactCommon/turbomodule/core (= 1000.0.0) - ScreenshotManager (0.0.1): - RCT-Folly (= 2021.07.22.00) + - RCTRequired + - RCTTypeSafety + - React-Codegen - React-Core + - React-RCTFabric + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core - SocketRocket (0.6.0) - Yoga (1.14.0) - YogaKit (1.18.1): @@ -783,15 +797,14 @@ DEPENDENCIES: - FlipperKit/FlipperKitUserDefaultsPlugin (= 0.125.0) - FlipperKit/SKIOSNetworkPlugin (= 0.125.0) - glog (from `../../third-party-podspecs/glog.podspec`) - - hermes-engine (from `../../sdks/hermes/hermes-engine.podspec`) - - libevent (~> 2.1.12) + - MyNativeView (from `NativeComponentExample`) + - NativeCxxModuleExample (from `NativeCxxModuleExample`) - OpenSSL-Universal (= 1.1.1100) - RCT-Folly (from `../../third-party-podspecs/RCT-Folly.podspec`) - RCT-Folly/Fabric (from `../../third-party-podspecs/RCT-Folly.podspec`) - RCTRequired (from `../../Libraries/RCTRequired`) - RCTTypeSafety (from `../../Libraries/TypeSafety`) - React (from `../../`) - - React-bridging (from `../../ReactCommon`) - React-callinvoker (from `../../ReactCommon/callinvoker`) - React-Codegen (from `build/generated/ios`) - React-Core (from `../../`) @@ -801,7 +814,8 @@ DEPENDENCIES: - React-cxxreact (from `../../ReactCommon/cxxreact`) - React-Fabric (from `../../ReactCommon`) - React-graphics (from `../../ReactCommon/react/renderer/graphics`) - - React-hermes (from `../../ReactCommon/hermes`) + - React-jsc (from `../../ReactCommon/jsi`) + - React-jsc/Fabric (from `../../ReactCommon/jsi`) - React-jsi (from `../../ReactCommon/jsi`) - React-jsidynamic (from `../../ReactCommon/jsi`) - React-jsiexecutor (from `../../ReactCommon/jsiexecutor`) @@ -857,8 +871,10 @@ EXTERNAL SOURCES: :path: "../../React/FBReactNativeSpec" glog: :podspec: "../../third-party-podspecs/glog.podspec" - hermes-engine: - :podspec: "../../sdks/hermes/hermes-engine.podspec" + MyNativeView: + :path: NativeComponentExample + NativeCxxModuleExample: + :path: NativeCxxModuleExample RCT-Folly: :podspec: "../../third-party-podspecs/RCT-Folly.podspec" RCTRequired: @@ -867,8 +883,6 @@ EXTERNAL SOURCES: :path: "../../Libraries/TypeSafety" React: :path: "../../" - React-bridging: - :path: "../../ReactCommon" React-callinvoker: :path: "../../ReactCommon/callinvoker" React-Codegen: @@ -883,8 +897,8 @@ EXTERNAL SOURCES: :path: "../../ReactCommon" React-graphics: :path: "../../ReactCommon/react/renderer/graphics" - React-hermes: - :path: "../../ReactCommon/hermes" + React-jsc: + :path: "../../ReactCommon/jsi" React-jsi: :path: "../../ReactCommon/jsi" React-jsidynamic: @@ -939,7 +953,7 @@ SPEC CHECKSUMS: CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 FBLazyVector: 19e408e76fa9258dd32191a50d60c41444f52d29 - FBReactNativeSpec: 9761d52cf2d3727e2557fbf4014c514909d76b6b + FBReactNativeSpec: 17b5a6331790d1596b0c82887c546b42a24c4103 Flipper: 26fc4b7382499f1281eb8cb921e5c3ad6de91fe0 Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c Flipper-DoubleConversion: 2dc99b02f658daf147069aad9dbd29d8feb06d30 @@ -951,23 +965,23 @@ SPEC CHECKSUMS: FlipperKit: cbdee19bdd4e7f05472a66ce290f1b729ba3cb86 fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b - hermes-engine: 05b2399259b25f6c105858adc778c04342c1f424 libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 + MyNativeView: f6008cff7263168410ad24bdbcfd2a042c1ebe98 + NativeCxxModuleExample: 1fbcdaf387d47c238f7fea79b209f7baa4e8da94 OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1 RCTRequired: 1c8808cf84569265784a6c33984bbb506ada8c6e RCTTypeSafety: b6dcb5036a808864ee8cad66ca15f263c24661cc React: 8d809d414723bb5763093ddec7658066a21ccabc - React-bridging: c8806159f8ef90f27443857eed1efdb8c85940e1 React-callinvoker: 5f16202ad4e45f0607b1fae0f6955a8f7c87eef1 - React-Codegen: d2434d5e4d238bceef25f40c4f58b199eb981ad0 - React-Core: 3965263aa4b4e1ebf7b4fdb50d2f49ce7bf28f63 + React-Codegen: 888f6f02360425016a440f1220c406052dfd4acd + React-Core: 542b7d0642b33954e33ba6b57537b0a8195de1ae React-CoreModules: 675170bccf156da3a3348e04e2036ce401b2010d React-cxxreact: ebed982230716c3515ab2f435cb13aec8a56af02 React-Fabric: 141459e61c825acf02d26ece099acbd9cbd87b99 React-graphics: 2dda97baebb0082bb85499c862c3f269a194f416 - React-hermes: 4912383b4f062173cb623e570ead70ab380f7bef - React-jsi: c24dbcfdf7ea075138b73372387c7f17c0db56ef + React-jsc: 8fddea2e192e1c25f490daf03cd3268780b195a1 + React-jsi: c826471016a9b7430be3a358084f86ecee10909a React-jsidynamic: 2b14ac1b6d3a1b7daa1e5a424b98de87da981698 React-jsiexecutor: 14e899380e3fe9ca74c4e19727540a03e7574721 React-jsinspector: 7733dd522d044aef87caa39f3eda77593358a7eb @@ -975,7 +989,7 @@ SPEC CHECKSUMS: React-perflogger: c4fdd48988c2d3047186fc1bc1772d634cfca2ea React-RCTActionSheet: 166fd1df85ac10219466b45d12a5884d3eaceac1 React-RCTAnimation: d6127046c6bb44bd3e67b7503c4ad7f91131b58e - React-RCTAppDelegate: e427b692bf829e40f9b318e2a29dca2ab5f36cf6 + React-RCTAppDelegate: f2b8ac4ccfeaf85158386eff7ee0d9092e4784f0 React-RCTBlob: 68675c89ebe6edf310dddd0774ba07b685f090a9 React-RCTFabric: a98a6effece6719669b8c6b4d2c33fb0edddc613 React-RCTImage: 6de9f0f4402af859849e97cc73a56a52f400f4c9 @@ -986,14 +1000,14 @@ SPEC CHECKSUMS: React-RCTTest: be92171ef0a1818f96324eac3be0356f4fa08844 React-RCTText: a861fbf2835299d3cc4189697cddd8bd8602afb9 React-RCTVibration: 0386f50996a153b3f39cecbe7d139763ac9a9fdf - React-rncore: 665c70690f404bbfa3948148de72689672a906d2 + React-rncore: 98050fbb79add6089e13af51ce597e5f1161c3f6 React-runtimeexecutor: 97dca9247f4d3cfe0733384b189c6930fbd402b7 - ReactCommon: b1f213aa09e3dfd0a89389b5023fdb1cd6528e96 - ScreenshotManager: cf552c19152e3357f08875fc2f85adb2dee6a66b + ReactCommon: 8bb1d2a9c03870de143668ee3a1cd0a758f99d18 + ScreenshotManager: 49b430fbb6b5db5bed6087a9d070511ce3b0488e SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608 Yoga: 1b1a12ff3d86a10565ea7cbe057d42f5e5fb2a07 YogaKit: f782866e155069a2cca2517aafea43200b01fd5a -PODFILE CHECKSUM: 20298ecd3f30aa788ad491637e593ed0d8c100ca +PODFILE CHECKSUM: bf9967be685aa1934d483bfd03f43079d8108641 COCOAPODS: 1.11.3 diff --git a/packages/rn-tester/RNTester/RNTesterTurboModuleProvider.mm b/packages/rn-tester/RNTester/RNTesterTurboModuleProvider.mm index b8532eab9db215..32e5c3418013a9 100644 --- a/packages/rn-tester/RNTester/RNTesterTurboModuleProvider.mm +++ b/packages/rn-tester/RNTester/RNTesterTurboModuleProvider.mm @@ -7,6 +7,9 @@ #import "RNTesterTurboModuleProvider.h" +#ifdef RCT_NEW_ARCH_ENABLED +#import +#endif #import #import #import @@ -28,7 +31,11 @@ Class RNTesterTurboModuleClassProvider(const char *name) if (name == "SampleTurboCxxModule") { return std::make_shared(jsInvoker); } - +#ifdef RCT_NEW_ARCH_ENABLED + if (name == "NativeCxxModuleExampleCxx") { + return std::make_shared(jsInvoker); + } +#endif return nullptr; } diff --git a/packages/rn-tester/js/examples/TurboModule/NativeCxxModuleExampleExample.js b/packages/rn-tester/js/examples/TurboModule/NativeCxxModuleExampleExample.js new file mode 100644 index 00000000000000..ba62ba6e64ef4e --- /dev/null +++ b/packages/rn-tester/js/examples/TurboModule/NativeCxxModuleExampleExample.js @@ -0,0 +1,222 @@ +/** + * 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. + * + * @format + * @flow strict-local + */ + +import type {RootTag} from 'react-native/Libraries/ReactNative/RootTag'; + +import { + StyleSheet, + Text, + View, + FlatList, + Platform, + TouchableOpacity, + RootTagContext, +} from 'react-native'; +import * as React from 'react'; +import NativeCxxModuleExample /*EnumInt,*/ from '../../../NativeCxxModuleExample/NativeCxxModuleExample'; + +type State = {| + testResults: { + [string]: { + type: string, + value: mixed, + ... + }, + ... + }, +|}; + +type Examples = + | 'callback' + | 'getArray' + | 'getBool' + | 'getConstants' + | 'getEnum' + | 'getMap' + | 'getNumber' + | 'getObject' + | 'getSet' + | 'getString' + | 'getUnion' + | 'getValue' + | 'promise' + | 'rejectPromise' + | 'voidFunc'; + +class NativeCxxModuleExampleExample extends React.Component<{||}, State> { + static contextType: React$Context = RootTagContext; + + state: State = { + testResults: {}, + }; + + // Add calls to methods in TurboModule here + // $FlowFixMe[missing-local-annot] + _tests = { + callback: () => + NativeCxxModuleExample?.getValueWithCallback(callbackValue => + this._setResult('callback', callbackValue), + ), + getArray: () => + NativeCxxModuleExample?.getArray([ + {a: 1, b: 'foo'}, + {a: 2, b: 'bar'}, + null, + ]), + getBool: () => NativeCxxModuleExample?.getBool(true), + getConstants: () => NativeCxxModuleExample?.getConstants(), + getEnum: () => NativeCxxModuleExample?.getEnum(/*EnumInt.A*/ 2), + getMap: () => NativeCxxModuleExample?.getMap({a: 1, b: null, c: 3}), + getNumber: () => NativeCxxModuleExample?.getNumber(99.95), + getObject: () => + NativeCxxModuleExample?.getObject({a: 1, b: 'foo', c: null}), + getSet: () => NativeCxxModuleExample?.getSet([1, 1.1, 1.1, 1.1, 2]), + getString: () => NativeCxxModuleExample?.getString('Hello'), + getUnion: () => NativeCxxModuleExample?.getUnion(1.44, 'Two', {low: '12'}), + getValue: () => + NativeCxxModuleExample?.getValue(5, 'test', {a: 1, b: 'foo'}), + promise: () => + NativeCxxModuleExample?.getValueWithPromise(false).then(valuePromise => + this._setResult('promise', valuePromise), + ), + rejectPromise: () => + NativeCxxModuleExample?.getValueWithPromise(true) + .then(() => {}) + .catch(e => this._setResult('rejectPromise', e.message)), + voidFunc: () => NativeCxxModuleExample?.voidFunc(), + }; + + _setResult( + name: string | Examples, + result: + | $FlowFixMe + | void + | Array<$FlowFixMe> + | boolean + | {const1: boolean, const2: number, const3: string} + | number + | {[key: string]: ?number} + | Promise + | number + | string, + ) { + this.setState(({testResults}) => ({ + testResults: { + ...testResults, + /* $FlowFixMe[invalid-computed-prop] (>=0.111.0 site=react_native_fb) + * This comment suppresses an error found when Flow v0.111 was + * deployed. To see the error, delete this comment and run Flow. */ + [name]: {value: result, type: typeof result}, + }, + })); + } + + _renderResult(name: Examples): React.Node { + const result = this.state.testResults[name] || {}; + return ( + + {JSON.stringify(result.value)} + {result.type} + + ); + } + + componentDidMount(): void { + if (global.__turboModuleProxy == null) { + throw new Error( + 'Cannot load this example because TurboModule is not configured.', + ); + } + Object.keys(this._tests).forEach(item => + this._setResult(item, this._tests[item]()), + ); + } + + render(): React.Node { + return ( + + + + Object.keys(this._tests).forEach(item => + this._setResult(item, this._tests[item]()), + ) + }> + Run all tests + + this.setState({testResults: {}})} + style={[styles.column, styles.button]}> + Clear results + + + item} + renderItem={({item}) => ( + + this._setResult(item, this._tests[item]())}> + {item} + + {this._renderResult(item)} + + )} + /> + + ); + } +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + }, + item: { + flexDirection: 'row', + margin: 6, + }, + column: { + flex: 2, + justifyContent: 'center', + padding: 3, + }, + result: { + alignItems: 'stretch', + justifyContent: 'space-between', + }, + value: { + fontFamily: Platform.OS === 'ios' ? 'Menlo' : 'monospace', + fontSize: 12, + }, + type: { + color: '#333', + fontSize: 10, + }, + button: { + borderColor: '#444', + padding: 3, + flex: 1, + }, + buttonTextLarge: { + textAlign: 'center', + color: 'rgb(0,122,255)', + fontSize: 16, + padding: 6, + }, + buttonText: { + color: 'rgb(0,122,255)', + textAlign: 'center', + }, +}); + +module.exports = NativeCxxModuleExampleExample; diff --git a/packages/rn-tester/js/examples/TurboModule/TurboCxxModuleExample.js b/packages/rn-tester/js/examples/TurboModule/TurboCxxModuleExample.js new file mode 100644 index 00000000000000..18e9f53ae249d9 --- /dev/null +++ b/packages/rn-tester/js/examples/TurboModule/TurboCxxModuleExample.js @@ -0,0 +1,27 @@ +/** + * 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. + * + * @format + * @flow + */ + +'use strict'; + +const React = require('react'); +const NativeCxxModuleExampleExample = require('./NativeCxxModuleExampleExample'); + +exports.displayName = (undefined: ?string); +exports.title = 'Cxx TurboModule'; +exports.category = 'Basic'; +exports.description = 'Usage of Cxx TurboModule'; +exports.examples = [ + { + title: 'TurboCxxModuleExample', + render: function (): React.Element { + return ; + }, + }, +]; diff --git a/packages/rn-tester/js/utils/RNTesterList.android.js b/packages/rn-tester/js/utils/RNTesterList.android.js index f92ff40c207528..401d0743cac880 100644 --- a/packages/rn-tester/js/utils/RNTesterList.android.js +++ b/packages/rn-tester/js/utils/RNTesterList.android.js @@ -283,6 +283,11 @@ const APIs: Array = [ category: 'Basic', module: require('../examples/TurboModule/TurboModuleExample'), }, + { + key: 'TurboCxxModuleExample', + category: 'Basic', + module: require('../examples/TurboModule/TurboCxxModuleExample'), + }, ]; if (ReactNativeFeatureFlags.shouldEmitW3CPointerEvents()) { diff --git a/packages/rn-tester/js/utils/RNTesterList.ios.js b/packages/rn-tester/js/utils/RNTesterList.ios.js index af266e7ea0efdb..d0536191ec8a8d 100644 --- a/packages/rn-tester/js/utils/RNTesterList.ios.js +++ b/packages/rn-tester/js/utils/RNTesterList.ios.js @@ -258,6 +258,10 @@ const APIs: Array = [ key: 'TurboModuleExample', module: require('../examples/TurboModule/TurboModuleExample'), }, + { + key: 'TurboCxxModuleExample', + module: require('../examples/TurboModule/TurboCxxModuleExample'), + }, { key: 'VibrationExample', module: require('../examples/Vibration/VibrationExample'),