react-native-nitro-modules 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NitroModules.podspec +4 -0
- package/README.md +2 -2
- package/android/CMakeLists.txt +3 -0
- package/android/build.gradle +27 -3
- package/android/src/main/cpp/JNIOnLoad.cpp +5 -5
- package/android/src/main/cpp/platform/NitroLogger.cpp +1 -1
- package/android/src/main/cpp/turbomodule/JNitroModules.cpp +41 -0
- package/android/src/main/cpp/turbomodule/JNitroModules.hpp +37 -0
- package/android/src/main/java/com/margelo/nitro/NitroModules.kt +69 -0
- package/android/src/main/java/com/margelo/nitro/NitroModulesPackage.kt +34 -0
- package/android/src/main/java/com/margelo/nitro/core/HybridObject.kt +6 -2
- package/android/src/newarch/NitroModulesSpec.kt +6 -0
- package/android/src/oldarch/NitroModulesSpec.kt +9 -0
- package/cpp/core/HybridFunction.hpp +13 -4
- package/cpp/entrypoint/HybridNitroModulesProxy.cpp +55 -0
- package/cpp/entrypoint/HybridNitroModulesProxy.hpp +48 -0
- package/cpp/entrypoint/InstallNitro.cpp +28 -0
- package/cpp/entrypoint/InstallNitro.hpp +41 -0
- package/cpp/jsi/JSIConverter+ArrayBuffer.hpp +6 -6
- package/cpp/jsi/JSIConverter+HostObject.hpp +73 -0
- package/cpp/jsi/JSIConverter+HybridObject.hpp +1 -1
- package/cpp/jsi/JSIConverter+Promise.hpp +1 -0
- package/cpp/jsi/JSIConverter+Tuple.hpp +2 -2
- package/cpp/jsi/JSIConverter.hpp +1 -0
- package/cpp/prototype/HybridObjectPrototype.cpp +4 -3
- package/cpp/threading/CallInvokerDispatcher.hpp +5 -0
- package/cpp/utils/NitroDefines.hpp +8 -0
- package/cpp/utils/TypeInfo.hpp +40 -20
- package/ios/core/ArrayBufferHolder.hpp +1 -1
- package/ios/core/HybridObjectSpec.swift +1 -1
- package/ios/platform/NitroLogger.mm +1 -2
- package/ios/turbomodule/NativeNitroModules+NewArch.mm +67 -0
- package/ios/turbomodule/NativeNitroModules+OldArch.mm +71 -0
- package/ios/turbomodule/NativeNitroModules.h +22 -0
- package/lib/BoxedHybridObject.d.ts +12 -0
- package/lib/BoxedHybridObject.js +1 -0
- package/lib/ModuleNotFoundError.js +3 -13
- package/lib/NitroModules.d.ts +1 -83
- package/lib/NitroModules.js +2 -94
- package/lib/NitroModulesProxy.d.ts +58 -0
- package/lib/NitroModulesProxy.js +1 -0
- package/lib/commonjs/BoxedHybridObject.js +6 -0
- package/lib/commonjs/BoxedHybridObject.js.map +1 -0
- package/lib/commonjs/ModuleNotFoundError.js +3 -15
- package/lib/commonjs/ModuleNotFoundError.js.map +1 -1
- package/lib/commonjs/NitroModules.js +11 -100
- package/lib/commonjs/NitroModules.js.map +1 -1
- package/lib/commonjs/NitroModulesProxy.js +6 -0
- package/lib/commonjs/NitroModulesProxy.js.map +1 -0
- package/lib/commonjs/turbomodule/NativeNitroModules.js +36 -0
- package/lib/commonjs/turbomodule/NativeNitroModules.js.map +1 -0
- package/lib/commonjs/turbomodule/NativeNitroModules.web.js +17 -0
- package/lib/commonjs/turbomodule/NativeNitroModules.web.js.map +1 -0
- package/lib/module/BoxedHybridObject.js +4 -0
- package/lib/module/BoxedHybridObject.js.map +1 -0
- package/lib/module/ModuleNotFoundError.js +3 -15
- package/lib/module/ModuleNotFoundError.js.map +1 -1
- package/lib/module/NitroModules.js +2 -100
- package/lib/module/NitroModules.js.map +1 -1
- package/lib/module/NitroModulesProxy.js +4 -0
- package/lib/module/NitroModulesProxy.js.map +1 -0
- package/lib/module/turbomodule/NativeNitroModules.js +31 -0
- package/lib/module/turbomodule/NativeNitroModules.js.map +1 -0
- package/lib/{NitroModulesTurboModule.web.js → module/turbomodule/NativeNitroModules.web.js} +9 -1
- package/lib/module/turbomodule/NativeNitroModules.web.js.map +1 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/turbomodule/NativeNitroModules.d.ts +7 -0
- package/lib/turbomodule/NativeNitroModules.js +27 -0
- package/lib/turbomodule/NativeNitroModules.web.d.ts +2 -0
- package/lib/turbomodule/NativeNitroModules.web.js +9 -0
- package/lib/typescript/AnyMap.d.ts +20 -0
- package/lib/typescript/BoxedHybridObject.d.ts +13 -0
- package/lib/typescript/BoxedHybridObject.d.ts.map +1 -0
- package/lib/typescript/ModuleNotFoundError.d.ts +7 -0
- package/lib/typescript/ModuleNotFoundError.d.ts.map +1 -1
- package/lib/typescript/NitroModules.d.ts +1 -83
- package/lib/typescript/NitroModules.d.ts.map +1 -1
- package/lib/typescript/NitroModulesProxy.d.ts +59 -0
- package/lib/typescript/NitroModulesProxy.d.ts.map +1 -0
- package/lib/typescript/__tests__/index.test.d.ts +1 -0
- package/lib/typescript/index.d.ts +4 -0
- package/lib/typescript/turbomodule/NativeNitroModules.d.ts +8 -0
- package/lib/typescript/turbomodule/NativeNitroModules.d.ts.map +1 -0
- package/lib/typescript/turbomodule/NativeNitroModules.web.d.ts +3 -0
- package/lib/typescript/turbomodule/NativeNitroModules.web.d.ts.map +1 -0
- package/package.json +10 -3
- package/src/BoxedHybridObject.ts +13 -0
- package/src/ModuleNotFoundError.ts +3 -19
- package/src/NitroModules.ts +2 -108
- package/src/NitroModulesProxy.ts +61 -0
- package/src/turbomodule/NativeNitroModules.ts +48 -0
- package/src/turbomodule/NativeNitroModules.web.ts +16 -0
- package/android/src/main/java/com/margelo/nitro/NitroModulesPackage.java +0 -30
- package/cpp/turbomodule/NativeNitroModules.cpp +0 -146
- package/cpp/turbomodule/NativeNitroModules.h +0 -8
- package/cpp/turbomodule/NativeNitroModules.hpp +0 -38
- package/cpp/turbomodule/RegisterNativeNitroModules.cpp +0 -33
- package/cpp/turbomodule/RegisterNativeNitroModules.hpp +0 -21
- package/ios/turbomodule/NitroModuleOnLoad.mm +0 -32
- package/lib/NativeNitroModules.d.ts +0 -16
- package/lib/NativeNitroModules.js +0 -22
- package/lib/NativeNitroModules.web.d.ts +0 -4
- package/lib/NativeNitroModules.web.js +0 -3
- package/lib/NitroModulesTurboModule.d.ts +0 -18
- package/lib/NitroModulesTurboModule.js +0 -23
- package/lib/NitroModulesTurboModule.web.d.ts +0 -1
- package/lib/commonjs/NitroModulesTurboModule.js +0 -34
- package/lib/commonjs/NitroModulesTurboModule.js.map +0 -1
- package/lib/commonjs/NitroModulesTurboModule.web.js +0 -11
- package/lib/commonjs/NitroModulesTurboModule.web.js.map +0 -1
- package/lib/module/NitroModulesTurboModule.js +0 -30
- package/lib/module/NitroModulesTurboModule.js.map +0 -1
- package/lib/module/NitroModulesTurboModule.web.js +0 -7
- package/lib/module/NitroModulesTurboModule.web.js.map +0 -1
- package/lib/typescript/NitroModulesTurboModule.d.ts +0 -19
- package/lib/typescript/NitroModulesTurboModule.d.ts.map +0 -1
- package/lib/typescript/NitroModulesTurboModule.web.d.ts +0 -2
- package/lib/typescript/NitroModulesTurboModule.web.d.ts.map +0 -1
- package/src/NitroModulesTurboModule.ts +0 -50
- package/src/NitroModulesTurboModule.web.ts +0 -7
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Created by Marc Rousavy on 07.10.24.
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
#pragma once
|
|
6
|
+
|
|
7
|
+
#include "IsSharedPtrTo.hpp"
|
|
8
|
+
#include "NitroDefines.hpp"
|
|
9
|
+
#include "TypeInfo.hpp"
|
|
10
|
+
#include <jsi/jsi.h>
|
|
11
|
+
#include <type_traits>
|
|
12
|
+
|
|
13
|
+
namespace margelo::nitro {
|
|
14
|
+
|
|
15
|
+
using namespace facebook;
|
|
16
|
+
|
|
17
|
+
// jsi::HostObject <> {}
|
|
18
|
+
template <typename T>
|
|
19
|
+
struct JSIConverter<T, std::enable_if_t<is_shared_ptr_to_v<T, jsi::HostObject>>> final {
|
|
20
|
+
using TPointee = typename T::element_type;
|
|
21
|
+
|
|
22
|
+
static inline T fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
|
|
23
|
+
#ifdef NITRO_DEBUG
|
|
24
|
+
if (!arg.isObject()) [[unlikely]] {
|
|
25
|
+
if (arg.isUndefined()) [[unlikely]] {
|
|
26
|
+
throw jsi::JSError(runtime, invalidTypeErrorMessage("undefined", "It is undefined!"));
|
|
27
|
+
} else {
|
|
28
|
+
std::string stringRepresentation = arg.toString(runtime).utf8(runtime);
|
|
29
|
+
throw jsi::JSError(runtime, invalidTypeErrorMessage(stringRepresentation, "It is not an object!"));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
#endif
|
|
33
|
+
jsi::Object object = arg.asObject(runtime);
|
|
34
|
+
|
|
35
|
+
#ifdef NITRO_DEBUG
|
|
36
|
+
if (!object.isHostObject<TPointee>(runtime)) [[unlikely]] {
|
|
37
|
+
if (!object.isHostObject(runtime)) [[unlikely]] {
|
|
38
|
+
std::string stringRepresentation = arg.toString(runtime).utf8(runtime);
|
|
39
|
+
throw jsi::JSError(runtime, invalidTypeErrorMessage(stringRepresentation, "It is not a HostObject at all!"));
|
|
40
|
+
} else {
|
|
41
|
+
std::string stringRepresentation = arg.toString(runtime).utf8(runtime);
|
|
42
|
+
throw jsi::JSError(runtime, invalidTypeErrorMessage(stringRepresentation, "It is a different HostObject<T>!"));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
#endif
|
|
46
|
+
return object.getHostObject<TPointee>(runtime);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
static inline jsi::Value toJSI(jsi::Runtime& runtime, const T& arg) {
|
|
50
|
+
if (arg == nullptr) [[unlikely]] {
|
|
51
|
+
std::string typeName = TypeInfo::getFriendlyTypename<TPointee>();
|
|
52
|
+
throw jsi::JSError(runtime, "Cannot convert nullptr to HostObject<" + typeName + ">!");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return jsi::Object::createFromHostObject(runtime, arg);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
|
|
59
|
+
if (value.isObject()) {
|
|
60
|
+
jsi::Object object = value.getObject(runtime);
|
|
61
|
+
return object.isHostObject<TPointee>(runtime);
|
|
62
|
+
}
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private:
|
|
67
|
+
static std::string invalidTypeErrorMessage(const std::string& typeDescription, const std::string& reason) {
|
|
68
|
+
std::string typeName = TypeInfo::getFriendlyTypename<TPointee>();
|
|
69
|
+
return "Cannot convert \"" + typeDescription + "\" to HostObject<" + typeName + ">! " + reason;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
} // namespace margelo::nitro
|
|
@@ -78,7 +78,7 @@ struct JSIConverter<T, std::enable_if_t<is_shared_ptr_to_v<T, jsi::NativeState>>
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
private:
|
|
81
|
-
static
|
|
81
|
+
static std::string invalidTypeErrorMessage(const std::string& typeDescription, const std::string& reason) {
|
|
82
82
|
std::string typeName = TypeInfo::getFriendlyTypename<TPointee>();
|
|
83
83
|
return "Cannot convert \"" + typeDescription + "\" to NativeState<" + typeName + ">! " + reason;
|
|
84
84
|
}
|
|
@@ -34,6 +34,7 @@ struct JSIConverter<std::future<TResult>> final {
|
|
|
34
34
|
static inline std::future<TResult> fromJSI(jsi::Runtime&, const jsi::Value&) {
|
|
35
35
|
throw std::runtime_error("Promise cannot be converted to a native type - it needs to be awaited first!");
|
|
36
36
|
}
|
|
37
|
+
|
|
37
38
|
static inline jsi::Value toJSI(jsi::Runtime& runtime, std::future<TResult>&& arg) {
|
|
38
39
|
auto sharedFuture = std::make_shared<std::future<TResult>>(std::move(arg));
|
|
39
40
|
std::shared_ptr<Dispatcher> strongDispatcher = Dispatcher::getRuntimeGlobalDispatcher(runtime);
|
|
@@ -29,8 +29,8 @@ struct JSIConverter<std::tuple<Types...>> final {
|
|
|
29
29
|
jsi::Array array = object.asArray(runtime);
|
|
30
30
|
if (array.size(runtime) != sizeof...(Types)) [[unlikely]] {
|
|
31
31
|
std::string types = TypeInfo::getFriendlyTypenames<Types...>();
|
|
32
|
-
throw std::
|
|
33
|
-
|
|
32
|
+
throw std::length_error("The given JS Array has " + std::to_string(array.size(runtime)) + " items, but std::tuple<" + types +
|
|
33
|
+
"> expects " + std::to_string(sizeof...(Types)) + " items.");
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
return copyArrayItemsToTuple(runtime, array, std::index_sequence_for<Types...>{});
|
package/cpp/jsi/JSIConverter.hpp
CHANGED
|
@@ -184,6 +184,7 @@ struct JSIConverter<std::string> final {
|
|
|
184
184
|
#include "JSIConverter+AnyMap.hpp"
|
|
185
185
|
#include "JSIConverter+ArrayBuffer.hpp"
|
|
186
186
|
#include "JSIConverter+Function.hpp"
|
|
187
|
+
#include "JSIConverter+HostObject.hpp"
|
|
187
188
|
#include "JSIConverter+HybridObject.hpp"
|
|
188
189
|
#include "JSIConverter+Optional.hpp"
|
|
189
190
|
#include "JSIConverter+Promise.hpp"
|
|
@@ -31,7 +31,8 @@ jsi::Value HybridObjectPrototype::createPrototype(jsi::Runtime& runtime, const s
|
|
|
31
31
|
|
|
32
32
|
// 2. We didn't find the given prototype in cache (either it's a new prototype, or a new runtime),
|
|
33
33
|
// so we need to create it. First, we need some helper methods from JS
|
|
34
|
-
|
|
34
|
+
std::string typeName = TypeInfo::getFriendlyTypename(prototype->getNativeInstanceId(), true);
|
|
35
|
+
Logger::log(LogLevel::Info, TAG, "Creating new JS prototype for C++ instance type \"%s\"...", typeName.c_str());
|
|
35
36
|
jsi::Object objectConstructor = runtime.global().getPropertyAsObject(runtime, "Object");
|
|
36
37
|
jsi::Function objectCreate = objectConstructor.getPropertyAsFunction(runtime, "create");
|
|
37
38
|
jsi::Function objectDefineProperty = objectConstructor.getPropertyAsFunction(runtime, "defineProperty");
|
|
@@ -71,8 +72,8 @@ jsi::Value HybridObjectPrototype::createPrototype(jsi::Runtime& runtime, const s
|
|
|
71
72
|
|
|
72
73
|
// 7. In DEBUG, add a __type info to the prototype object.
|
|
73
74
|
#ifdef NITRO_DEBUG
|
|
74
|
-
auto
|
|
75
|
-
cachedObject->setProperty(runtime, "__type", jsi::String::createFromUtf8(runtime,
|
|
75
|
+
auto prototypeName = "Prototype<" + typeName + ">";
|
|
76
|
+
cachedObject->setProperty(runtime, "__type", jsi::String::createFromUtf8(runtime, prototypeName));
|
|
76
77
|
#endif
|
|
77
78
|
|
|
78
79
|
// 8. Return it!
|
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
#pragma once
|
|
6
6
|
|
|
7
7
|
#include "Dispatcher.hpp"
|
|
8
|
+
|
|
9
|
+
// This is react-native specific
|
|
10
|
+
#if __has_include(<ReactCommon/CallInvoker.h>)
|
|
8
11
|
#include <ReactCommon/CallInvoker.h>
|
|
9
12
|
|
|
10
13
|
namespace margelo::nitro {
|
|
@@ -31,3 +34,5 @@ private:
|
|
|
31
34
|
};
|
|
32
35
|
|
|
33
36
|
} // namespace margelo::nitro
|
|
37
|
+
|
|
38
|
+
#endif
|
package/cpp/utils/TypeInfo.hpp
CHANGED
|
@@ -7,10 +7,12 @@
|
|
|
7
7
|
|
|
8
8
|
#pragma once
|
|
9
9
|
|
|
10
|
+
#include "NitroDefines.hpp"
|
|
10
11
|
#include <regex>
|
|
11
12
|
#include <sstream>
|
|
12
13
|
#include <string>
|
|
13
14
|
#include <type_traits>
|
|
15
|
+
#include <typeindex>
|
|
14
16
|
|
|
15
17
|
#if __has_include(<cxxabi.h>)
|
|
16
18
|
#include <cxxabi.h>
|
|
@@ -38,12 +40,10 @@ public:
|
|
|
38
40
|
return std::regex_replace(original, re, replacement);
|
|
39
41
|
}
|
|
40
42
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
static inline std::string getFriendlyTypename() {
|
|
46
|
-
std::string name = typeid(T).name();
|
|
43
|
+
static inline std::string demangleName(const std::string& typeName, bool removeNamespace = false) {
|
|
44
|
+
#ifdef NITRO_DEBUG
|
|
45
|
+
// In debug, we demangle the name using Cxx ABI and prettify it.
|
|
46
|
+
std::string name = typeName;
|
|
47
47
|
#if __has_include(<cxxabi.h>)
|
|
48
48
|
int status = 0;
|
|
49
49
|
char* demangled_name = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);
|
|
@@ -64,31 +64,51 @@ public:
|
|
|
64
64
|
name,
|
|
65
65
|
R"(std::__1::unordered_map<([^,]+), ([^>]+), std::__1::hash<\1>, std::__1::equal_to<\1>, std::__1::allocator<std::__1::pair<const \1, \2>>>)",
|
|
66
66
|
"std::unordered_map<$1, $2>");
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
|
|
68
|
+
if (removeNamespace) [[unlikely]] {
|
|
69
|
+
// replace `margelo::nitro::HybridObject` -> `HybridObject`
|
|
70
|
+
size_t lastColon = name.rfind(':');
|
|
71
|
+
if (lastColon != std::string::npos) {
|
|
72
|
+
// Type contains a namespace - remove it
|
|
73
|
+
name = name.substr(lastColon + 1);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
70
76
|
|
|
71
77
|
return name;
|
|
78
|
+
#else
|
|
79
|
+
// In release, we don't do any of that. Just return the ugly name.
|
|
80
|
+
return typeName;
|
|
81
|
+
#endif
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Get a friendly name of the given `type_info` (if possible, demangled)
|
|
86
|
+
*/
|
|
87
|
+
static inline std::string getFriendlyTypename(const std::type_info& type, bool removeNamespace = false) {
|
|
88
|
+
std::string typeName = type.name();
|
|
89
|
+
return demangleName(typeName, removeNamespace);
|
|
72
90
|
}
|
|
73
91
|
|
|
74
92
|
/**
|
|
75
|
-
* Get a friendly name of the
|
|
93
|
+
* Get a friendly name of the given `type_index` (if possible, demangled)
|
|
94
|
+
*/
|
|
95
|
+
static inline std::string getFriendlyTypename(const std::type_index& typeIndex, bool removeNamespace = false) {
|
|
96
|
+
std::string typeName = typeIndex.name();
|
|
97
|
+
return demangleName(typeName, removeNamespace);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Get a friendly name of the type `T` (if possible, demangled)
|
|
76
102
|
*/
|
|
77
103
|
template <typename T>
|
|
78
|
-
static inline std::string
|
|
79
|
-
|
|
80
|
-
size_t lastColon = friendly.rfind(':');
|
|
81
|
-
if (lastColon == std::string::npos) {
|
|
82
|
-
// Type does not have any namespace (:), just return as is.
|
|
83
|
-
return friendly;
|
|
84
|
-
}
|
|
85
|
-
return friendly.substr(lastColon + 1);
|
|
104
|
+
static inline std::string getFriendlyTypename(bool removeNamespace = false) {
|
|
105
|
+
return getFriendlyTypename(typeid(T), removeNamespace);
|
|
86
106
|
}
|
|
87
107
|
|
|
88
108
|
template <typename... Types>
|
|
89
|
-
static inline std::string getFriendlyTypenames() {
|
|
109
|
+
static inline std::string getFriendlyTypenames(bool removeNamespace = false) {
|
|
90
110
|
std::ostringstream stream;
|
|
91
|
-
((stream << TypeInfo::getFriendlyTypename<Types>() << ", "), ...);
|
|
111
|
+
((stream << TypeInfo::getFriendlyTypename<Types>(removeNamespace) << ", "), ...);
|
|
92
112
|
std::string string = stream.str();
|
|
93
113
|
return string.substr(0, string.length() - 2);
|
|
94
114
|
}
|
|
@@ -35,7 +35,7 @@ public:
|
|
|
35
35
|
* Once the `ArrayBuffer` is no longer in use, the given `deleteFunc` will be called with the given `deleteFuncContext`
|
|
36
36
|
* as an argument. The caller is responsible for deleting `data` once this is called.
|
|
37
37
|
*/
|
|
38
|
-
static ArrayBufferHolder makeBuffer(uint8_t* data, size_t size, SwiftClosure destroy) {
|
|
38
|
+
static ArrayBufferHolder makeBuffer(uint8_t* _Nonnull data, size_t size, SwiftClosure destroy) {
|
|
39
39
|
std::function<void()> deleteFunc = destroy.getFunction();
|
|
40
40
|
auto arrayBuffer = ArrayBuffer::makeBuffer(data, size, std::move(deleteFunc));
|
|
41
41
|
return ArrayBufferHolder(arrayBuffer);
|
|
@@ -10,7 +10,7 @@ import Foundation
|
|
|
10
10
|
/**
|
|
11
11
|
* A base protocol for all Swift-based Hybrid Objects.
|
|
12
12
|
*/
|
|
13
|
-
public protocol HybridObjectSpec {
|
|
13
|
+
public protocol HybridObjectSpec: AnyObject {
|
|
14
14
|
/**
|
|
15
15
|
* Holds the C++ HybridObject and it's context.
|
|
16
16
|
* Use the default initializer in your implementation, C++ will set and get this value.
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
//
|
|
7
7
|
|
|
8
8
|
#include "NitroLogger.hpp"
|
|
9
|
-
#include "AnyMapHolder.hpp"
|
|
10
9
|
#include "NitroDefines.hpp"
|
|
11
10
|
#include <Foundation/Foundation.h>
|
|
12
11
|
|
|
@@ -23,7 +22,7 @@ const char* levelToString(LogLevel level) {
|
|
|
23
22
|
case LogLevel::Error:
|
|
24
23
|
return "ERROR";
|
|
25
24
|
default:
|
|
26
|
-
throw std::
|
|
25
|
+
throw std::invalid_argument("Invalid LogLevel!");
|
|
27
26
|
}
|
|
28
27
|
}
|
|
29
28
|
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
//
|
|
2
|
+
// NativeNitroModules+NewArch.mm
|
|
3
|
+
// DoubleConversion
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 21.06.24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#import "NativeNitroModules.h"
|
|
9
|
+
|
|
10
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
11
|
+
|
|
12
|
+
#import "CallInvokerDispatcher.hpp"
|
|
13
|
+
#import "InstallNitro.hpp"
|
|
14
|
+
|
|
15
|
+
#import <ReactCommon/CallInvoker.h>
|
|
16
|
+
#import <ReactCommon/RCTTurboModuleWithJSIBindings.h>
|
|
17
|
+
|
|
18
|
+
using namespace facebook;
|
|
19
|
+
using namespace margelo;
|
|
20
|
+
|
|
21
|
+
// Make NativeNitroModules comply to RCTTurboModuleWithJSIBindings
|
|
22
|
+
@interface NativeNitroModules () <RCTTurboModuleWithJSIBindings>
|
|
23
|
+
@end
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* NativeNitroModules implementation for the new architecture.
|
|
27
|
+
* This uses `installJSIBindingsWithRuntime:` to install the `global.NitroModulesProxy` into the JS Runtime.
|
|
28
|
+
*/
|
|
29
|
+
@implementation NativeNitroModules {
|
|
30
|
+
bool _didInstall;
|
|
31
|
+
std::weak_ptr<react::CallInvoker> _callInvoker;
|
|
32
|
+
}
|
|
33
|
+
RCT_EXPORT_MODULE(NitroModules)
|
|
34
|
+
|
|
35
|
+
- (void)installJSIBindingsWithRuntime:(jsi::Runtime&)runtime {
|
|
36
|
+
// 1. Get CallInvoker we cached statically
|
|
37
|
+
auto callInvoker = _callInvoker.lock();
|
|
38
|
+
if (callInvoker == nullptr) {
|
|
39
|
+
throw std::runtime_error("Cannot install global.NitroModulesProxy - CallInvoker was null!");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 2. Wrap CallInvoker as Dispatcher
|
|
43
|
+
auto dispatcher = std::make_shared<nitro::CallInvokerDispatcher>(callInvoker);
|
|
44
|
+
|
|
45
|
+
// 3. Install Nitro
|
|
46
|
+
nitro::install(runtime, dispatcher);
|
|
47
|
+
_didInstall = true;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
- (NSString*)install {
|
|
51
|
+
if (_didInstall) {
|
|
52
|
+
// installJSIBindingsWithRuntime ran successfully.
|
|
53
|
+
return nil;
|
|
54
|
+
} else {
|
|
55
|
+
return @"installJSIBindingsWithRuntime: was not called - JSI Bindings could not be installed!";
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
- (std::shared_ptr<react::TurboModule>)getTurboModule:(const react::ObjCTurboModule::InitParams&)params {
|
|
60
|
+
// Cache the CallInvoker statically (weak) - we use it later in `installJSIBindingsWithRuntime:`.
|
|
61
|
+
_callInvoker = params.jsInvoker;
|
|
62
|
+
return std::make_shared<react::NativeNitroModulesSpecJSI>(params);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@end
|
|
66
|
+
|
|
67
|
+
#endif
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
//
|
|
2
|
+
// NativeNitroModules+OldArch.mm
|
|
3
|
+
// DoubleConversion
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 21.06.24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#import "NativeNitroModules.h"
|
|
9
|
+
|
|
10
|
+
#ifndef RCT_NEW_ARCH_ENABLED
|
|
11
|
+
|
|
12
|
+
#import "CallInvokerDispatcher.hpp"
|
|
13
|
+
#import "InstallNitro.hpp"
|
|
14
|
+
|
|
15
|
+
#import <React/RCTBridge+Private.h>
|
|
16
|
+
#import <React/RCTBridge.h>
|
|
17
|
+
|
|
18
|
+
using namespace facebook;
|
|
19
|
+
using namespace margelo;
|
|
20
|
+
|
|
21
|
+
// forward-declaration (private API)
|
|
22
|
+
@interface RCTBridge (JSIRuntime)
|
|
23
|
+
- (void*)runtime;
|
|
24
|
+
- (std::shared_ptr<react::CallInvoker>)jsCallInvoker;
|
|
25
|
+
@end
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* NativeNitroModules implementation for the old architecture.
|
|
29
|
+
* This uses `RCTBridge` to grab the `jsi::Runtime` and `react::CallInvoker`.
|
|
30
|
+
*/
|
|
31
|
+
@implementation NativeNitroModules
|
|
32
|
+
RCT_EXPORT_MODULE(NitroModules)
|
|
33
|
+
|
|
34
|
+
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(install) {
|
|
35
|
+
try {
|
|
36
|
+
// 1. Cast RCTBridge to a RCTCxxBridge (ObjC)
|
|
37
|
+
RCTCxxBridge* cxxBridge = (RCTCxxBridge*)RCTBridge.currentBridge;
|
|
38
|
+
if (!cxxBridge) {
|
|
39
|
+
return @"RCTBridge is not a RCTCxxBridge!";
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 2. Access jsi::Runtime and cast from void*
|
|
43
|
+
jsi::Runtime* runtime = reinterpret_cast<jsi::Runtime*>(cxxBridge.runtime);
|
|
44
|
+
if (!runtime) {
|
|
45
|
+
return @"jsi::Runtime on RCTCxxBridge was null!";
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// 3. Access react::CallInvoker
|
|
49
|
+
std::shared_ptr<react::CallInvoker> callInvoker = cxxBridge.jsCallInvoker;
|
|
50
|
+
if (!callInvoker) {
|
|
51
|
+
return @"react::CallInvoker on RCTCxxBridge was null!";
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// 4. Wrap react::CallInvoker in nitro::Dispatcher
|
|
55
|
+
auto dispatcher = std::make_shared<nitro::CallInvokerDispatcher>(callInvoker);
|
|
56
|
+
|
|
57
|
+
// 5. Install Nitro
|
|
58
|
+
nitro::install(*runtime, dispatcher);
|
|
59
|
+
return nil;
|
|
60
|
+
} catch (std::exception& error) {
|
|
61
|
+
// ?. Any C++ error occurred (probably in nitro::install()?)
|
|
62
|
+
return [NSString stringWithCString:error.what() encoding:kCFStringEncodingUTF8];
|
|
63
|
+
} catch (...) {
|
|
64
|
+
// ?. Any non-std error occured (probably in ObjC code)
|
|
65
|
+
return @"Unknown non-std error occurred while installing Nitro!";
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@end
|
|
70
|
+
|
|
71
|
+
#endif
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
//
|
|
2
|
+
// NativeNitroModules.h
|
|
3
|
+
// NitroModules
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 07.10.24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
9
|
+
|
|
10
|
+
// New Architecture uses the Codegen'd Spec (TurboModule)
|
|
11
|
+
#import "NitroModulesSpec.h"
|
|
12
|
+
@interface NativeNitroModules : NSObject <NativeNitroModulesSpec>
|
|
13
|
+
@end
|
|
14
|
+
|
|
15
|
+
#else
|
|
16
|
+
|
|
17
|
+
// Old Architecture is an untyped RCTBridgeModule
|
|
18
|
+
#import <React/RCTBridgeModule.h>
|
|
19
|
+
@interface NativeNitroModules : NSObject <RCTBridgeModule>
|
|
20
|
+
@end
|
|
21
|
+
|
|
22
|
+
#endif
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { HybridObject } from './HybridObject';
|
|
2
|
+
/**
|
|
3
|
+
* Represents a boxed {@linkcode HybridObject} that can later be unboxed again.
|
|
4
|
+
* This is implemented as a `jsi::HostObject`.
|
|
5
|
+
*/
|
|
6
|
+
export interface BoxedHybridObject<T extends HybridObject> {
|
|
7
|
+
/**
|
|
8
|
+
* Unboxes the {@linkcode HybridObject}.
|
|
9
|
+
* This can be called from a different Runtime than the one it was boxed in.
|
|
10
|
+
*/
|
|
11
|
+
unbox(): T;
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -20,26 +20,16 @@ function getFrameworkType() {
|
|
|
20
20
|
}
|
|
21
21
|
export class ModuleNotFoundError extends Error {
|
|
22
22
|
constructor(cause) {
|
|
23
|
-
// TurboModule not found, something went wrong!
|
|
24
|
-
if (global.__turboModuleProxy == null) {
|
|
25
|
-
// TurboModules are not available/new arch is not enabled.
|
|
26
|
-
const message = 'Failed to get NitroModules: NitroModules require the new architecture to be enabled!';
|
|
27
|
-
const suggestions = [];
|
|
28
|
-
suggestions.push('Enable the new architecture in your app to use NitroModules. (See https://github.com/reactwg/react-native-new-architecture/blob/main/docs/enable-apps.md)');
|
|
29
|
-
const error = messageWithSuggestions(message, suggestions);
|
|
30
|
-
super(error, { cause: cause });
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
23
|
const framework = getFrameworkType();
|
|
34
24
|
if (framework === 'expo-go') {
|
|
35
25
|
super('NitroModules are not supported in Expo Go! Use EAS (`expo prebuild`) or eject to a bare workflow instead.');
|
|
36
26
|
return;
|
|
37
27
|
}
|
|
38
|
-
const message = 'Failed to get NitroModules: The native "NitroModules"
|
|
28
|
+
const message = 'Failed to get NitroModules: The native "NitroModules" Turbo/Native-Module could not be found.';
|
|
39
29
|
const suggestions = [];
|
|
40
30
|
suggestions.push('Make sure react-native-nitro-modules/NitroModules is correctly autolinked (run `npx react-native config` to verify)');
|
|
41
|
-
suggestions.push('Make sure you enabled the new architecture (TurboModules) and CodeGen properly generated the "NativeNitroModules"/
|
|
42
|
-
suggestions.push('Make sure you are using react-native 0.
|
|
31
|
+
suggestions.push('Make sure you enabled the new architecture (TurboModules) and CodeGen properly generated the "NativeNitroModules"/NitroModules specs. See https://github.com/reactwg/react-native-new-architecture/blob/main/docs/enable-apps.md');
|
|
32
|
+
suggestions.push('Make sure you are using react-native 0.75.0 or higher.');
|
|
43
33
|
suggestions.push('Make sure you rebuilt the app.');
|
|
44
34
|
if (framework === 'expo') {
|
|
45
35
|
suggestions.push('Make sure you ran `expo prebuild`.');
|
package/lib/NitroModules.d.ts
CHANGED
|
@@ -1,83 +1 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* Represents a boxed {@linkcode HybridObject} that can later be unboxed again.
|
|
4
|
-
* This is implemented as a `jsi::HostObject`.
|
|
5
|
-
*/
|
|
6
|
-
export interface BoxedHybridObject<T extends HybridObject> {
|
|
7
|
-
/**
|
|
8
|
-
* Unboxes the {@linkcode HybridObject}.
|
|
9
|
-
* This can be called from a different Runtime than the one it was boxed in.
|
|
10
|
-
*/
|
|
11
|
-
unbox(): T;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* A lazy proxy for initializing Nitro Modules HybridObjects.
|
|
15
|
-
*/
|
|
16
|
-
export declare const NitroModules: {
|
|
17
|
-
/**
|
|
18
|
-
* Create a new instance of the `HybridObject` {@linkcode T}.
|
|
19
|
-
*
|
|
20
|
-
* {@linkcode T} has to be registered beforehand under the name {@linkcode name}
|
|
21
|
-
* in the native Nitro Modules `HybridObjectRegistry`.
|
|
22
|
-
*
|
|
23
|
-
* @param name The name of the `HybridObject` under which it was registered at.
|
|
24
|
-
* @returns An instance of {@linkcode T}
|
|
25
|
-
* @throws an Error if {@linkcode T} has not been registered under the name {@linkcode name}.
|
|
26
|
-
*/
|
|
27
|
-
createHybridObject<T extends HybridObject<any>>(name: string): T;
|
|
28
|
-
/**
|
|
29
|
-
* Get a list of all registered Hybrid Objects.
|
|
30
|
-
*/
|
|
31
|
-
getAllHybridObjectNames(): string[];
|
|
32
|
-
/**
|
|
33
|
-
* Returns whether a HybridObject under the given {@linkcode name} is registered, or not.
|
|
34
|
-
*/
|
|
35
|
-
hasHybridObject(name: string): boolean;
|
|
36
|
-
/**
|
|
37
|
-
* Returns whether the given {@linkcode object} has a `NativeState` or not.
|
|
38
|
-
*
|
|
39
|
-
* This can be a quick way to check if an object is a valid {@linkcode HybridObject},
|
|
40
|
-
* and has not yet been disposed.
|
|
41
|
-
* @example
|
|
42
|
-
* ```ts
|
|
43
|
-
* const someObject = NitroModules.createHybridObject<Some>('Some')
|
|
44
|
-
* console.log(NitroModules.hasNativeState(someObject)) // -> true
|
|
45
|
-
* someObject.dispose()
|
|
46
|
-
* console.log(NitroModules.hasNativeState(someObject)) // -> false
|
|
47
|
-
* ```
|
|
48
|
-
*/
|
|
49
|
-
hasNativeState(object: object): boolean;
|
|
50
|
-
/**
|
|
51
|
-
* Forcefully removes the `NativeState` of the given {@linkcode object}.
|
|
52
|
-
*/
|
|
53
|
-
removeNativeState(object: object): void;
|
|
54
|
-
/**
|
|
55
|
-
* Gets the current build type configuration as defined in the `NITRO_DEBUG`
|
|
56
|
-
* preprocessor flag.
|
|
57
|
-
*/
|
|
58
|
-
readonly buildType: "debug" | "release";
|
|
59
|
-
/**
|
|
60
|
-
* Boxes the given {@linkcode hybridObject} into a {@linkcode BoxedHybridObject<T>}, which can
|
|
61
|
-
* later be unboxed in a separate Runtime.
|
|
62
|
-
*
|
|
63
|
-
* While Nitro is runtime-agnostic and all `HybridObject`s can be used from a any Runtime,
|
|
64
|
-
* some threading/worklet libraries (like [react-native-worklets-core](https://github.com/margelo/react-native-worklets-core))
|
|
65
|
-
* do not yet support copying over `HybridObject`s as they use newer JSI APIs like `jsi::NativeState`.
|
|
66
|
-
*
|
|
67
|
-
* While those APIs are not yet available, you can still use every Nitro Hybrid Object in a separate
|
|
68
|
-
* Runtime/Worklet context by just boxing it yourself:
|
|
69
|
-
*
|
|
70
|
-
* @example
|
|
71
|
-
* ```ts
|
|
72
|
-
* const something = NitroModules.createHybridObject<Something>('Something')
|
|
73
|
-
* const boxed = NitroModules.box(something)
|
|
74
|
-
* const context = Worklets.createContext('DummyContext')
|
|
75
|
-
* context.runAsync(() => {
|
|
76
|
-
* 'worklet'
|
|
77
|
-
* const unboxed = boxed.unbox()
|
|
78
|
-
* console.log(unboxed.name) // --> "Something"
|
|
79
|
-
* })
|
|
80
|
-
* ```
|
|
81
|
-
*/
|
|
82
|
-
box<T extends HybridObject>(hybridObject: T): BoxedHybridObject<T>;
|
|
83
|
-
};
|
|
1
|
+
export * from './turbomodule/NativeNitroModules';
|