react-native-nitro-modules 0.4.1 → 0.6.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 -1
- package/README.md +35 -16
- package/android/gradle.properties +5 -5
- package/android/src/main/cpp/JNIOnLoad.cpp +8 -0
- package/android/src/main/cpp/core/ByteBufferArrayBuffer.hpp +47 -0
- package/android/src/main/cpp/core/JAnyMap.hpp +193 -0
- package/android/src/main/cpp/core/JAnyValue.hpp +191 -0
- package/android/src/main/cpp/core/JArrayBuffer.hpp +119 -0
- package/android/src/main/cpp/core/JHybridObject.hpp +11 -4
- package/android/src/main/cpp/core/JPromise.hpp +88 -0
- package/android/src/main/cpp/platform/NitroLogger.cpp +36 -0
- package/android/src/main/cpp/registry/JHybridObjectInitializer.hpp +1 -1
- package/android/src/main/cpp/registry/JHybridObjectRegistry.cpp +1 -1
- package/android/src/main/cpp/registry/JHybridObjectRegistry.hpp +1 -1
- package/android/src/main/cpp/utils/{JNISharedPtr.h → JNISharedPtr.hpp} +13 -1
- package/android/src/main/java/com/margelo/nitro/JNIOnLoad.java +27 -0
- package/android/src/main/java/com/margelo/nitro/NitroModulesPackage.java +1 -9
- package/android/src/main/java/com/margelo/nitro/core/AnyMap.kt +61 -0
- package/android/src/main/java/com/margelo/nitro/core/AnyValue.kt +153 -0
- package/android/src/main/java/com/margelo/nitro/core/ArrayBuffer.kt +84 -0
- package/android/src/main/java/com/margelo/nitro/{HybridObject.kt → core/HybridObject.kt} +12 -15
- package/android/src/main/java/com/margelo/nitro/{HybridObjectInitializer.java → core/HybridObjectInitializer.java} +1 -1
- package/android/src/main/java/com/margelo/nitro/{HybridObjectRegistry.java → core/HybridObjectRegistry.java} +6 -4
- package/android/src/main/java/com/margelo/nitro/core/Promise.kt +115 -0
- package/cpp/core/AnyMap.hpp +2 -2
- package/cpp/core/ArrayBuffer.cpp +5 -5
- package/cpp/core/ArrayBuffer.hpp +12 -7
- package/cpp/core/HybridFunction.hpp +119 -45
- package/cpp/core/HybridObject.cpp +17 -6
- package/cpp/core/HybridObject.hpp +32 -8
- package/cpp/jsi/JSICache.cpp +5 -5
- package/cpp/jsi/JSICache.hpp +1 -3
- package/cpp/jsi/JSIConverter+AnyMap.hpp +2 -2
- package/cpp/jsi/JSIConverter+ArrayBuffer.hpp +2 -2
- package/cpp/jsi/JSIConverter+Function.hpp +7 -6
- package/cpp/jsi/JSIConverter+HybridObject.hpp +6 -5
- package/cpp/jsi/JSIConverter+Optional.hpp +1 -1
- package/cpp/jsi/JSIConverter+Promise.hpp +6 -4
- package/cpp/jsi/JSIConverter+Tuple.hpp +1 -1
- package/cpp/jsi/JSIConverter+UnorderedMap.hpp +1 -1
- package/cpp/jsi/JSIConverter+Variant.hpp +1 -3
- package/cpp/jsi/JSIConverter+Vector.hpp +1 -1
- package/cpp/jsi/JSIConverter.hpp +11 -11
- package/cpp/jsi/JSPromise.cpp +2 -2
- package/cpp/platform/NitroLogger.hpp +67 -0
- package/cpp/prototype/HybridObjectPrototype.cpp +2 -2
- package/cpp/prototype/Prototype.hpp +43 -22
- package/cpp/registry/HybridObjectRegistry.cpp +4 -4
- package/cpp/threading/Dispatcher.cpp +4 -3
- package/cpp/threading/ThreadPool.cpp +2 -2
- package/cpp/turbomodule/NativeNitroModules.cpp +26 -8
- package/cpp/turbomodule/NativeNitroModules.h +1 -0
- package/cpp/turbomodule/NativeNitroModules.hpp +2 -0
- package/cpp/utils/TypeInfo.hpp +14 -0
- package/ios/core/AnyMapHolder.hpp +91 -0
- package/ios/core/AnyMapHolder.swift +316 -0
- package/ios/core/ArrayBufferHolder.hpp +16 -5
- package/ios/core/{ArrayBuffer.swift → ArrayBufferHolder.swift} +15 -17
- package/ios/core/HybridContext.hpp +3 -3
- package/ios/core/Promise.swift +182 -0
- package/ios/core/PromiseHolder.hpp +86 -0
- package/ios/platform/NitroLogger.mm +36 -0
- package/ios/platform/ThreadUtils.cpp +1 -1
- package/ios/turbomodule/NitroModuleOnLoad.mm +6 -0
- package/ios/utils/SwiftClosure.hpp +63 -0
- package/ios/utils/SwiftClosure.swift +58 -0
- package/lib/AnyMap.d.ts +3 -0
- package/lib/HybridObject.d.ts +15 -0
- package/lib/NativeNitroModules.d.ts +2 -0
- package/lib/NitroModules.d.ts +18 -0
- package/lib/NitroModules.js +24 -0
- package/lib/commonjs/NativeNitroModules.js.map +1 -1
- package/lib/commonjs/NitroModules.js +24 -0
- package/lib/commonjs/NitroModules.js.map +1 -1
- package/lib/commonjs/package.json +1 -0
- package/lib/module/AnyMap.js +1 -1
- package/lib/module/HybridObject.js +1 -1
- package/lib/module/ModuleNotFoundError.js +2 -0
- package/lib/module/ModuleNotFoundError.js.map +1 -1
- package/lib/module/NativeNitroModules.js +2 -0
- package/lib/module/NativeNitroModules.js.map +1 -1
- package/lib/module/NativeNitroModules.web.js +2 -0
- package/lib/module/NativeNitroModules.web.js.map +1 -1
- package/lib/module/NitroModules.js +26 -0
- package/lib/module/NitroModules.js.map +1 -1
- package/lib/module/index.js +2 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/package.json +1 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/typescript/AnyMap.d.ts +20 -0
- package/lib/typescript/AnyMap.d.ts.map +1 -1
- package/lib/typescript/HybridObject.d.ts +98 -0
- package/lib/typescript/HybridObject.d.ts.map +1 -1
- package/lib/typescript/NativeNitroModules.d.ts +2 -0
- package/lib/typescript/NativeNitroModules.d.ts.map +1 -1
- package/lib/typescript/NitroModules.d.ts +18 -0
- package/lib/typescript/NitroModules.d.ts.map +1 -1
- package/package.json +13 -12
- package/src/AnyMap.ts +3 -0
- package/src/HybridObject.ts +15 -0
- package/src/NativeNitroModules.ts +5 -0
- package/src/NitroModules.ts +24 -0
- package/android/src/main/cpp/core/JHybridObject.cpp +0 -8
- package/cpp/templates/IsInPack.hpp +0 -21
- package/cpp/utils/NitroLogger.hpp +0 -58
- package/ios/core/ClosureWrapper.swift +0 -25
- package/ios/core/HybridContext.cpp +0 -8
- package/ios/core/Promise.cpp +0 -10
- package/ios/core/Promise.hpp +0 -43
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
//
|
|
2
|
+
// JArrayBuffer.hpp
|
|
3
|
+
// react-native-nitro
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 14.07.24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#include "ArrayBuffer.hpp"
|
|
11
|
+
#include "ByteBufferArrayBuffer.hpp"
|
|
12
|
+
#include <fbjni/ByteBuffer.h>
|
|
13
|
+
#include <fbjni/fbjni.h>
|
|
14
|
+
#include <functional>
|
|
15
|
+
#include <utility>
|
|
16
|
+
|
|
17
|
+
namespace margelo::nitro {
|
|
18
|
+
|
|
19
|
+
using namespace facebook;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Represents a `ArrayBuffer` that can either hold a `ByteBuffer` (owning),
|
|
23
|
+
* or unknown/foreign memory, potentially from JS (non-owning).
|
|
24
|
+
*/
|
|
25
|
+
class JArrayBuffer final : public jni::HybridClass<JArrayBuffer> {
|
|
26
|
+
public:
|
|
27
|
+
static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/core/ArrayBuffer;";
|
|
28
|
+
|
|
29
|
+
public:
|
|
30
|
+
/**
|
|
31
|
+
* Create a new `JArrayBuffer` that wraps the given ArrayBuffer.
|
|
32
|
+
*/
|
|
33
|
+
static jni::local_ref<JArrayBuffer::javaobject> wrap(const std::shared_ptr<ArrayBuffer>& arrayBuffer) {
|
|
34
|
+
return newObjectCxxArgs(arrayBuffer);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
public:
|
|
38
|
+
/**
|
|
39
|
+
* Create a new `JArrayBuffer` that wraps the given `ByteBuffer` from Java.
|
|
40
|
+
*/
|
|
41
|
+
static jni::local_ref<JArrayBuffer::jhybriddata> initHybrid(jni::alias_ref<jhybridobject> jThis,
|
|
42
|
+
jni::alias_ref<jni::JByteBuffer> buffer) {
|
|
43
|
+
return makeCxxInstance(buffer);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public:
|
|
47
|
+
/**
|
|
48
|
+
* Get whether the `ArrayBuffer` is holding data from a `ByteBuffer`.
|
|
49
|
+
*/
|
|
50
|
+
bool getIsByteBuffer() {
|
|
51
|
+
auto byteBufferArrayBuffer = std::dynamic_pointer_cast<ByteBufferArrayBuffer>(_arrayBuffer);
|
|
52
|
+
return byteBufferArrayBuffer != nullptr;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get whether the `ArrayBuffer` is owning the data and can safely hold onto it longer.
|
|
57
|
+
*/
|
|
58
|
+
bool getIsOwner() {
|
|
59
|
+
return _arrayBuffer->isOwner();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Get the `ArrayBuffer`'s data as a `ByteBuffer`.
|
|
64
|
+
*
|
|
65
|
+
* - If the `ArrayBuffer` was created from a `ByteBuffer` (`isByteBuffer()`), this returns
|
|
66
|
+
* a reference to the original `ByteBuffer`, which is safe to be kept in memory for longer.
|
|
67
|
+
* - If the `ArrayBuffer` was created elsewhere (either in JS, or in C++), it does not have a
|
|
68
|
+
* `ByteBuffer`. In this case, `getBuffer()` will **copy** the data into a new `ByteBuffer` if
|
|
69
|
+
* `copyIfNeeded` is `true`, and **wrap** the data into a new `ByteBuffer` if `copyIfNeeded` is false.
|
|
70
|
+
*/
|
|
71
|
+
jni::alias_ref<jni::JByteBuffer> getByteBuffer(bool copyIfNeeded) {
|
|
72
|
+
auto byteBufferArrayBuffer = std::dynamic_pointer_cast<ByteBufferArrayBuffer>(_arrayBuffer);
|
|
73
|
+
if (byteBufferArrayBuffer != nullptr) {
|
|
74
|
+
// It is a `ByteBufferArrayBuffer`, which has a `ByteBuffer` underneath!
|
|
75
|
+
return byteBufferArrayBuffer->getBuffer();
|
|
76
|
+
} else {
|
|
77
|
+
// It is a different kind of `ArrayBuffer`, we need to copy or wrap the data.
|
|
78
|
+
size_t size = _arrayBuffer->size();
|
|
79
|
+
if (copyIfNeeded) {
|
|
80
|
+
auto buffer = jni::JByteBuffer::allocateDirect(size);
|
|
81
|
+
buffer->order(jni::JByteOrder::bigEndian());
|
|
82
|
+
memcpy(buffer->getDirectAddress(), _arrayBuffer->data(), size);
|
|
83
|
+
return buffer;
|
|
84
|
+
} else {
|
|
85
|
+
auto buffer = jni::JByteBuffer::wrapBytes(_arrayBuffer->data(), size);
|
|
86
|
+
buffer->order(jni::JByteOrder::bigEndian());
|
|
87
|
+
return buffer;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public:
|
|
93
|
+
/**
|
|
94
|
+
* Get the underlying `ArrayBuffer`.
|
|
95
|
+
*/
|
|
96
|
+
std::shared_ptr<ArrayBuffer> getArrayBuffer() const {
|
|
97
|
+
return _arrayBuffer;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
private:
|
|
101
|
+
JArrayBuffer(const std::shared_ptr<ArrayBuffer>& arrayBuffer) : _arrayBuffer(arrayBuffer) {}
|
|
102
|
+
JArrayBuffer(jni::alias_ref<jni::JByteBuffer> byteBuffer) {
|
|
103
|
+
_arrayBuffer = std::make_shared<ByteBufferArrayBuffer>(byteBuffer);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
private:
|
|
107
|
+
friend HybridBase;
|
|
108
|
+
using HybridBase::HybridBase;
|
|
109
|
+
std::shared_ptr<ArrayBuffer> _arrayBuffer;
|
|
110
|
+
|
|
111
|
+
public:
|
|
112
|
+
static void registerNatives() {
|
|
113
|
+
registerHybrid(
|
|
114
|
+
{makeNativeMethod("initHybrid", JArrayBuffer::initHybrid), makeNativeMethod("getByteBuffer", JArrayBuffer::getByteBuffer),
|
|
115
|
+
makeNativeMethod("getIsByteBuffer", JArrayBuffer::getIsByteBuffer), makeNativeMethod("getIsOwner", JArrayBuffer::getIsOwner)});
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
} // namespace margelo::nitro
|
|
@@ -14,12 +14,19 @@ namespace margelo::nitro {
|
|
|
14
14
|
|
|
15
15
|
using namespace facebook;
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Represents the Java `HybridObject` instance.
|
|
19
|
+
* HybridData is passed up from inherited members, so this acts like a base class
|
|
20
|
+
* and has to be inherited as "virtual" in C++ to properly avoid creating multiple `HybridObject` instances.
|
|
21
|
+
*/
|
|
22
|
+
class JHybridObject : public jni::HybridClass<JHybridObject>, public virtual HybridObject {
|
|
18
23
|
public:
|
|
19
|
-
static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/HybridObject;";
|
|
24
|
+
static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/core/HybridObject;";
|
|
20
25
|
|
|
21
|
-
|
|
22
|
-
|
|
26
|
+
~JHybridObject() override = default;
|
|
27
|
+
|
|
28
|
+
private:
|
|
29
|
+
friend HybridBase;
|
|
23
30
|
};
|
|
24
31
|
|
|
25
32
|
} // namespace margelo::nitro
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
//
|
|
2
|
+
// JPromise.hpp
|
|
3
|
+
// react-native-nitro
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 14.07.24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#include <fbjni/fbjni.h>
|
|
11
|
+
|
|
12
|
+
namespace margelo::nitro {
|
|
13
|
+
|
|
14
|
+
using namespace facebook;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Represents a Promise implemented in Java.
|
|
18
|
+
*/
|
|
19
|
+
class JPromise final : public jni::HybridClass<JPromise> {
|
|
20
|
+
public:
|
|
21
|
+
static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/core/Promise;";
|
|
22
|
+
using OnResolvedFunc = std::function<void(jni::alias_ref<jni::JObject>)>;
|
|
23
|
+
using OnRejectedFunc = std::function<void(jni::alias_ref<jni::JString>)>;
|
|
24
|
+
|
|
25
|
+
public:
|
|
26
|
+
/**
|
|
27
|
+
* Create a new, still unresolved `JPromise` from Java.
|
|
28
|
+
*/
|
|
29
|
+
static jni::local_ref<JPromise::jhybriddata> initHybrid(jni::alias_ref<jhybridobject>) {
|
|
30
|
+
return makeCxxInstance();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public:
|
|
34
|
+
void resolve(jni::alias_ref<jni::JObject> result) {
|
|
35
|
+
_result = jni::make_global(result);
|
|
36
|
+
for (const auto& onResolved : _onResolvedListeners) {
|
|
37
|
+
onResolved(_result);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
void reject(jni::alias_ref<jni::JString> error) {
|
|
41
|
+
_error = jni::make_global(error);
|
|
42
|
+
for (const auto& onRejected : _onRejectedListeners) {
|
|
43
|
+
onRejected(_error);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public:
|
|
48
|
+
void addOnResolvedListener(OnResolvedFunc&& onResolved) {
|
|
49
|
+
if (_result != nullptr) {
|
|
50
|
+
// Promise is already resolved! Call the callback immediately
|
|
51
|
+
onResolved(_result);
|
|
52
|
+
} else {
|
|
53
|
+
// Promise is not yet resolved, put the listener in our queue.
|
|
54
|
+
_onResolvedListeners.push_back(std::move(onResolved));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
void addOnRejectedListener(OnRejectedFunc&& onRejected) {
|
|
58
|
+
if (_error != nullptr) {
|
|
59
|
+
// Promise is already rejected! Call the callback immediately
|
|
60
|
+
onRejected(_error);
|
|
61
|
+
} else {
|
|
62
|
+
// Promise is not yet rejected, put the listener in our queue.
|
|
63
|
+
_onRejectedListeners.push_back(std::move(onRejected));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private:
|
|
68
|
+
JPromise() {}
|
|
69
|
+
|
|
70
|
+
private:
|
|
71
|
+
friend HybridBase;
|
|
72
|
+
using HybridBase::HybridBase;
|
|
73
|
+
jni::global_ref<jni::JObject> _result;
|
|
74
|
+
jni::global_ref<jni::JString> _error;
|
|
75
|
+
std::vector<OnResolvedFunc> _onResolvedListeners;
|
|
76
|
+
std::vector<OnRejectedFunc> _onRejectedListeners;
|
|
77
|
+
|
|
78
|
+
public:
|
|
79
|
+
static void registerNatives() {
|
|
80
|
+
registerHybrid({
|
|
81
|
+
makeNativeMethod("initHybrid", JPromise::initHybrid),
|
|
82
|
+
makeNativeMethod("nativeResolve", JPromise::resolve),
|
|
83
|
+
makeNativeMethod("nativeReject", JPromise::reject),
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
} // namespace margelo::nitro
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
//
|
|
2
|
+
// NitroLogger.cpp
|
|
3
|
+
// react-native-nitro
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 14.07.24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#include "NitroLogger.hpp"
|
|
9
|
+
#include <android/log.h>
|
|
10
|
+
|
|
11
|
+
namespace margelo::nitro {
|
|
12
|
+
|
|
13
|
+
int levelToAndroidLevel(LogLevel level) {
|
|
14
|
+
switch (level) {
|
|
15
|
+
case LogLevel::Debug:
|
|
16
|
+
return ANDROID_LOG_DEBUG;
|
|
17
|
+
case LogLevel::Info:
|
|
18
|
+
return ANDROID_LOG_INFO;
|
|
19
|
+
case LogLevel::Warning:
|
|
20
|
+
return ANDROID_LOG_WARN;
|
|
21
|
+
case LogLevel::Error:
|
|
22
|
+
return ANDROID_LOG_ERROR;
|
|
23
|
+
default:
|
|
24
|
+
throw std::runtime_error("Invalid LogLevel!");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
void Logger::nativeLog(LogLevel level, const char* tag, const std::string& message) {
|
|
29
|
+
#ifndef NDEBUG
|
|
30
|
+
int logLevel = levelToAndroidLevel(level);
|
|
31
|
+
std::string combinedTag = "Nitro." + std::string(tag);
|
|
32
|
+
__android_log_print(logLevel, combinedTag.c_str(), "%s", message.c_str());
|
|
33
|
+
#endif
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
} // namespace margelo::nitro
|
|
@@ -17,7 +17,7 @@ using namespace facebook;
|
|
|
17
17
|
|
|
18
18
|
struct JHybridObjectRegistry : public jni::JavaClass<JHybridObjectRegistry> {
|
|
19
19
|
public:
|
|
20
|
-
static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/HybridObjectRegistry;";
|
|
20
|
+
static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/core/HybridObjectRegistry;";
|
|
21
21
|
|
|
22
22
|
public:
|
|
23
23
|
static void registerHybridObjectConstructor(jni::alias_ref<jni::JClass> clazz, std::string hybridObjectName,
|
|
@@ -26,8 +26,20 @@ private:
|
|
|
26
26
|
};
|
|
27
27
|
|
|
28
28
|
class JNISharedPtr {
|
|
29
|
+
private:
|
|
30
|
+
template <typename T, template <typename, typename...> class Base>
|
|
31
|
+
struct is_base_template_of {
|
|
32
|
+
template <typename U>
|
|
33
|
+
static std::true_type test(Base<U>*) {}
|
|
34
|
+
|
|
35
|
+
template <typename>
|
|
36
|
+
static std::false_type test(...) {}
|
|
37
|
+
|
|
38
|
+
static constexpr bool value = decltype(test<T>(nullptr))::value;
|
|
39
|
+
};
|
|
40
|
+
|
|
29
41
|
public:
|
|
30
|
-
template <typename T, typename std::enable_if<
|
|
42
|
+
template <typename T, typename std::enable_if<is_base_template_of<T, jni::HybridClass>::value, int>::type = 0>
|
|
31
43
|
static std::shared_ptr<T> make_shared_from_jni(jni::global_ref<typename T::javaobject> ref) {
|
|
32
44
|
return std::shared_ptr<T>(ref->cthis(), GlobalRefDeleter<T>{ref});
|
|
33
45
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
package com.margelo.nitro;
|
|
2
|
+
|
|
3
|
+
import android.util.Log;
|
|
4
|
+
|
|
5
|
+
public class JNIOnLoad {
|
|
6
|
+
private static final String TAG = "NitroModules";
|
|
7
|
+
private static boolean isInitialized = false;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Initializes the C++ (JNI) part of Nitro Modules.
|
|
11
|
+
* This function should be called in a `static` block everytime the Java part
|
|
12
|
+
* interacts with the native C++ (JNI) part of Nitro Modules.
|
|
13
|
+
* If Native Nitro is already initialized, this function will do nothing.
|
|
14
|
+
*/
|
|
15
|
+
public synchronized static void initializeNativeNitro() {
|
|
16
|
+
if (isInitialized) return;
|
|
17
|
+
try {
|
|
18
|
+
Log.i(TAG, "Loading NitroModules C++ library...");
|
|
19
|
+
System.loadLibrary("NitroModules");
|
|
20
|
+
Log.i(TAG, "Successfully loaded NitroModules C++ library!");
|
|
21
|
+
isInitialized = true;
|
|
22
|
+
} catch (Throwable e) {
|
|
23
|
+
Log.e(TAG, "Failed to load NitroModules C++ library! Is it properly installed and linked?", e);
|
|
24
|
+
throw e;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -11,16 +11,8 @@ import com.facebook.react.TurboReactPackage;
|
|
|
11
11
|
import java.util.HashMap;
|
|
12
12
|
|
|
13
13
|
public class NitroModulesPackage extends TurboReactPackage {
|
|
14
|
-
private static final String TAG = "NitroModules";
|
|
15
14
|
static {
|
|
16
|
-
|
|
17
|
-
Log.i(TAG, "Loading NitroModules C++ library...");
|
|
18
|
-
System.loadLibrary("NitroModules");
|
|
19
|
-
Log.i(TAG, "Successfully loaded NitroModules C++ library!");
|
|
20
|
-
} catch (Throwable e) {
|
|
21
|
-
Log.e(TAG, "Failed to load NitroModules C++ library! Is it properly installed and linked?", e);
|
|
22
|
-
throw e;
|
|
23
|
-
}
|
|
15
|
+
JNIOnLoad.initializeNativeNitro();
|
|
24
16
|
}
|
|
25
17
|
|
|
26
18
|
@Nullable
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
package com.margelo.nitro.core
|
|
2
|
+
|
|
3
|
+
import androidx.annotation.Keep
|
|
4
|
+
import com.facebook.jni.HybridData
|
|
5
|
+
import com.facebook.proguard.annotations.DoNotStrip
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Represents an untyped map of string keys with associated values.
|
|
9
|
+
* This is like a JS [`object`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object).
|
|
10
|
+
*/
|
|
11
|
+
@Suppress("KotlinJniMissingFunction")
|
|
12
|
+
@Keep
|
|
13
|
+
@DoNotStrip
|
|
14
|
+
class AnyMap {
|
|
15
|
+
private val mHybridData: HybridData
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Create a new empty `AnyMap`.
|
|
19
|
+
*/
|
|
20
|
+
constructor() {
|
|
21
|
+
mHybridData = initHybrid()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Create a new `AnyMap` from C++, which potentially already holds data.
|
|
26
|
+
*/
|
|
27
|
+
@Suppress("unused")
|
|
28
|
+
private constructor(hybridData: HybridData) {
|
|
29
|
+
mHybridData = hybridData
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
external fun contains(key: String): Boolean
|
|
34
|
+
external fun remove(key: String)
|
|
35
|
+
external fun clear()
|
|
36
|
+
|
|
37
|
+
external fun isNull(key: String): Boolean
|
|
38
|
+
external fun isDouble(key: String): Boolean
|
|
39
|
+
external fun isBoolean(key: String): Boolean
|
|
40
|
+
external fun isBigInt(key: String): Boolean
|
|
41
|
+
external fun isString(key: String): Boolean
|
|
42
|
+
external fun isArray(key: String): Boolean
|
|
43
|
+
external fun isObject(key: String): Boolean
|
|
44
|
+
|
|
45
|
+
external fun getDouble(key: String): Double
|
|
46
|
+
external fun getBoolean(key: String): Boolean
|
|
47
|
+
external fun getBigInt(key: String): Long
|
|
48
|
+
external fun getString(key: String): String
|
|
49
|
+
external fun getAnyArray(key: String): AnyArray
|
|
50
|
+
external fun getAnyObject(key: String): AnyObject
|
|
51
|
+
|
|
52
|
+
external fun setNull(key: String)
|
|
53
|
+
external fun setDouble(key: String, value: Double)
|
|
54
|
+
external fun setBoolean(key: String, value: Boolean)
|
|
55
|
+
external fun setBigInt(key: String, value: Long)
|
|
56
|
+
external fun setString(key: String, value: String)
|
|
57
|
+
external fun setAnyArray(key: String, value: AnyArray)
|
|
58
|
+
external fun setAnyObject(key: String, value: AnyObject)
|
|
59
|
+
|
|
60
|
+
private external fun initHybrid(): HybridData
|
|
61
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
package com.margelo.nitro.core
|
|
2
|
+
|
|
3
|
+
import androidx.annotation.Keep
|
|
4
|
+
import com.facebook.jni.HybridData
|
|
5
|
+
import com.facebook.proguard.annotations.DoNotStrip
|
|
6
|
+
|
|
7
|
+
typealias AnyArray = Array<AnyValue>
|
|
8
|
+
typealias AnyObject = Map<String, AnyValue>
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Represents a value that can be any of the following types:
|
|
12
|
+
* - `null`
|
|
13
|
+
* - [Double]
|
|
14
|
+
* - [Boolean]
|
|
15
|
+
* - [Long]
|
|
16
|
+
* - [String]
|
|
17
|
+
* - [AnyArray] ([Array]`<AnyValue>`)
|
|
18
|
+
* - [AnyObject] ([Map]`<String, AnyValue>`)
|
|
19
|
+
*/
|
|
20
|
+
@Suppress("KotlinJniMissingFunction")
|
|
21
|
+
@Keep
|
|
22
|
+
@DoNotStrip
|
|
23
|
+
class AnyValue {
|
|
24
|
+
private val mHybridData: HybridData
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Create a new [AnyValue] that holds `null`.
|
|
28
|
+
*/
|
|
29
|
+
constructor() {
|
|
30
|
+
mHybridData = initHybrid()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Create a new [AnyValue] that holds the given [Double]
|
|
35
|
+
*/
|
|
36
|
+
constructor(value: Double) {
|
|
37
|
+
mHybridData = initHybrid(value)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Create a new [AnyValue] that holds the given [Boolean]
|
|
42
|
+
*/
|
|
43
|
+
constructor(value: Boolean) {
|
|
44
|
+
mHybridData = initHybrid(value)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Create a new [AnyValue] that holds the given [Long]
|
|
49
|
+
*/
|
|
50
|
+
constructor(value: Long) {
|
|
51
|
+
mHybridData = initHybrid(value)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Create a new [AnyValue] that holds the given [String]
|
|
56
|
+
*/
|
|
57
|
+
constructor(value: String) {
|
|
58
|
+
mHybridData = initHybrid(value)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Create a new [AnyValue] that holds the given [AnyArray]
|
|
63
|
+
*/
|
|
64
|
+
constructor(value: AnyArray) {
|
|
65
|
+
mHybridData = initHybrid(value)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Create a new [AnyValue] that holds the given [AnyObject]
|
|
70
|
+
*/
|
|
71
|
+
constructor(value: AnyObject) {
|
|
72
|
+
mHybridData = initHybrid(value)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Gets whether this [AnyValue] instance is holding a `null`.
|
|
77
|
+
*/
|
|
78
|
+
external fun isNull(): Boolean
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Gets whether this [AnyValue] instance is holding a [Double] value.
|
|
82
|
+
*/
|
|
83
|
+
external fun isDouble(): Boolean
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Gets whether this [AnyValue] instance is holding a [Boolean] value.
|
|
87
|
+
*/
|
|
88
|
+
external fun isBoolean(): Boolean
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Gets whether this [AnyValue] instance is holding a [Long] value.
|
|
92
|
+
*/
|
|
93
|
+
external fun isBigInt(): Boolean
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Gets whether this [AnyValue] instance is holding a [String] value.
|
|
97
|
+
*/
|
|
98
|
+
external fun isString(): Boolean
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Gets whether this [AnyValue] instance is holding an [AnyArray] value.
|
|
102
|
+
*/
|
|
103
|
+
external fun isAnyArray(): Boolean
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Gets whether this [AnyValue] instance is holding an [AnyObject] value.
|
|
107
|
+
*/
|
|
108
|
+
external fun isAnyObject(): Boolean
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Get the [Double] value this [AnyValue] is holding.
|
|
112
|
+
* @throws Error if this [AnyValue] is not holding a [Double] (see [isDouble]`()`)
|
|
113
|
+
*/
|
|
114
|
+
external fun asDouble(): Double
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Get the [Boolean] value this [AnyValue] is holding.
|
|
118
|
+
* @throws Error if this [AnyValue] is not holding a [Boolean] (see [isBoolean]`()`)
|
|
119
|
+
*/
|
|
120
|
+
external fun asBoolean(): Boolean
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Get the [Long] value this [AnyValue] is holding.
|
|
124
|
+
* @throws Error if this [AnyValue] is not holding a [Long] (see [isLong]`()`)
|
|
125
|
+
*/
|
|
126
|
+
external fun asBigInt(): Long
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Get the [String] value this [AnyValue] is holding.
|
|
130
|
+
* @throws Error if this [AnyValue] is not holding a [String] (see [isString]`()`)
|
|
131
|
+
*/
|
|
132
|
+
external fun asString(): String
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Get the [AnyArray] value this [AnyValue] is holding.
|
|
136
|
+
* @throws Error if this [AnyValue] is not holding an [AnyArray] (see [isAnyArray]`()`)
|
|
137
|
+
*/
|
|
138
|
+
external fun asAnyArray(): AnyArray
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Get the [AnyObject] value this [AnyValue] is holding.
|
|
142
|
+
* @throws Error if this [AnyValue] is not holding an [AnyObject] (see [isAnyObject]`()`)
|
|
143
|
+
*/
|
|
144
|
+
external fun asAnyObject(): AnyObject
|
|
145
|
+
|
|
146
|
+
private external fun initHybrid(): HybridData
|
|
147
|
+
private external fun initHybrid(value: Double): HybridData
|
|
148
|
+
private external fun initHybrid(value: Boolean): HybridData
|
|
149
|
+
private external fun initHybrid(value: Long): HybridData
|
|
150
|
+
private external fun initHybrid(value: String): HybridData
|
|
151
|
+
private external fun initHybrid(value: AnyArray): HybridData
|
|
152
|
+
private external fun initHybrid(value: AnyObject): HybridData
|
|
153
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
package com.margelo.nitro.core
|
|
2
|
+
|
|
3
|
+
import androidx.annotation.Keep
|
|
4
|
+
import com.facebook.jni.HybridData
|
|
5
|
+
import com.facebook.proguard.annotations.DoNotStrip
|
|
6
|
+
import java.nio.ByteBuffer
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* An ArrayBuffer instance shared between native (Kotlin/C++) and JS.
|
|
10
|
+
*
|
|
11
|
+
* A `ByteBuffer` will be used as the underlying `ArrayBuffer`'s data,
|
|
12
|
+
* which has to remain valid for as long as the `ArrayBuffer` is alive.
|
|
13
|
+
*/
|
|
14
|
+
@Suppress("KotlinJniMissingFunction")
|
|
15
|
+
@Keep
|
|
16
|
+
@DoNotStrip
|
|
17
|
+
class ArrayBuffer {
|
|
18
|
+
/**
|
|
19
|
+
* Holds the native C++ instance of the `ArrayBuffer`.
|
|
20
|
+
*/
|
|
21
|
+
private val mHybridData: HybridData
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Whether this `ArrayBuffer` is an **owning-**, or a **non-owning-** `ArrayBuffer`.
|
|
25
|
+
* - **Owning** ArrayBuffers can safely be held in memory for longer, and accessed at any point.
|
|
26
|
+
* - **Non-owning** ArrayBuffers can not be held in memory for longer, and can only be safely
|
|
27
|
+
* accessed within the synchronous function's scope (aka on the JS Thread). Once you switch Threads,
|
|
28
|
+
* data access is not safe anymore. If you need to access data longer, copy the data.
|
|
29
|
+
*/
|
|
30
|
+
val isOwner: Boolean
|
|
31
|
+
get() = getIsOwner()
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Whether this `ArrayBuffer` is holding a `ByteBuffer`, or not.
|
|
35
|
+
* - If the `ArrayBuffer` holds a `ByteBuffer`, `getBuffer(false)` can safely be called to
|
|
36
|
+
* get shared access to the underlying data, without performing any copies.
|
|
37
|
+
* - If the `ArrayBuffer` doesn't hold a `ByteBuffer`, it can still be accessed via `getBuffer(false)`,
|
|
38
|
+
* but the returned `ByteBuffer` is only valid as long as it's parent `ArrayBuffer` is alive.
|
|
39
|
+
*/
|
|
40
|
+
val isByteBuffer: Boolean
|
|
41
|
+
get() = getIsByteBuffer()
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Get a `ByteBuffer` that holds- or wraps- the underlying data.
|
|
45
|
+
* - If this `ArrayBuffer` has been created from Kotlin/Java, it is already holding a
|
|
46
|
+
* `ByteBuffer` (`isByteBuffer == true`). In this case, the returned buffer is safe to access,
|
|
47
|
+
* even after the `ArrayBuffer` has already been destroyed in JS.
|
|
48
|
+
* - If this `ArrayBuffer` has been created elsewhere (C++/JS), it is not holding a
|
|
49
|
+
* `ByteBuffer` (`isByteBuffer == false`). In this case, the returned buffer will either be a copy
|
|
50
|
+
* of the data (`copyIfNeeded == true`), or just wrapping the data (`copyIfNeeded == false`).
|
|
51
|
+
*
|
|
52
|
+
* @param copyIfNeeded If this `ArrayBuffer` is not holding a `ByteBuffer` (`isByteBuffer == false`),
|
|
53
|
+
* the foreign data needs to be either _wrapped_, or _copied_ to be represented as a `ByteBuffer`.
|
|
54
|
+
* This flag controls that behaviour.
|
|
55
|
+
*/
|
|
56
|
+
fun getBuffer(copyIfNeeded: Boolean): ByteBuffer {
|
|
57
|
+
return getByteBuffer(copyIfNeeded)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Create a new **owning-** `ArrayBuffer` that holds the given `ByteBuffer`.
|
|
62
|
+
* The `ByteBuffer` needs to remain valid for as long as the `ArrayBuffer` is alive.
|
|
63
|
+
*/
|
|
64
|
+
constructor(byteBuffer: ByteBuffer) {
|
|
65
|
+
if (!byteBuffer.isDirect) {
|
|
66
|
+
throw Error("ArrayBuffers can only be created from direct ByteBuffers, " +
|
|
67
|
+
"and the given ByteBuffer is not direct!")
|
|
68
|
+
}
|
|
69
|
+
mHybridData = initHybrid(byteBuffer)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Create a new **non-owning-** `ArrayBuffer` that holds foreign data, potentially coming from JS.
|
|
74
|
+
*/
|
|
75
|
+
@Suppress("unused")
|
|
76
|
+
private constructor(hybridData: HybridData) {
|
|
77
|
+
mHybridData = hybridData
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private external fun getByteBuffer(copyIfNeeded: Boolean): ByteBuffer
|
|
81
|
+
private external fun getIsOwner(): Boolean
|
|
82
|
+
private external fun getIsByteBuffer(): Boolean
|
|
83
|
+
private external fun initHybrid(buffer: ByteBuffer): HybridData
|
|
84
|
+
}
|