react-native-nitro-modules 0.10.0 → 0.11.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.
Files changed (111) hide show
  1. package/NitroModules.podspec +2 -0
  2. package/README.md +1 -1
  3. package/android/CMakeLists.txt +3 -0
  4. package/android/build.gradle +26 -2
  5. package/android/src/main/cpp/JNIOnLoad.cpp +5 -5
  6. package/android/src/main/cpp/turbomodule/JNitroModules.cpp +39 -0
  7. package/android/src/main/cpp/turbomodule/JNitroModules.hpp +37 -0
  8. package/android/src/main/java/com/margelo/nitro/NitroModules.kt +69 -0
  9. package/android/src/main/java/com/margelo/nitro/NitroModulesPackage.kt +34 -0
  10. package/android/src/main/java/com/margelo/nitro/core/HybridObject.kt +6 -2
  11. package/android/src/newarch/NitroModulesSpec.kt +6 -0
  12. package/android/src/oldarch/NitroModulesSpec.kt +9 -0
  13. package/cpp/core/HybridFunction.hpp +12 -3
  14. package/cpp/entrypoint/HybridNitroModulesProxy.cpp +55 -0
  15. package/cpp/entrypoint/HybridNitroModulesProxy.hpp +48 -0
  16. package/cpp/entrypoint/InstallNitro.cpp +28 -0
  17. package/cpp/entrypoint/InstallNitro.hpp +41 -0
  18. package/cpp/jsi/JSIConverter+HostObject.hpp +73 -0
  19. package/cpp/jsi/JSIConverter+HybridObject.hpp +1 -1
  20. package/cpp/jsi/JSIConverter.hpp +1 -0
  21. package/ios/core/HybridObjectSpec.swift +1 -1
  22. package/ios/platform/NitroLogger.mm +0 -1
  23. package/ios/turbomodule/NativeNitroModules+NewArch.mm +67 -0
  24. package/ios/turbomodule/NativeNitroModules+OldArch.mm +68 -0
  25. package/ios/turbomodule/NativeNitroModules.h +22 -0
  26. package/lib/BoxedHybridObject.d.ts +12 -0
  27. package/lib/BoxedHybridObject.js +1 -0
  28. package/lib/ModuleNotFoundError.js +3 -13
  29. package/lib/NitroModules.d.ts +1 -83
  30. package/lib/NitroModules.js +2 -94
  31. package/lib/NitroModulesProxy.d.ts +58 -0
  32. package/lib/NitroModulesProxy.js +1 -0
  33. package/lib/commonjs/BoxedHybridObject.js +6 -0
  34. package/lib/commonjs/BoxedHybridObject.js.map +1 -0
  35. package/lib/commonjs/ModuleNotFoundError.js +3 -15
  36. package/lib/commonjs/ModuleNotFoundError.js.map +1 -1
  37. package/lib/commonjs/NitroModules.js +11 -100
  38. package/lib/commonjs/NitroModules.js.map +1 -1
  39. package/lib/commonjs/NitroModulesProxy.js +6 -0
  40. package/lib/commonjs/NitroModulesProxy.js.map +1 -0
  41. package/lib/commonjs/turbomodule/NativeNitroModules.js +36 -0
  42. package/lib/commonjs/turbomodule/NativeNitroModules.js.map +1 -0
  43. package/lib/commonjs/turbomodule/NativeNitroModules.web.js +17 -0
  44. package/lib/commonjs/turbomodule/NativeNitroModules.web.js.map +1 -0
  45. package/lib/module/BoxedHybridObject.js +4 -0
  46. package/lib/module/BoxedHybridObject.js.map +1 -0
  47. package/lib/module/ModuleNotFoundError.js +3 -15
  48. package/lib/module/ModuleNotFoundError.js.map +1 -1
  49. package/lib/module/NitroModules.js +2 -100
  50. package/lib/module/NitroModules.js.map +1 -1
  51. package/lib/module/NitroModulesProxy.js +4 -0
  52. package/lib/module/NitroModulesProxy.js.map +1 -0
  53. package/lib/module/turbomodule/NativeNitroModules.js +31 -0
  54. package/lib/module/turbomodule/NativeNitroModules.js.map +1 -0
  55. package/lib/{NitroModulesTurboModule.web.js → module/turbomodule/NativeNitroModules.web.js} +9 -1
  56. package/lib/module/turbomodule/NativeNitroModules.web.js.map +1 -0
  57. package/lib/tsconfig.tsbuildinfo +1 -1
  58. package/lib/turbomodule/NativeNitroModules.d.ts +7 -0
  59. package/lib/turbomodule/NativeNitroModules.js +27 -0
  60. package/lib/turbomodule/NativeNitroModules.web.d.ts +2 -0
  61. package/lib/turbomodule/NativeNitroModules.web.js +9 -0
  62. package/lib/typescript/AnyMap.d.ts +20 -0
  63. package/lib/typescript/BoxedHybridObject.d.ts +13 -0
  64. package/lib/typescript/BoxedHybridObject.d.ts.map +1 -0
  65. package/lib/typescript/ModuleNotFoundError.d.ts +7 -0
  66. package/lib/typescript/ModuleNotFoundError.d.ts.map +1 -1
  67. package/lib/typescript/NitroModules.d.ts +1 -83
  68. package/lib/typescript/NitroModules.d.ts.map +1 -1
  69. package/lib/typescript/NitroModulesProxy.d.ts +59 -0
  70. package/lib/typescript/NitroModulesProxy.d.ts.map +1 -0
  71. package/lib/typescript/__tests__/index.test.d.ts +1 -0
  72. package/lib/typescript/index.d.ts +4 -0
  73. package/lib/typescript/turbomodule/NativeNitroModules.d.ts +8 -0
  74. package/lib/typescript/turbomodule/NativeNitroModules.d.ts.map +1 -0
  75. package/lib/typescript/turbomodule/NativeNitroModules.web.d.ts +3 -0
  76. package/lib/typescript/turbomodule/NativeNitroModules.web.d.ts.map +1 -0
  77. package/package.json +9 -1
  78. package/src/BoxedHybridObject.ts +13 -0
  79. package/src/ModuleNotFoundError.ts +3 -19
  80. package/src/NitroModules.ts +2 -108
  81. package/src/NitroModulesProxy.ts +61 -0
  82. package/src/turbomodule/NativeNitroModules.ts +48 -0
  83. package/src/turbomodule/NativeNitroModules.web.ts +16 -0
  84. package/android/src/main/java/com/margelo/nitro/NitroModulesPackage.java +0 -30
  85. package/cpp/turbomodule/NativeNitroModules.cpp +0 -146
  86. package/cpp/turbomodule/NativeNitroModules.h +0 -8
  87. package/cpp/turbomodule/NativeNitroModules.hpp +0 -38
  88. package/cpp/turbomodule/RegisterNativeNitroModules.cpp +0 -33
  89. package/cpp/turbomodule/RegisterNativeNitroModules.hpp +0 -21
  90. package/ios/turbomodule/NitroModuleOnLoad.mm +0 -32
  91. package/lib/NativeNitroModules.d.ts +0 -16
  92. package/lib/NativeNitroModules.js +0 -22
  93. package/lib/NativeNitroModules.web.d.ts +0 -4
  94. package/lib/NativeNitroModules.web.js +0 -3
  95. package/lib/NitroModulesTurboModule.d.ts +0 -18
  96. package/lib/NitroModulesTurboModule.js +0 -23
  97. package/lib/NitroModulesTurboModule.web.d.ts +0 -1
  98. package/lib/commonjs/NitroModulesTurboModule.js +0 -34
  99. package/lib/commonjs/NitroModulesTurboModule.js.map +0 -1
  100. package/lib/commonjs/NitroModulesTurboModule.web.js +0 -11
  101. package/lib/commonjs/NitroModulesTurboModule.web.js.map +0 -1
  102. package/lib/module/NitroModulesTurboModule.js +0 -30
  103. package/lib/module/NitroModulesTurboModule.js.map +0 -1
  104. package/lib/module/NitroModulesTurboModule.web.js +0 -7
  105. package/lib/module/NitroModulesTurboModule.web.js.map +0 -1
  106. package/lib/typescript/NitroModulesTurboModule.d.ts +0 -19
  107. package/lib/typescript/NitroModulesTurboModule.d.ts.map +0 -1
  108. package/lib/typescript/NitroModulesTurboModule.web.d.ts +0 -2
  109. package/lib/typescript/NitroModulesTurboModule.web.d.ts.map +0 -1
  110. package/src/NitroModulesTurboModule.ts +0 -50
  111. package/src/NitroModulesTurboModule.web.ts +0 -7
