expo-modules-core 0.9.2 → 0.11.1
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/CHANGELOG.md +33 -3
- package/README.md +3 -3
- package/android/CMakeLists.txt +163 -0
- package/android/build.gradle +343 -5
- package/android/src/main/cpp/CachedReferencesRegistry.cpp +65 -0
- package/android/src/main/cpp/CachedReferencesRegistry.h +80 -0
- package/android/src/main/cpp/Exceptions.cpp +22 -0
- package/android/src/main/cpp/Exceptions.h +38 -0
- package/android/src/main/cpp/ExpoModulesHostObject.cpp +47 -0
- package/android/src/main/cpp/ExpoModulesHostObject.h +32 -0
- package/android/src/main/cpp/JNIFunctionBody.cpp +44 -0
- package/android/src/main/cpp/JNIFunctionBody.h +50 -0
- package/android/src/main/cpp/JNIInjector.cpp +23 -0
- package/android/src/main/cpp/JSIInteropModuleRegistry.cpp +122 -0
- package/android/src/main/cpp/JSIInteropModuleRegistry.h +96 -0
- package/android/src/main/cpp/JSIObjectWrapper.h +33 -0
- package/android/src/main/cpp/JSITypeConverter.h +84 -0
- package/android/src/main/cpp/JavaScriptModuleObject.cpp +219 -0
- package/android/src/main/cpp/JavaScriptModuleObject.h +144 -0
- package/android/src/main/cpp/JavaScriptObject.cpp +125 -0
- package/android/src/main/cpp/JavaScriptObject.h +131 -0
- package/android/src/main/cpp/JavaScriptRuntime.cpp +127 -0
- package/android/src/main/cpp/JavaScriptRuntime.h +87 -0
- package/android/src/main/cpp/JavaScriptValue.cpp +172 -0
- package/android/src/main/cpp/JavaScriptValue.h +78 -0
- package/android/src/main/cpp/MethodMetadata.cpp +340 -0
- package/android/src/main/cpp/MethodMetadata.h +131 -0
- package/android/src/main/java/expo/modules/adapters/react/NativeModulesProxy.java +2 -0
- package/android/src/main/java/expo/modules/core/errors/ContextDestroyedException.kt +7 -0
- package/android/src/main/java/expo/modules/interfaces/permissions/Permissions.java +30 -0
- package/android/src/main/java/expo/modules/kotlin/AppContext.kt +98 -3
- package/android/src/main/java/expo/modules/kotlin/ConcatIterator.kt +18 -0
- package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +15 -12
- package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +45 -3
- package/android/src/main/java/expo/modules/kotlin/activityaware/AppCompatActivityAware.kt +49 -0
- package/android/src/main/java/expo/modules/kotlin/activityaware/AppCompatActivityAwareHelper.kt +43 -0
- package/android/src/main/java/expo/modules/kotlin/activityaware/OnActivityAvailableListener.kt +18 -0
- package/android/src/main/java/expo/modules/kotlin/activityresult/ActivityResultsManager.kt +99 -0
- package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultCaller.kt +25 -0
- package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultContract.kt +27 -0
- package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultFallbackCallback.kt +17 -0
- package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultLauncher.kt +30 -0
- package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultRegistry.kt +358 -0
- package/android/src/main/java/expo/modules/kotlin/activityresult/DataPersistor.kt +135 -0
- package/android/src/main/java/expo/modules/kotlin/defaultmodules/ErrorManagerModule.kt +2 -2
- package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +13 -0
- package/android/src/main/java/expo/modules/kotlin/exception/ExceptionDecorator.kt +2 -0
- package/android/src/main/java/expo/modules/kotlin/functions/AnyFunction.kt +53 -15
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunction.kt +35 -7
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionBuilder.kt +13 -121
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionComponent.kt +21 -0
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromiseComponent.kt +21 -0
- package/android/src/main/java/expo/modules/kotlin/functions/SuspendFunctionComponent.kt +63 -0
- package/android/src/main/java/expo/modules/kotlin/functions/SyncFunctionComponent.kt +36 -0
- package/android/src/main/java/expo/modules/kotlin/jni/CppType.kt +19 -0
- package/android/src/main/java/expo/modules/kotlin/jni/JNIFunctionBody.kt +39 -0
- package/android/src/main/java/expo/modules/kotlin/jni/JSIInteropModuleRegistry.kt +89 -0
- package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptModuleObject.kt +46 -0
- package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptObject.kt +113 -0
- package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptValue.kt +35 -0
- package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +16 -6
- package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +5 -500
- package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +30 -5
- package/android/src/main/java/expo/modules/kotlin/objects/ObjectDefinitionBuilder.kt +271 -0
- package/android/src/main/java/expo/modules/kotlin/objects/ObjectDefinitionData.kt +21 -0
- package/android/src/main/java/expo/modules/kotlin/objects/PropertyComponent.kt +54 -0
- package/android/src/main/java/expo/modules/kotlin/objects/PropertyComponentBuilder.kt +32 -0
- package/android/src/main/java/expo/modules/kotlin/providers/AppContextProvider.kt +14 -0
- package/android/src/main/java/expo/modules/kotlin/providers/CurrentActivityProvider.kt +22 -0
- package/android/src/main/java/expo/modules/kotlin/records/RecordTypeConverter.kt +19 -2
- package/android/src/main/java/expo/modules/kotlin/types/AnyType.kt +3 -2
- package/android/src/main/java/expo/modules/kotlin/types/AnyTypeConverter.kt +36 -0
- package/android/src/main/java/expo/modules/kotlin/types/ArrayTypeConverter.kt +7 -2
- package/android/src/main/java/expo/modules/kotlin/types/BasicTypeConverters.kt +68 -20
- package/android/src/main/java/expo/modules/kotlin/types/EnumTypeConverter.kt +50 -22
- package/android/src/main/java/expo/modules/kotlin/types/ListTypeConverter.kt +18 -2
- package/android/src/main/java/expo/modules/kotlin/types/MapTypeConverter.kt +18 -2
- package/android/src/main/java/expo/modules/kotlin/types/PairTypeConverter.kt +17 -2
- package/android/src/main/java/expo/modules/kotlin/types/TypeConverter.kt +43 -3
- package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +12 -0
- package/android/src/main/java/expo/modules/kotlin/views/ViewGroupDefinitionBuilder.kt +0 -41
- package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +0 -33
- package/build/NativeModulesProxy.native.d.ts.map +1 -1
- package/build/NativeModulesProxy.native.js +9 -3
- package/build/NativeModulesProxy.native.js.map +1 -1
- package/build/PermissionsInterface.d.ts +29 -0
- package/build/PermissionsInterface.d.ts.map +1 -1
- package/build/PermissionsInterface.js +9 -0
- package/build/PermissionsInterface.js.map +1 -1
- package/ios/AppDelegates/EXAppDelegatesLoader.m +1 -2
- package/ios/ExpoModulesCore.podspec +3 -2
- package/ios/JSI/EXJSIConversions.mm +6 -0
- package/ios/JSI/EXJSIInstaller.h +15 -21
- package/ios/JSI/EXJSIInstaller.mm +39 -3
- package/ios/JSI/EXJSIUtils.h +48 -3
- package/ios/JSI/EXJSIUtils.mm +88 -4
- package/ios/JSI/EXJavaScriptObject.h +11 -18
- package/ios/JSI/EXJavaScriptObject.mm +37 -18
- package/ios/JSI/EXJavaScriptRuntime.h +43 -9
- package/ios/JSI/EXJavaScriptRuntime.mm +70 -27
- package/ios/JSI/EXJavaScriptTypedArray.h +30 -0
- package/ios/JSI/EXJavaScriptTypedArray.mm +29 -0
- package/ios/JSI/EXJavaScriptValue.h +3 -2
- package/ios/JSI/EXJavaScriptValue.mm +17 -20
- package/ios/JSI/EXJavaScriptWeakObject.h +23 -0
- package/ios/JSI/EXJavaScriptWeakObject.mm +53 -0
- package/ios/JSI/EXObjectDeallocator.h +27 -0
- package/ios/JSI/ExpoModulesHostObject.h +3 -3
- package/ios/JSI/ExpoModulesHostObject.mm +4 -4
- package/ios/JSI/JavaScriptRuntime.swift +38 -1
- package/ios/JSI/JavaScriptValue.swift +7 -0
- package/ios/JSI/TypedArray.cpp +67 -0
- package/ios/JSI/TypedArray.h +46 -0
- package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +0 -11
- package/ios/NativeModulesProxy/EXNativeModulesProxy.h +17 -10
- package/ios/NativeModulesProxy/EXNativeModulesProxy.mm +86 -77
- package/ios/NativeModulesProxy/NativeModulesProxyModule.swift +17 -0
- package/ios/Services/EXReactNativeEventEmitter.h +2 -2
- package/ios/Services/EXReactNativeEventEmitter.m +11 -6
- package/ios/Swift/AppContext.swift +206 -28
- package/ios/Swift/Arguments/AnyArgument.swift +18 -0
- package/ios/Swift/Arguments/{Types/EnumArgumentType.swift → EnumArgument.swift} +2 -17
- package/ios/Swift/Classes/ClassComponent.swift +95 -0
- package/ios/Swift/Classes/ClassComponentElement.swift +33 -0
- package/ios/Swift/Classes/ClassComponentElementsBuilder.swift +34 -0
- package/ios/Swift/Classes/ClassComponentFactories.swift +96 -0
- package/ios/Swift/DynamicTypes/AnyDynamicType.swift +44 -0
- package/ios/Swift/DynamicTypes/DynamicArrayType.swift +56 -0
- package/ios/Swift/DynamicTypes/DynamicConvertibleType.swift +27 -0
- package/ios/Swift/DynamicTypes/DynamicEnumType.swift +27 -0
- package/ios/Swift/DynamicTypes/DynamicOptionalType.swift +63 -0
- package/ios/Swift/DynamicTypes/DynamicRawType.swift +33 -0
- package/ios/Swift/DynamicTypes/DynamicSharedObjectType.swift +37 -0
- package/ios/Swift/DynamicTypes/DynamicType.swift +39 -0
- package/ios/Swift/DynamicTypes/DynamicTypedArrayType.swift +46 -0
- package/ios/Swift/Exceptions/ChainableException.swift +3 -3
- package/ios/Swift/Exceptions/CodedError.swift +1 -1
- package/ios/Swift/Exceptions/Exception.swift +8 -6
- package/ios/Swift/Exceptions/UnexpectedException.swift +2 -1
- package/ios/Swift/ExpoBridgeModule.m +5 -0
- package/ios/Swift/ExpoBridgeModule.swift +79 -0
- package/ios/Swift/Functions/AnyFunction.swift +33 -31
- package/ios/Swift/Functions/AsyncFunctionComponent.swift +196 -59
- package/ios/Swift/Functions/SyncFunctionComponent.swift +142 -58
- package/ios/Swift/JavaScriptUtils.swift +32 -57
- package/ios/Swift/Logging/LogHandlers.swift +39 -0
- package/ios/Swift/Logging/LogType.swift +62 -0
- package/ios/Swift/Logging/Logger.swift +201 -0
- package/ios/Swift/ModuleHolder.swift +19 -54
- package/ios/Swift/ModuleRegistry.swift +7 -1
- package/ios/Swift/Modules/AnyModule.swift +3 -3
- package/ios/Swift/ModulesProvider.swift +2 -0
- package/ios/Swift/Objects/JavaScriptObjectBuilder.swift +37 -0
- package/ios/Swift/Objects/ObjectDefinition.swift +74 -1
- package/ios/Swift/Objects/ObjectDefinitionComponents.swift +77 -68
- package/ios/Swift/Objects/PropertyComponent.swift +147 -0
- package/ios/Swift/Promise.swift +17 -4
- package/ios/Swift/Records/Field.swift +2 -2
- package/ios/Swift/SharedObjects/SharedObject.swift +20 -0
- package/ios/Swift/SharedObjects/SharedObjectRegistry.swift +129 -0
- package/ios/Swift/TypedArrays/AnyTypedArray.swift +11 -0
- package/ios/Swift/TypedArrays/ConcreteTypedArrays.swift +56 -0
- package/ios/Swift/TypedArrays/GenericTypedArray.swift +49 -0
- package/ios/Swift/TypedArrays/TypedArray.swift +80 -0
- package/ios/Swift/Utilities.swift +28 -0
- package/ios/Swift/Views/ConcreteViewProp.swift +3 -3
- package/ios/Swift/Views/ViewManagerDefinitionComponents.swift +2 -2
- package/ios/Tests/ClassComponentSpec.swift +210 -0
- package/ios/Tests/DynamicTypeSpec.swift +336 -0
- package/ios/Tests/EnumArgumentSpec.swift +48 -0
- package/ios/Tests/ExpoModulesSpec.swift +17 -3
- package/ios/Tests/FunctionSpec.swift +167 -118
- package/ios/Tests/Mocks/ModuleMocks.swift +1 -1
- package/ios/Tests/PropertyComponentSpec.swift +95 -0
- package/ios/Tests/SharedObjectRegistrySpec.swift +109 -0
- package/ios/Tests/TypedArraysSpec.swift +136 -0
- package/package.json +2 -2
- package/src/NativeModulesProxy.native.ts +13 -3
- package/src/PermissionsInterface.ts +29 -0
- package/src/ts-declarations/ExpoModules.d.ts +7 -0
- package/tsconfig.json +1 -1
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromise.kt +0 -15
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncSuspendFunction.kt +0 -36
- package/ios/Swift/Arguments/AnyArgumentType.swift +0 -13
- package/ios/Swift/Arguments/ArgumentType.swift +0 -28
- package/ios/Swift/Arguments/Types/ArrayArgumentType.swift +0 -42
- package/ios/Swift/Arguments/Types/ConvertibleArgumentType.swift +0 -16
- package/ios/Swift/Arguments/Types/OptionalArgumentType.swift +0 -49
- package/ios/Swift/Arguments/Types/PromiseArgumentType.swift +0 -15
- package/ios/Swift/Arguments/Types/RawArgumentType.swift +0 -25
- package/ios/Swift/Functions/ConcreteFunction.swift +0 -103
- package/ios/Swift/SwiftInteropBridge.swift +0 -155
- package/ios/Tests/ArgumentTypeSpec.swift +0 -143
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// Copyright © 2021-present 650 Industries, Inc. (aka Expo)
|
|
2
|
+
|
|
3
|
+
#pragma once
|
|
4
|
+
|
|
5
|
+
#include "JSIObjectWrapper.h"
|
|
6
|
+
|
|
7
|
+
#include <fbjni/fbjni.h>
|
|
8
|
+
#include <jsi/jsi.h>
|
|
9
|
+
|
|
10
|
+
#include <type_traits>
|
|
11
|
+
|
|
12
|
+
namespace jni = facebook::jni;
|
|
13
|
+
namespace jsi = facebook::jsi;
|
|
14
|
+
|
|
15
|
+
namespace expo {
|
|
16
|
+
/**
|
|
17
|
+
* A base template of the jni to jsi types converter.
|
|
18
|
+
* To make this conversion as fast and easy as possible we used the type trait technic.
|
|
19
|
+
*/
|
|
20
|
+
template<class T, typename = void>
|
|
21
|
+
struct jsi_type_converter {
|
|
22
|
+
static const bool isDefined = false;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Conversion from jni::alias_ref<T::javaobject> to jsi::Value where T extends JSIValueWrapper or JSIObjectWrapper.
|
|
27
|
+
*/
|
|
28
|
+
template<class T>
|
|
29
|
+
struct jsi_type_converter<
|
|
30
|
+
jni::alias_ref<T>,
|
|
31
|
+
std::enable_if_t<
|
|
32
|
+
// jni::ReprType<T>::HybridType>::value if T looks like `R::javaobject`, it will return R
|
|
33
|
+
std::is_base_of<JSIValueWrapper, typename jni::ReprType<T>::HybridType>::value ||
|
|
34
|
+
std::is_base_of<JSIObjectWrapper, typename jni::ReprType<T>::HybridType>::value
|
|
35
|
+
>
|
|
36
|
+
> {
|
|
37
|
+
static const bool isDefined = true;
|
|
38
|
+
|
|
39
|
+
inline static jsi::Value convert(
|
|
40
|
+
jsi::Runtime &runtime,
|
|
41
|
+
jni::alias_ref<T> &value) {
|
|
42
|
+
if (value == nullptr) {
|
|
43
|
+
return jsi::Value::undefined();
|
|
44
|
+
}
|
|
45
|
+
return jsi::Value(runtime, *value->cthis()->get());
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Conversion from primitive types from which jsi::Value can be constructed (like bool, double) to jsi::Value.
|
|
51
|
+
*/
|
|
52
|
+
template<class T>
|
|
53
|
+
struct jsi_type_converter<
|
|
54
|
+
T,
|
|
55
|
+
std::enable_if_t<std::is_fundamental_v<T> && std::is_constructible_v<jsi::Value, T>>
|
|
56
|
+
> {
|
|
57
|
+
static const bool isDefined = true;
|
|
58
|
+
|
|
59
|
+
inline static jsi::Value convert(jsi::Runtime &runtime, T value) {
|
|
60
|
+
return jsi::Value(value);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Conversion from jni::alias_ref<jstring> to jsi::Value.
|
|
66
|
+
*/
|
|
67
|
+
template<>
|
|
68
|
+
struct jsi_type_converter<jni::alias_ref<jstring>> {
|
|
69
|
+
static const bool isDefined = true;
|
|
70
|
+
|
|
71
|
+
inline static jsi::Value convert(jsi::Runtime &runtime, jni::alias_ref<jstring> &value) {
|
|
72
|
+
if (value == nullptr) {
|
|
73
|
+
return jsi::Value::undefined();
|
|
74
|
+
}
|
|
75
|
+
return jsi::Value(jsi::String::createFromUtf8(runtime, value->toStdString()));
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Helper that checks if the type converter was defined for the given type.
|
|
81
|
+
*/
|
|
82
|
+
template<class T>
|
|
83
|
+
inline constexpr bool is_jsi_type_converter_defined = jsi_type_converter<T>::isDefined;
|
|
84
|
+
} // namespace expo
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
// Copyright © 2021-present 650 Industries, Inc. (aka Expo)
|
|
2
|
+
|
|
3
|
+
#include "JavaScriptModuleObject.h"
|
|
4
|
+
#include "JSIInteropModuleRegistry.h"
|
|
5
|
+
|
|
6
|
+
#include <folly/dynamic.h>
|
|
7
|
+
#include <jsi/JSIDynamic.h>
|
|
8
|
+
#include <react/jni/ReadableNativeArray.h>
|
|
9
|
+
#include <fbjni/detail/Hybrid.h>
|
|
10
|
+
#include <ReactCommon/TurboModuleUtils.h>
|
|
11
|
+
#include <jni/JCallback.h>
|
|
12
|
+
#include <jsi/JSIDynamic.h>
|
|
13
|
+
#include <fbjni/fbjni.h>
|
|
14
|
+
#include <jsi/jsi.h>
|
|
15
|
+
|
|
16
|
+
#include <utility>
|
|
17
|
+
#include <tuple>
|
|
18
|
+
#include <algorithm>
|
|
19
|
+
|
|
20
|
+
namespace jni = facebook::jni;
|
|
21
|
+
namespace jsi = facebook::jsi;
|
|
22
|
+
namespace react = facebook::react;
|
|
23
|
+
|
|
24
|
+
namespace expo {
|
|
25
|
+
|
|
26
|
+
jni::local_ref<jni::HybridClass<JavaScriptModuleObject>::jhybriddata>
|
|
27
|
+
JavaScriptModuleObject::initHybrid(jni::alias_ref<jhybridobject> jThis) {
|
|
28
|
+
return makeCxxInstance(jThis);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
void JavaScriptModuleObject::registerNatives() {
|
|
32
|
+
registerHybrid({
|
|
33
|
+
makeNativeMethod("initHybrid", JavaScriptModuleObject::initHybrid),
|
|
34
|
+
makeNativeMethod("exportConstants", JavaScriptModuleObject::exportConstants),
|
|
35
|
+
makeNativeMethod("registerSyncFunction",
|
|
36
|
+
JavaScriptModuleObject::registerSyncFunction),
|
|
37
|
+
makeNativeMethod("registerAsyncFunction",
|
|
38
|
+
JavaScriptModuleObject::registerAsyncFunction),
|
|
39
|
+
makeNativeMethod("registerProperty",
|
|
40
|
+
JavaScriptModuleObject::registerProperty),
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
std::shared_ptr<jsi::Object> JavaScriptModuleObject::getJSIObject(jsi::Runtime &runtime) {
|
|
45
|
+
if (jsiObject == nullptr) {
|
|
46
|
+
auto hostObject = std::make_shared<JavaScriptModuleObject::HostObject>(this);
|
|
47
|
+
jsiObject = std::make_shared<jsi::Object>(
|
|
48
|
+
jsi::Object::createFromHostObject(runtime, hostObject));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return jsiObject;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
void JavaScriptModuleObject::exportConstants(
|
|
55
|
+
jni::alias_ref<react::NativeMap::javaobject> constants
|
|
56
|
+
) {
|
|
57
|
+
auto dynamic = constants->cthis()->consume();
|
|
58
|
+
assert(dynamic.isObject());
|
|
59
|
+
|
|
60
|
+
for (const auto &[key, value]: dynamic.items()) {
|
|
61
|
+
this->constants[key.asString()] = value;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
void JavaScriptModuleObject::registerSyncFunction(
|
|
66
|
+
jni::alias_ref<jstring> name,
|
|
67
|
+
jint args,
|
|
68
|
+
jni::alias_ref<jni::JArrayInt> desiredTypes,
|
|
69
|
+
jni::alias_ref<JNIFunctionBody::javaobject> body
|
|
70
|
+
) {
|
|
71
|
+
std::string cName = name->toStdString();
|
|
72
|
+
std::unique_ptr<int[]> types = desiredTypes->getRegion(0, args);
|
|
73
|
+
|
|
74
|
+
methodsMetadata.try_emplace(
|
|
75
|
+
cName,
|
|
76
|
+
cName,
|
|
77
|
+
args,
|
|
78
|
+
false,
|
|
79
|
+
std::move(types),
|
|
80
|
+
jni::make_global(body)
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
void JavaScriptModuleObject::registerAsyncFunction(
|
|
85
|
+
jni::alias_ref<jstring> name,
|
|
86
|
+
jint args,
|
|
87
|
+
jni::alias_ref<jni::JArrayInt> desiredTypes,
|
|
88
|
+
jni::alias_ref<JNIAsyncFunctionBody::javaobject> body
|
|
89
|
+
) {
|
|
90
|
+
auto cName = name->toStdString();
|
|
91
|
+
std::unique_ptr<int[]> types = desiredTypes->getRegion(0, args);
|
|
92
|
+
|
|
93
|
+
methodsMetadata.try_emplace(
|
|
94
|
+
cName,
|
|
95
|
+
cName,
|
|
96
|
+
args,
|
|
97
|
+
true,
|
|
98
|
+
std::move(types),
|
|
99
|
+
jni::make_global(body)
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
void JavaScriptModuleObject::registerProperty(
|
|
104
|
+
jni::alias_ref<jstring> name,
|
|
105
|
+
jint desiredType,
|
|
106
|
+
jni::alias_ref<JNIFunctionBody::javaobject> getter,
|
|
107
|
+
jni::alias_ref<JNIFunctionBody::javaobject> setter
|
|
108
|
+
) {
|
|
109
|
+
auto cName = name->toStdString();
|
|
110
|
+
std::unique_ptr<int[]> types = std::make_unique<int[]>(1);
|
|
111
|
+
types[0] = desiredType;
|
|
112
|
+
|
|
113
|
+
auto getterMetadata = MethodMetadata(
|
|
114
|
+
cName,
|
|
115
|
+
0,
|
|
116
|
+
false,
|
|
117
|
+
std::make_unique<int[]>(0),
|
|
118
|
+
jni::make_global(getter)
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
auto setterMetadata = MethodMetadata(
|
|
122
|
+
cName,
|
|
123
|
+
1,
|
|
124
|
+
false,
|
|
125
|
+
std::move(types),
|
|
126
|
+
jni::make_global(setter)
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
auto functions = std::make_pair(
|
|
130
|
+
std::move(getterMetadata),
|
|
131
|
+
std::move(setterMetadata)
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
properties.insert({cName, std::move(functions)});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
JavaScriptModuleObject::HostObject::HostObject(
|
|
138
|
+
JavaScriptModuleObject *jsModule) : jsModule(jsModule) {}
|
|
139
|
+
|
|
140
|
+
jsi::Value JavaScriptModuleObject::HostObject::get(jsi::Runtime &runtime,
|
|
141
|
+
const jsi::PropNameID &name) {
|
|
142
|
+
auto cName = name.utf8(runtime);
|
|
143
|
+
|
|
144
|
+
auto constantsRecord = jsModule->constants.find(cName);
|
|
145
|
+
if (constantsRecord != jsModule->constants.end()) {
|
|
146
|
+
auto dynamic = constantsRecord->second;
|
|
147
|
+
return jsi::valueFromDynamic(runtime, dynamic);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
auto propertyRecord = jsModule->properties.find(cName);
|
|
151
|
+
if (propertyRecord != jsModule->properties.end()) {
|
|
152
|
+
auto&[getter, _] = propertyRecord->second;
|
|
153
|
+
return getter.callSync(runtime, jsModule->jsiInteropModuleRegistry, nullptr, 0);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
auto metadataRecord = jsModule->methodsMetadata.find(cName);
|
|
157
|
+
if (metadataRecord == jsModule->methodsMetadata.end()) {
|
|
158
|
+
return jsi::Value::undefined();
|
|
159
|
+
}
|
|
160
|
+
auto &metadata = metadataRecord->second;
|
|
161
|
+
return jsi::Value(runtime, *metadata.toJSFunction(runtime, jsModule->jsiInteropModuleRegistry));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
void JavaScriptModuleObject::HostObject::set(
|
|
165
|
+
jsi::Runtime &runtime,
|
|
166
|
+
const jsi::PropNameID &name,
|
|
167
|
+
const jsi::Value &value
|
|
168
|
+
) {
|
|
169
|
+
auto cName = name.utf8(runtime);
|
|
170
|
+
auto propertyRecord = jsModule->properties.find(cName);
|
|
171
|
+
if (propertyRecord != jsModule->properties.end()) {
|
|
172
|
+
auto&[_, setter] = propertyRecord->second;
|
|
173
|
+
setter.callSync(runtime, jsModule->jsiInteropModuleRegistry, &value, 1);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
throw jsi::JSError(
|
|
178
|
+
runtime,
|
|
179
|
+
"RuntimeError: Cannot override the host object for expo module '" + name.utf8(runtime) + "'"
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
std::vector<jsi::PropNameID> JavaScriptModuleObject::HostObject::getPropertyNames(
|
|
184
|
+
jsi::Runtime &rt
|
|
185
|
+
) {
|
|
186
|
+
auto &metadata = jsModule->methodsMetadata;
|
|
187
|
+
std::vector<jsi::PropNameID> result;
|
|
188
|
+
std::transform(
|
|
189
|
+
metadata.begin(),
|
|
190
|
+
metadata.end(),
|
|
191
|
+
std::back_inserter(result),
|
|
192
|
+
[&rt](const auto &kv) {
|
|
193
|
+
return jsi::PropNameID::forUtf8(rt, kv.first);
|
|
194
|
+
}
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
auto &constants = jsModule->constants;
|
|
198
|
+
std::transform(
|
|
199
|
+
constants.begin(),
|
|
200
|
+
constants.end(),
|
|
201
|
+
std::back_inserter(result),
|
|
202
|
+
[&rt](const auto &kv) {
|
|
203
|
+
return jsi::PropNameID::forUtf8(rt, kv.first);
|
|
204
|
+
}
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
auto &properties = jsModule->properties;
|
|
208
|
+
std::transform(
|
|
209
|
+
properties.begin(),
|
|
210
|
+
properties.end(),
|
|
211
|
+
std::back_inserter(result),
|
|
212
|
+
[&rt](const auto &kv) {
|
|
213
|
+
return jsi::PropNameID::forUtf8(rt, kv.first);
|
|
214
|
+
}
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
return result;
|
|
218
|
+
}
|
|
219
|
+
} // namespace expo
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// Copyright © 2021-present 650 Industries, Inc. (aka Expo)
|
|
2
|
+
|
|
3
|
+
#pragma once
|
|
4
|
+
|
|
5
|
+
#include <fbjni/fbjni.h>
|
|
6
|
+
#include <jsi/jsi.h>
|
|
7
|
+
#include <react/jni/ReadableNativeArray.h>
|
|
8
|
+
#include <jni/JCallback.h>
|
|
9
|
+
|
|
10
|
+
#include <unordered_map>
|
|
11
|
+
|
|
12
|
+
#include "MethodMetadata.h"
|
|
13
|
+
#include "JNIFunctionBody.h"
|
|
14
|
+
|
|
15
|
+
namespace jni = facebook::jni;
|
|
16
|
+
namespace jsi = facebook::jsi;
|
|
17
|
+
namespace react = facebook::react;
|
|
18
|
+
|
|
19
|
+
namespace expo {
|
|
20
|
+
class JSIInteropModuleRegistry;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* A CPP part of the module.
|
|
24
|
+
*
|
|
25
|
+
* Right now objects of this class are stored by the ModuleHolder to ensure they will live
|
|
26
|
+
* as long as the RN context.
|
|
27
|
+
*/
|
|
28
|
+
class JavaScriptModuleObject : public jni::HybridClass<JavaScriptModuleObject> {
|
|
29
|
+
public:
|
|
30
|
+
static auto constexpr
|
|
31
|
+
kJavaDescriptor = "Lexpo/modules/kotlin/jni/JavaScriptModuleObject;";
|
|
32
|
+
static auto constexpr TAG = "JavaScriptModuleObject";
|
|
33
|
+
|
|
34
|
+
static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jhybridobject> jThis);
|
|
35
|
+
|
|
36
|
+
static void registerNatives();
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Pointer to the module registry interop.
|
|
40
|
+
*/
|
|
41
|
+
JSIInteropModuleRegistry *jsiInteropModuleRegistry;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Returns a cached instance of jsi::Object representing this module.
|
|
45
|
+
* @param runtime
|
|
46
|
+
* @return Wrapped instance of JavaScriptModuleObject::HostObject
|
|
47
|
+
*/
|
|
48
|
+
std::shared_ptr<jsi::Object> getJSIObject(jsi::Runtime &runtime);
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Exports constants that will be assigned to the underlying HostObject.
|
|
52
|
+
*/
|
|
53
|
+
void exportConstants(jni::alias_ref<react::NativeMap::javaobject> constants);
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Registers a sync function.
|
|
57
|
+
* That function can be called via the `JavaScriptModuleObject.callSyncMethod` method.
|
|
58
|
+
*/
|
|
59
|
+
void registerSyncFunction(
|
|
60
|
+
jni::alias_ref<jstring> name,
|
|
61
|
+
jint args,
|
|
62
|
+
jni::alias_ref<jni::JArrayInt> desiredTypes,
|
|
63
|
+
jni::alias_ref<JNIFunctionBody::javaobject> body
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Registers a async function.
|
|
68
|
+
* That function can be called via the `JavaScriptModuleObject.callAsyncMethod` method.
|
|
69
|
+
*/
|
|
70
|
+
void registerAsyncFunction(
|
|
71
|
+
jni::alias_ref<jstring> name,
|
|
72
|
+
jint args,
|
|
73
|
+
jni::alias_ref<jni::JArrayInt> desiredTypes,
|
|
74
|
+
jni::alias_ref<JNIAsyncFunctionBody::javaobject> body
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Registers a property
|
|
79
|
+
* @param name of the property
|
|
80
|
+
* @param desiredType of the setter argument
|
|
81
|
+
* @param getter body for the get method - can be nullptr
|
|
82
|
+
* @param setter body for the set method - can be nullptr
|
|
83
|
+
*/
|
|
84
|
+
void registerProperty(
|
|
85
|
+
jni::alias_ref<jstring> name,
|
|
86
|
+
jint desiredType,
|
|
87
|
+
jni::alias_ref<JNIFunctionBody::javaobject> getter,
|
|
88
|
+
jni::alias_ref<JNIFunctionBody::javaobject> setter
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* An inner class of the `JavaScriptModuleObject` that is exported to the JS.
|
|
93
|
+
* It's an additional communication layer between JS and Kotlin.
|
|
94
|
+
* So the high-level view on accessing the exported function will look like this:
|
|
95
|
+
* `JS` --get function--> `JavaScriptModuleObject::HostObject` --access module metadata--> `JavaScriptModuleObject`
|
|
96
|
+
* --create JSI function--> `MethodMetadata`
|
|
97
|
+
*
|
|
98
|
+
* This abstraction wasn't necessary. However, it makes the management of ownership much easier -
|
|
99
|
+
* `JavaScriptModuleObject` is held by the ModuleHolder and `JavaScriptModuleObject::HostObject` is stored in the JS runtime.
|
|
100
|
+
* Without this distinction the `JavaScriptModuleObject` would have to turn into `HostObject` and `HybridObject` at the same time.
|
|
101
|
+
*/
|
|
102
|
+
class HostObject : public jsi::HostObject {
|
|
103
|
+
public:
|
|
104
|
+
HostObject(JavaScriptModuleObject *);
|
|
105
|
+
|
|
106
|
+
jsi::Value get(jsi::Runtime &, const jsi::PropNameID &name) override;
|
|
107
|
+
|
|
108
|
+
void set(jsi::Runtime &, const jsi::PropNameID &name, const jsi::Value &value) override;
|
|
109
|
+
|
|
110
|
+
std::vector<jsi::PropNameID> getPropertyNames(jsi::Runtime &rt) override;
|
|
111
|
+
|
|
112
|
+
private:
|
|
113
|
+
JavaScriptModuleObject *jsModule;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
private:
|
|
117
|
+
friend HybridBase;
|
|
118
|
+
/**
|
|
119
|
+
* A reference to the `JavaScriptModuleObject::HostObject`.
|
|
120
|
+
* Simple we cached that value to return the same object each time.
|
|
121
|
+
*/
|
|
122
|
+
std::shared_ptr<jsi::Object> jsiObject = nullptr;
|
|
123
|
+
jni::global_ref<JavaScriptModuleObject::javaobject> javaPart_;
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Metadata map that stores information about all available methods on this module.
|
|
127
|
+
*/
|
|
128
|
+
std::unordered_map<std::string, MethodMetadata> methodsMetadata;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* A constants map.
|
|
132
|
+
*/
|
|
133
|
+
std::unordered_map<std::string, folly::dynamic> constants;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* A registry of properties
|
|
137
|
+
* The first MethodMetadata points to the getter and the second one to the setter.
|
|
138
|
+
*/
|
|
139
|
+
std::map<std::string, std::pair<MethodMetadata, MethodMetadata>> properties;
|
|
140
|
+
|
|
141
|
+
explicit JavaScriptModuleObject(jni::alias_ref<jhybridobject> jThis)
|
|
142
|
+
: javaPart_(jni::make_global(jThis)) {}
|
|
143
|
+
};
|
|
144
|
+
} // namespace expo
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// Copyright © 2021-present 650 Industries, Inc. (aka Expo)
|
|
2
|
+
|
|
3
|
+
#include "JavaScriptObject.h"
|
|
4
|
+
#include "JavaScriptValue.h"
|
|
5
|
+
#include "JavaScriptRuntime.h"
|
|
6
|
+
#include "JSITypeConverter.h"
|
|
7
|
+
|
|
8
|
+
namespace expo {
|
|
9
|
+
void JavaScriptObject::registerNatives() {
|
|
10
|
+
registerHybrid({
|
|
11
|
+
makeNativeMethod("hasProperty", JavaScriptObject::jniHasProperty),
|
|
12
|
+
makeNativeMethod("getProperty", JavaScriptObject::jniGetProperty),
|
|
13
|
+
makeNativeMethod("getPropertyNames", JavaScriptObject::jniGetPropertyNames),
|
|
14
|
+
makeNativeMethod("setBoolProperty", JavaScriptObject::setProperty<bool>),
|
|
15
|
+
makeNativeMethod("setDoubleProperty", JavaScriptObject::setProperty<double>),
|
|
16
|
+
makeNativeMethod("setStringProperty",
|
|
17
|
+
JavaScriptObject::setProperty<jni::alias_ref<jstring>>),
|
|
18
|
+
makeNativeMethod("setJSValueProperty",
|
|
19
|
+
JavaScriptObject::setProperty<jni::alias_ref<JavaScriptValue::javaobject>>),
|
|
20
|
+
makeNativeMethod("setJSObjectProperty",
|
|
21
|
+
JavaScriptObject::setProperty<jni::alias_ref<JavaScriptObject::javaobject>>),
|
|
22
|
+
makeNativeMethod("unsetProperty", JavaScriptObject::unsetProperty),
|
|
23
|
+
makeNativeMethod("defineBoolProperty", JavaScriptObject::defineProperty<bool>),
|
|
24
|
+
makeNativeMethod("defineDoubleProperty",
|
|
25
|
+
JavaScriptObject::defineProperty<double>),
|
|
26
|
+
makeNativeMethod("defineStringProperty",
|
|
27
|
+
JavaScriptObject::defineProperty<jni::alias_ref<jstring>>),
|
|
28
|
+
makeNativeMethod("defineJSValueProperty",
|
|
29
|
+
JavaScriptObject::defineProperty<jni::alias_ref<JavaScriptValue::javaobject>>),
|
|
30
|
+
makeNativeMethod("defineJSObjectProperty",
|
|
31
|
+
JavaScriptObject::defineProperty<jni::alias_ref<JavaScriptObject::javaobject>>),
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
JavaScriptObject::JavaScriptObject(
|
|
36
|
+
std::weak_ptr<JavaScriptRuntime> runtime,
|
|
37
|
+
std::shared_ptr<jsi::Object> jsObject
|
|
38
|
+
) : runtimeHolder(std::move(runtime)), jsObject(std::move(jsObject)) {
|
|
39
|
+
assert(runtimeHolder.lock() != nullptr);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
std::shared_ptr<jsi::Object> JavaScriptObject::get() {
|
|
43
|
+
return jsObject;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
bool JavaScriptObject::hasProperty(const std::string &name) {
|
|
47
|
+
auto runtime = runtimeHolder.lock();
|
|
48
|
+
assert(runtime != nullptr);
|
|
49
|
+
return jsObject->hasProperty(*runtime->get(), name.c_str());
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
jsi::Value JavaScriptObject::getProperty(const std::string &name) {
|
|
53
|
+
auto runtime = runtimeHolder.lock();
|
|
54
|
+
assert(runtime != nullptr);
|
|
55
|
+
return jsObject->getProperty(*runtime->get(), name.c_str());
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
bool JavaScriptObject::jniHasProperty(jni::alias_ref<jstring> name) {
|
|
59
|
+
return hasProperty(name->toStdString());
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
jni::local_ref<JavaScriptValue::javaobject> JavaScriptObject::jniGetProperty(
|
|
63
|
+
jni::alias_ref<jstring> name
|
|
64
|
+
) {
|
|
65
|
+
auto result = std::make_shared<jsi::Value>(getProperty(name->toStdString()));
|
|
66
|
+
return JavaScriptValue::newObjectCxxArgs(runtimeHolder, result);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
std::vector<std::string> JavaScriptObject::getPropertyNames() {
|
|
70
|
+
auto runtime = runtimeHolder.lock();
|
|
71
|
+
assert(runtime != nullptr);
|
|
72
|
+
|
|
73
|
+
jsi::Array properties = jsObject->getPropertyNames(*runtime->get());
|
|
74
|
+
auto size = properties.size(*runtime->get());
|
|
75
|
+
|
|
76
|
+
std::vector<std::string> names(size);
|
|
77
|
+
for (size_t i = 0; i < size; i++) {
|
|
78
|
+
auto propertyName = properties
|
|
79
|
+
.getValueAtIndex(*runtime->get(), i)
|
|
80
|
+
.asString(*runtime->get())
|
|
81
|
+
.utf8(*runtime->get());
|
|
82
|
+
names[i] = propertyName;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return names;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
jni::local_ref<jni::JArrayClass<jstring>> JavaScriptObject::jniGetPropertyNames() {
|
|
89
|
+
std::vector<std::string> cResult = getPropertyNames();
|
|
90
|
+
auto paredResult = jni::JArrayClass<jstring>::newArray(cResult.size());
|
|
91
|
+
for (size_t i = 0; i < cResult.size(); i++) {
|
|
92
|
+
paredResult->setElement(i, jni::make_jstring(cResult[i]).get());
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return paredResult;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
void JavaScriptObject::setProperty(const std::string &name, jsi::Value value) {
|
|
99
|
+
auto runtime = runtimeHolder.lock();
|
|
100
|
+
assert(runtime != nullptr);
|
|
101
|
+
jsObject->setProperty(*runtime->get(), name.c_str(), value);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
void JavaScriptObject::unsetProperty(jni::alias_ref<jstring> name) {
|
|
105
|
+
auto runtime = runtimeHolder.lock();
|
|
106
|
+
assert(runtime != nullptr);
|
|
107
|
+
auto cName = name->toStdString();
|
|
108
|
+
jsObject->setProperty(
|
|
109
|
+
*runtime->get(),
|
|
110
|
+
cName.c_str(),
|
|
111
|
+
jsi::Value::undefined()
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
jsi::Object JavaScriptObject::preparePropertyDescriptor(
|
|
116
|
+
jsi::Runtime &jsRuntime,
|
|
117
|
+
int options
|
|
118
|
+
) {
|
|
119
|
+
jsi::Object descriptor(jsRuntime);
|
|
120
|
+
descriptor.setProperty(jsRuntime, "configurable", (bool) ((1 << 0) & options));
|
|
121
|
+
descriptor.setProperty(jsRuntime, "enumerable", (bool) ((1 << 1) & options));
|
|
122
|
+
descriptor.setProperty(jsRuntime, "writable", (bool) ((1 << 2) & options));
|
|
123
|
+
return descriptor;
|
|
124
|
+
}
|
|
125
|
+
} // namespace expo
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// Copyright © 2021-present 650 Industries, Inc. (aka Expo)
|
|
2
|
+
|
|
3
|
+
#pragma once
|
|
4
|
+
|
|
5
|
+
#include "JSIObjectWrapper.h"
|
|
6
|
+
#include "JSITypeConverter.h"
|
|
7
|
+
#include "JavaScriptRuntime.h"
|
|
8
|
+
|
|
9
|
+
#include <fbjni/fbjni.h>
|
|
10
|
+
#include <jsi/jsi.h>
|
|
11
|
+
|
|
12
|
+
#include <memory>
|
|
13
|
+
|
|
14
|
+
namespace jni = facebook::jni;
|
|
15
|
+
namespace jsi = facebook::jsi;
|
|
16
|
+
|
|
17
|
+
namespace expo {
|
|
18
|
+
class JavaScriptValue;
|
|
19
|
+
|
|
20
|
+
class JavaScriptRuntime;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Represents any JavaScript object. Its purpose is to exposes `jsi::Object` API back to Kotlin.
|
|
24
|
+
*/
|
|
25
|
+
class JavaScriptObject : public jni::HybridClass<JavaScriptObject>, JSIObjectWrapper {
|
|
26
|
+
public:
|
|
27
|
+
static auto constexpr
|
|
28
|
+
kJavaDescriptor = "Lexpo/modules/kotlin/jni/JavaScriptObject;";
|
|
29
|
+
static auto constexpr TAG = "JavaScriptObject";
|
|
30
|
+
|
|
31
|
+
static void registerNatives();
|
|
32
|
+
|
|
33
|
+
JavaScriptObject(
|
|
34
|
+
std::weak_ptr<JavaScriptRuntime> runtime,
|
|
35
|
+
std::shared_ptr<jsi::Object> jsObject
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
std::shared_ptr<jsi::Object> get() override;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @return a bool whether the object has a property with the given name
|
|
42
|
+
*/
|
|
43
|
+
bool hasProperty(const std::string &name);
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @return the property of the object with the given name.
|
|
47
|
+
* If the name isn't a property on the object, returns the `jsi::Value::undefined` value.
|
|
48
|
+
*/
|
|
49
|
+
jsi::Value getProperty(const std::string &name);
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @return a vector consisting of all enumerable property names in the object and its prototype chain.
|
|
53
|
+
*/
|
|
54
|
+
std::vector<std::string> getPropertyNames();
|
|
55
|
+
|
|
56
|
+
void setProperty(const std::string &name, jsi::Value value);
|
|
57
|
+
|
|
58
|
+
private:
|
|
59
|
+
friend HybridBase;
|
|
60
|
+
std::weak_ptr<JavaScriptRuntime> runtimeHolder;
|
|
61
|
+
std::shared_ptr<jsi::Object> jsObject;
|
|
62
|
+
|
|
63
|
+
bool jniHasProperty(jni::alias_ref<jstring> name);
|
|
64
|
+
|
|
65
|
+
jni::local_ref<jni::HybridClass<JavaScriptValue>::javaobject> jniGetProperty(
|
|
66
|
+
jni::alias_ref<jstring> name
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
jni::local_ref<jni::JArrayClass<jstring>> jniGetPropertyNames();
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Unsets property with the given name.
|
|
73
|
+
*/
|
|
74
|
+
void unsetProperty(jni::alias_ref<jstring> name);
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* A template to generate different versions of the `setProperty` method based on the `jsi_type_converter` trait.
|
|
78
|
+
* Those generated methods will be exported and visible in the Kotlin codebase.
|
|
79
|
+
* On the other hand, we could just make one function that would take a generic Java Object,
|
|
80
|
+
* but then we would have to decide what to do with it and how to convert it to jsi::Value
|
|
81
|
+
* in cpp. That would be expensive. So it's easier to ensure that
|
|
82
|
+
* we call the correct version of `setProperty` in the Kotlin code.
|
|
83
|
+
*
|
|
84
|
+
* This template will work only if the jsi_type_converter exists for a given type.
|
|
85
|
+
*/
|
|
86
|
+
template<
|
|
87
|
+
class T,
|
|
88
|
+
typename = std::enable_if_t<is_jsi_type_converter_defined<T>>
|
|
89
|
+
>
|
|
90
|
+
void setProperty(jni::alias_ref<jstring> name, T value) {
|
|
91
|
+
auto runtime = runtimeHolder.lock();
|
|
92
|
+
assert(runtime != nullptr);
|
|
93
|
+
auto cName = name->toStdString();
|
|
94
|
+
|
|
95
|
+
jsObject->setProperty(
|
|
96
|
+
*runtime->get(),
|
|
97
|
+
cName.c_str(),
|
|
98
|
+
jsi_type_converter<T>::convert(*runtime->get(), value)
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
template<
|
|
103
|
+
class T,
|
|
104
|
+
typename = std::enable_if_t<is_jsi_type_converter_defined<T>>
|
|
105
|
+
>
|
|
106
|
+
void defineProperty(jni::alias_ref<jstring> name, T value, int options) {
|
|
107
|
+
auto runtime = runtimeHolder.lock();
|
|
108
|
+
assert(runtime != nullptr);
|
|
109
|
+
jsi::Runtime &jsRuntime = *runtime->get();
|
|
110
|
+
|
|
111
|
+
auto cName = name->toStdString();
|
|
112
|
+
jsi::Object global = jsRuntime.global();
|
|
113
|
+
jsi::Object objectClass = global.getPropertyAsObject(jsRuntime, "Object");
|
|
114
|
+
jsi::Function definePropertyFunction = objectClass.getPropertyAsFunction(
|
|
115
|
+
jsRuntime,
|
|
116
|
+
"defineProperty"
|
|
117
|
+
);
|
|
118
|
+
jsi::Object descriptor = preparePropertyDescriptor(jsRuntime, options);
|
|
119
|
+
|
|
120
|
+
descriptor.setProperty(jsRuntime, "value", jsi_type_converter<T>::convert(jsRuntime, value));
|
|
121
|
+
|
|
122
|
+
definePropertyFunction.callWithThis(jsRuntime, objectClass, {
|
|
123
|
+
jsi::Value(jsRuntime, *jsObject),
|
|
124
|
+
jsi::String::createFromUtf8(jsRuntime, cName),
|
|
125
|
+
std::move(descriptor)
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
static jsi::Object preparePropertyDescriptor(jsi::Runtime &jsRuntime, int options);
|
|
130
|
+
};
|
|
131
|
+
} // namespace expo
|