@@ -31,6 +31,8 @@ Pod::Spec.new do |s|
31
31
  "cpp/core/AnyMap.hpp",
32
32
  "cpp/core/ArrayBuffer.hpp",
33
33
  "cpp/core/HybridObject.hpp",
34
+ "cpp/entrypoint/HybridNitroModulesProxy.hpp",
35
+ "cpp/entrypoint/InstallNitro.hpp",
34
36
  "cpp/registry/HybridObjectRegistry.hpp",
35
37
  "cpp/jsi/JSIConverter.hpp",
36
38
  "cpp/threading/Dispatcher.hpp",
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- <a href="https://margelo.io">
1
+ <a href="https://margelo.com">
2
2
  <picture>
3
3
  <source media="(prefers-color-scheme: dark)" srcset="../../docs/static/img/banner-react-native-nitro-modules-dark.png" />
4
4
  <source media="(prefers-color-scheme: light)" srcset="../../docs/static/img/banner-react-native-nitro-modules-light.png" />
@@ -22,6 +22,7 @@ add_library(NitroModules SHARED
22
22
  include_directories(
23
23
  # Shared C++ includes
24
24
  ../cpp/core
25
+ ../cpp/entrypoint
25
26
  ../cpp/jsi
26
27
  ../cpp/platform
27
28
  ../cpp/registry
@@ -34,6 +35,7 @@ include_directories(
34
35
  # Android-specific C++ includes
35
36
  src/main/cpp/core
36
37
  src/main/cpp/registry
38
+ src/main/cpp/turbomodule
37
39
  src/main/cpp/platform
38
40
  src/main/cpp/utils
39
41
  )
@@ -51,4 +53,5 @@ target_link_libraries(
51
53
  fbjni::fbjni # <-- Facebook C++ JNI helpers
52
54
  ReactAndroid::jsi # <-- RN: JSI
53
55
  ReactAndroid::react_nativemodule_core # <-- RN: TurboModules Core
56
+ ReactAndroid::turbomodulejsijni # <-- RN: TurboModules utils (e.g. CallInvokerHolder)
54
57
  )
@@ -33,6 +33,8 @@ def getExtOrIntegerDefault(name) {
33
33
  return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["Nitro_" + name]).toInteger()
34
34
  }
35
35
 
36
+ logger.info("[NitroModules] Your app is boosted by nitro modules! 🔥")
37
+
36
38
  android {
37
39
  namespace "com.margelo.nitro"
38
40
 
@@ -65,6 +67,26 @@ android {
65
67
  prefabPublishing true
66
68
  }
67
69
 
70
+ packagingOptions {
71
+ excludes = [
72
+ "META-INF",
73
+ "META-INF/**",
74
+ "**/libc++_shared.so",
75
+ "**/libfbjni.so",
76
+ "**/libjsi.so",
77
+ "**/libfolly_json.so",
78
+ "**/libfolly_runtime.so",
79
+ "**/libglog.so",
80
+ "**/libhermes.so",
81
+ "**/libhermes-executor-debug.so",
82
+ "**/libhermes_executor.so",
83
+ "**/libreactnativejni.so",
84
+ "**/libturbomodulejsijni.so",
85
+ "**/libreact_nativemodule_core.so",
86
+ "**/libjscexecutor.so"
87
+ ]
88
+ }
89
+
68
90
  prefab {
69
91
  NitroModules {
70
92
  headers "${project.buildDir}/headers/nitromodules/"
@@ -91,8 +113,11 @@ android {
91
113
  if (isNewArchitectureEnabled()) {
92
114
  java.srcDirs += [
93
115
  // React Codegen files
94
- "${project.buildDir}/generated/source/codegen/java"
116
+ "${project.buildDir}/generated/source/codegen/java",
117
+ "src/newarch"
95
118
  ]
119
+ } else {
120
+ java.srcDirs += ["src/oldarch"]
96
121
  }
97
122
  }
98
123
  }
@@ -119,7 +144,6 @@ if (isNewArchitectureEnabled()) {
119
144
  }
120
145
  }
121
146
 
122
-
123
147
  task prepareHeaders(type: Copy) {
124
148
  from fileTree('./src/main/cpp').filter { it.isFile() }
125
149
  from fileTree('../cpp/').filter { it.isFile() }
@@ -4,8 +4,8 @@
4
4
  #include "JAnyValue.hpp"
5
5
  #include "JArrayBuffer.hpp"
6
6
  #include "JHybridObjectRegistry.hpp"
7
+ #include "JNitroModules.hpp"
7
8
  #include "JPromise.hpp"
8
- #include "RegisterNativeNitroModules.hpp"
9
9
  #include <fbjni/fbjni.h>
10
10
  #include <jni.h>
11
11
 
@@ -13,14 +13,14 @@ using namespace margelo::nitro;
13
13
 
14
14
  JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
15
15
  return facebook::jni::initialize(vm, [] {
16
- // 1. Initialize the Nitro JSI Turbo Module
17
- RegisterNativeNitroModules::registerNativeNitroModules();
18
-
19
- // 2. Initialize all Java bindings
16
+ // 1. Initialize all core Nitro Java bindings
20
17
  JHybridObjectRegistry::registerNatives();
21
18
  JArrayBuffer::registerNatives();
22
19
  JAnyMap::registerNatives();
23
20
  JAnyValue::registerNatives();
24
21
  JPromise::registerNatives();
22
+
23
+ // 2. Initialize the React Native TurboModule C++ part
24
+ JNitroModules::registerNatives();
25
25
  });
26
26
  }
@@ -0,0 +1,39 @@
1
+ //
2
+ // Created by Marc Rousavy on 07.10.24.
3
+ //
4
+
5
+ #include "JNitroModules.hpp"
6
+ #include "CallInvokerDispatcher.hpp"
7
+ #include "InstallNitro.hpp"
8
+
9
+ namespace margelo::nitro {
10
+
11
+ JNitroModules::JNitroModules() = default;
12
+
13
+ jni::local_ref<JNitroModules::jhybriddata> JNitroModules::initHybrid(jni::alias_ref<JNitroModules::jhybridobject>) {
14
+ return makeCxxInstance();
15
+ }
16
+
17
+ void JNitroModules::install(jlong runtimePointer, jni::alias_ref<react::CallInvokerHolder::javaobject> callInvokerHolder) {
18
+ auto runtime = reinterpret_cast<jsi::Runtime*>(runtimePointer);
19
+ if (runtime == nullptr) {
20
+ throw std::runtime_error("jsi::Runtime was null!");
21
+ }
22
+
23
+ if (callInvokerHolder == nullptr) {
24
+ throw std::runtime_error("CallInvokerHolder was null!");
25
+ }
26
+ auto callInvoker = callInvokerHolder->cthis()->getCallInvoker();
27
+ if (callInvoker == nullptr) {
28
+ throw std::runtime_error("CallInvoker was null!");
29
+ }
30
+
31
+ auto dispatcher = std::make_shared<CallInvokerDispatcher>(callInvoker);
32
+ margelo::nitro::install(*runtime, dispatcher);
33
+ }
34
+
35
+ void JNitroModules::registerNatives() {
36
+ registerHybrid({makeNativeMethod("initHybrid", JNitroModules::initHybrid), makeNativeMethod("install", JNitroModules::install)});
37
+ }
38
+
39
+ } // namespace margelo::nitro
@@ -0,0 +1,37 @@
1
+ //
2
+ // Created by Marc Rousavy on 07.10.24.
3
+ //
4
+
5
+ #pragma once
6
+
7
+ #include <ReactCommon/CallInvoker.h>
8
+ #include <ReactCommon/CallInvokerHolder.h>
9
+ #include <fbjni/fbjni.h>
10
+ #include <jsi/jsi.h>
11
+
12
+ namespace margelo::nitro {
13
+
14
+ using namespace facebook;
15
+
16
+ class JNitroModules final : public jni::HybridClass<JNitroModules> {
17
+ public:
18
+ static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/NitroModules;";
19
+
20
+ private:
21
+ explicit JNitroModules();
22
+
23
+ private:
24
+ // JNI Methods
25
+ static jni::local_ref<JNitroModules::jhybriddata> initHybrid(jni::alias_ref<jhybridobject> javaThis);
26
+ void install(jlong runtimePointer, jni::alias_ref<react::CallInvokerHolder::javaobject> callInvokerHolder);
27
+
28
+ private:
29
+ static auto constexpr TAG = "NitroModules";
30
+ using HybridBase::HybridBase;
31
+ friend HybridBase;
32
+
33
+ public:
34
+ static void registerNatives();
35
+ };
36
+
37
+ } // namespace margelo::nitro
@@ -0,0 +1,69 @@
1
+ package com.margelo.nitro
2
+
3
+ import androidx.annotation.Keep
4
+ import com.facebook.jni.HybridData
5
+ import com.facebook.proguard.annotations.DoNotStrip
6
+ import com.facebook.react.bridge.ReactApplicationContext
7
+ import com.facebook.react.bridge.ReactMethod
8
+ import com.facebook.react.common.annotations.FrameworkAPI
9
+ import com.facebook.react.turbomodule.core.CallInvokerHolderImpl
10
+ import com.facebook.react.turbomodule.core.interfaces.CallInvokerHolder
11
+
12
+ @DoNotStrip
13
+ @Keep
14
+ @OptIn(FrameworkAPI::class)
15
+ @Suppress("KotlinJniMissingFunction")
16
+ class NitroModules internal constructor(val context: ReactApplicationContext) : NitroModulesSpec(context) {
17
+ private val mHybridData: HybridData
18
+
19
+ init {
20
+ mHybridData = initHybrid()
21
+ applicationContext = context
22
+ }
23
+
24
+ override fun getName(): String {
25
+ return NAME
26
+ }
27
+
28
+ @ReactMethod(isBlockingSynchronousMethod = true)
29
+ override fun install(): String? {
30
+ try {
31
+ // 1. Get jsi::Runtime pointer
32
+ val jsContext = context.javaScriptContextHolder
33
+ ?: return "ReactApplicationContext.javaScriptContextHolder is null!"
34
+
35
+ // 2. Get CallInvokerHolder
36
+ val callInvokerHolder = context.jsCallInvokerHolder as? CallInvokerHolderImpl
37
+ ?: return "ReactApplicationContext.jsCallInvokerHolder is null!"
38
+
39
+ // 3. Install Nitro
40
+ install(jsContext.get(), callInvokerHolder)
41
+
42
+ return null
43
+ } catch (e: Throwable) {
44
+ // ?. Something went wrong! Maybe a JNI error?
45
+ return e.message
46
+ }
47
+ }
48
+
49
+ private external fun initHybrid(): HybridData
50
+ private external fun install(jsRuntimePointer: Long, callInvokerHolder: CallInvokerHolderImpl)
51
+
52
+ companion object {
53
+ /**
54
+ * The TurboModule's name.
55
+ */
56
+ const val NAME = "NitroModules"
57
+
58
+ /**
59
+ * Get the current `ReactApplicationContext`, or `null` if none is available.
60
+ */
61
+ @JvmStatic
62
+ var applicationContext: ReactApplicationContext? = null
63
+
64
+ init {
65
+ // Make sure Nitro's C++ library is loaded
66
+ JNIOnLoad.initializeNativeNitro()
67
+ }
68
+ }
69
+ }
@@ -0,0 +1,34 @@
1
+ package com.margelo.nitro
2
+
3
+ import com.facebook.react.TurboReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.module.model.ReactModuleInfo
7
+ import com.facebook.react.module.model.ReactModuleInfoProvider
8
+
9
+ class NitroModulesPackage : TurboReactPackage() {
10
+ override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
11
+ return if (name == NitroModules.NAME) {
12
+ NitroModules(reactContext)
13
+ } else {
14
+ null
15
+ }
16
+ }
17
+
18
+ override fun getReactModuleInfoProvider(): ReactModuleInfoProvider {
19
+ return ReactModuleInfoProvider {
20
+ val moduleInfos: MutableMap<String, ReactModuleInfo> = HashMap()
21
+ val isTurboModule: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
22
+ moduleInfos[NitroModules.NAME] = ReactModuleInfo(
23
+ NitroModules.NAME,
24
+ NitroModules.NAME,
25
+ canOverrideExistingModule = false,
26
+ needsEagerInit = false,
27
+ hasConstants = false,
28
+ isCxxModule = false,
29
+ isTurboModule = isTurboModule
30
+ )
31
+ moduleInfos
32
+ }
33
+ }
34
+ }
@@ -4,12 +4,16 @@ import androidx.annotation.Keep
4
4
  import com.facebook.jni.HybridData
5
5
  import com.facebook.proguard.annotations.DoNotStrip
6
6
 
7
+ interface ExtendableHybridClass {
8
+ fun updateNative(hybridData: HybridData)
9
+ }
10
+
7
11
  /**
8
12
  * A base class for all Kotlin-based HybridObjects.
9
13
  */
10
14
  @Keep
11
15
  @DoNotStrip
12
- abstract class HybridObject {
16
+ abstract class HybridObject: ExtendableHybridClass {
13
17
  /**
14
18
  * Get the memory size of the Kotlin instance (plus any external heap allocations),
15
19
  * in bytes.
@@ -41,7 +45,7 @@ abstract class HybridObject {
41
45
  * Must be called in the constructor of a subclass of `HybridObject`, to initialize the C++
42
46
  * `JHybridObject` with a subclass of it.
43
47
  */
44
- protected fun updateNative(hybridData: HybridData) {
48
+ override fun updateNative(hybridData: HybridData) {
45
49
  mHybridData = hybridData
46
50
  }
47
51
  }
@@ -0,0 +1,6 @@
1
+ package com.margelo.nitro
2
+
3
+ import com.facebook.react.bridge.ReactApplicationContext
4
+
5
+ abstract class NitroModulesSpec internal constructor(context: ReactApplicationContext) : NativeNitroModulesSpec(context) {
6
+ }
@@ -0,0 +1,9 @@
1
+ package com.margelo.nitro
2
+
3
+ import com.facebook.react.bridge.ReactApplicationContext
4
+ import com.facebook.react.bridge.ReactContextBaseJavaModule
5
+ import com.facebook.react.bridge.Promise
6
+
7
+ abstract class NitroModulesSpec internal constructor(context: ReactApplicationContext) : ReactContextBaseJavaModule(context) {
8
+ abstract fun install(): String?
9
+ }
@@ -173,7 +173,14 @@ private:
173
173
  // 1. Convert jsi::Value to jsi::Object
174
174
  #ifdef NITRO_DEBUG
175
175
  if (!value.isObject()) [[unlikely]] {
176
- throw jsi::JSError(runtime, "Cannot " + getHybridFuncDebugInfo<THybrid>(funcKind, funcName) + " - `this` is not bound!");
176
+ throw jsi::JSError(runtime, "Cannot " + getHybridFuncDebugInfo<THybrid>(funcKind, funcName) +
177
+ " - `this` is not bound! Suggestions:\n"
178
+ "- Did you accidentally destructure the `HybridObject`? (`const { " +
179
+ funcName +
180
+ " } = ...`)\n"
181
+ "- Did you call `dispose()` on the `HybridObject` before?"
182
+ "- Did you accidentally call `" +
183
+ funcName + "` on the prototype directly?");
177
184
  }
178
185
  #endif
179
186
  jsi::Object object = value.getObject(runtime);
@@ -183,10 +190,12 @@ private:
183
190
  if (!object.hasNativeState(runtime)) [[unlikely]] {
184
191
  throw jsi::JSError(runtime, "Cannot " + getHybridFuncDebugInfo<THybrid>(funcKind, funcName) +
185
192
  " - `this` does not have a NativeState! Suggestions:\n"
186
- "- Did you accidentally destructure the `HybridObject` and lose a reference to the original object?\n"
193
+ "- Did you accidentally destructure the `HybridObject`? (`const { " +
194
+ funcName +
195
+ " } = ...`)\n"
187
196
  "- Did you call `dispose()` on the `HybridObject` before?"
188
197
  "- Did you accidentally call `" +
189
- funcName + "` on the prototype directly?\n");
198
+ funcName + "` on the prototype directly?");
190
199
  }
191
200
  #endif
192
201
 
@@ -0,0 +1,55 @@
1
+ //
2
+ // HybridNitroModulesProxy.hpp
3
+ // NitroModules
4
+ //
5
+ // Created by Marc Rousavy on 05.10.24
6
+ //
7
+
8
+ #include "HybridNitroModulesProxy.hpp"
9
+ #include "HybridObjectRegistry.hpp"
10
+ #include "NitroDefines.hpp"
11
+
12
+ namespace margelo::nitro {
13
+
14
+ void HybridNitroModulesProxy::loadHybridMethods() {
15
+ HybridObject::loadHybridMethods();
16
+
17
+ registerHybrids(this, [](Prototype& prototype) {
18
+ prototype.registerHybridMethod("createHybridObject", &HybridNitroModulesProxy::createHybridObject);
19
+ prototype.registerHybridMethod("hasHybridObject", &HybridNitroModulesProxy::hasHybridObject);
20
+ prototype.registerHybridMethod("getAllHybridObjectNames", &HybridNitroModulesProxy::getAllHybridObjectNames);
21
+
22
+ prototype.registerHybridMethod("box", &HybridNitroModulesProxy::box);
23
+
24
+ prototype.registerHybridGetter("buildType", &HybridNitroModulesProxy::getBuildType);
25
+ });
26
+ }
27
+
28
+ // Hybrid Object Registry
29
+ std::shared_ptr<HybridObject> HybridNitroModulesProxy::createHybridObject(const std::string& name) {
30
+ return HybridObjectRegistry::createHybridObject(name);
31
+ }
32
+
33
+ bool HybridNitroModulesProxy::hasHybridObject(const std::string& name) {
34
+ return HybridObjectRegistry::hasHybridObject(name);
35
+ }
36
+
37
+ std::vector<std::string> HybridNitroModulesProxy::getAllHybridObjectNames() {
38
+ return HybridObjectRegistry::getAllHybridObjectNames();
39
+ }
40
+
41
+ // Helpers
42
+ std::shared_ptr<BoxedHybridObject> HybridNitroModulesProxy::box(const std::shared_ptr<HybridObject>& hybridObject) {
43
+ return std::make_shared<BoxedHybridObject>(hybridObject);
44
+ }
45
+
46
+ // Build Info
47
+ std::string HybridNitroModulesProxy::getBuildType() {
48
+ #ifdef NITRO_DEBUG
49
+ return "debug";
50
+ #else
51
+ return "release";
52
+ #endif
53
+ }
54
+
55
+ } // namespace margelo::nitro
@@ -0,0 +1,48 @@
1
+ //
2
+ // HybridNitroModulesProxy.hpp
3
+ // NitroModules
4
+ //
5
+ // Created by Marc Rousavy on 05.10.24
6
+ //
7
+
8
+ #pragma once
9
+
10
+ #include "BoxedHybridObject.hpp"
11
+ #include "HybridObject.hpp"
12
+ #include <memory>
13
+ #include <string>
14
+
15
+ namespace margelo::nitro {
16
+
17
+ /**
18
+ * Represents the entry point for all other HybridObjects.
19
+ * The flow is as following:
20
+ * 1. (optional) Install a Dispatcher in `jsi::Runtime` to use async/callbacks.
21
+ * 2. Create an instance of `HybridNitroModulesProxy`
22
+ * 3. Pass the object from `.toObject()` it to JS (either install in global, or return somehow)
23
+ * 4. From JS, you can access methods on this HybridObject to create all other HybridObjects.
24
+ */
25
+ class HybridNitroModulesProxy : public HybridObject {
26
+ public:
27
+ explicit HybridNitroModulesProxy() : HybridObject(TAG) {}
28
+
29
+ public:
30
+ void loadHybridMethods() override;
31
+
32
+ public:
33
+ // Hybrid Object Registry
34
+ std::shared_ptr<HybridObject> createHybridObject(const std::string& name);
35
+ bool hasHybridObject(const std::string& name);
36
+ std::vector<std::string> getAllHybridObjectNames();
37
+
38
+ // Helpers
39
+ std::shared_ptr<BoxedHybridObject> box(const std::shared_ptr<HybridObject>& hybridObject);
40
+
41
+ // Build Info
42
+ std::string getBuildType();
43
+
44
+ private:
45
+ static constexpr auto TAG = "NitroModulesProxy";
46
+ };
47
+
48
+ } // namespace margelo::nitro
@@ -0,0 +1,28 @@
1
+ //
2
+ // InstallNitro.cpp
3
+ // NitroModules
4
+ //
5
+ // Created by Marc Rousavy on 05.10.24
6
+ //
7
+
8
+ #include "InstallNitro.hpp"
9
+ #include "HybridNitroModulesProxy.hpp"
10
+
11
+ namespace margelo::nitro {
12
+
13
+ void install(jsi::Runtime& runtime, std::shared_ptr<Dispatcher> dispatcher) {
14
+ // Registers a Dispatcher for Nitro to call back into the JS Runtime.
15
+ // This allows creating Promises and calling back to JS.
16
+ Dispatcher::installRuntimeGlobalDispatcher(runtime, dispatcher);
17
+
18
+ // Installs NitroModulesProxy itself into the Runtime's global.
19
+ install(runtime);
20
+ }
21
+
22
+ void install(jsi::Runtime& runtime) {
23
+ // Installs global.NitroModulesProxy
24
+ auto proxy = std::make_shared<HybridNitroModulesProxy>();
25
+ runtime.global().setProperty(runtime, "NitroModulesProxy", proxy->toObject(runtime));
26
+ }
27
+
28
+ } // namespace margelo::nitro
@@ -0,0 +1,41 @@
1
+ //
2
+ // InstallNitro.hpp
3
+ // NitroModules
4
+ //
5
+ // Created by Marc Rousavy on 05.10.24
6
+ //
7
+
8
+ #pragma once
9
+
10
+ #include "Dispatcher.hpp"
11
+ #include <jsi/jsi.h>
12
+ #include <memory>
13
+
14
+ namespace margelo::nitro {
15
+
16
+ /**
17
+ * Installs Nitro into the given JS `runtime`.
18
+ * This will create `global.NitroModulesProxy`, Nitro's entry-point,
19
+ * which can be used to create all registered HybridObjects from JS.
20
+ *
21
+ * Also registers the given `dispatcher` which allows using callbacks,
22
+ * and async code (Promises).
23
+ * The `dispatcher` needs to implement `runAsync`/`runSync` to run
24
+ * methods on whatever Thread can safely access `runtime`.
25
+ * In a non-thread-safe Runtime, it needs to be a single Thread (e.g.
26
+ * React's `CallInvoker`), but in a thread-safe Runtime it might just be
27
+ * an implementation that runs the method directly.
28
+ */
29
+ void install(jsi::Runtime& runtime, std::shared_ptr<Dispatcher> dispatcher);
30
+
31
+ /**
32
+ * Installs Nitro into the given JS `runtime`.
33
+ * This will create `global.NitroModulesProxy`, Nitro's entry-point,
34
+ * which can be used to create all registered HybridObjects from JS.
35
+ *
36
+ * No `Dispatcher` will be installed, meaning Nitro can only use synchronous
37
+ * methods.
38
+ */
39
+ void install(jsi::Runtime& runtime);
40
+
41
+ } // namespace margelo::nitro
@@ -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 inline std::string invalidTypeErrorMessage(const std::string& typeDescription, const std::string& reason) {
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
  }
@@ -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"
@@ -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