expo-modules-core 0.9.0 → 0.10.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/CHANGELOG.md +25 -0
- package/android/CMakeLists.txt +154 -0
- package/android/build.gradle +293 -5
- 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 +29 -0
- package/android/src/main/cpp/JNIFunctionBody.h +50 -0
- package/android/src/main/cpp/JNIInjector.cpp +19 -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 +138 -0
- package/android/src/main/cpp/JavaScriptModuleObject.h +122 -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 +230 -0
- package/android/src/main/cpp/MethodMetadata.h +92 -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 +49 -1
- 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 +39 -3
- 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 +19 -14
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunction.kt +29 -7
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionBuilder.kt +13 -13
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionComponent.kt +18 -0
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromiseComponent.kt +18 -0
- package/android/src/main/java/expo/modules/kotlin/functions/SuspendFunctionComponent.kt +56 -0
- package/android/src/main/java/expo/modules/kotlin/functions/SyncFunctionComponent.kt +28 -0
- package/android/src/main/java/expo/modules/kotlin/jni/CppType.kt +18 -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 +44 -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 +15 -5
- package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +65 -111
- package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +35 -2
- 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/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 +5 -0
- 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/ios/AppDelegates/EXAppDelegatesLoader.m +1 -2
- package/ios/ExpoModulesCore.podspec +1 -1
- 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 +47 -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 +88 -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 +208 -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/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 +65 -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 +198 -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 +12 -3
- 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/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,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
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// Copyright © 2021-present 650 Industries, Inc. (aka Expo)
|
|
2
|
+
|
|
3
|
+
#include "JavaScriptRuntime.h"
|
|
4
|
+
#include "JavaScriptValue.h"
|
|
5
|
+
#include "JavaScriptObject.h"
|
|
6
|
+
#include "Exceptions.h"
|
|
7
|
+
|
|
8
|
+
#if FOR_HERMES
|
|
9
|
+
|
|
10
|
+
#include <hermes/hermes.h>
|
|
11
|
+
|
|
12
|
+
#include <utility>
|
|
13
|
+
|
|
14
|
+
#else
|
|
15
|
+
|
|
16
|
+
#include <jsi/JSCRuntime.h>
|
|
17
|
+
|
|
18
|
+
#endif
|
|
19
|
+
|
|
20
|
+
namespace jsi = facebook::jsi;
|
|
21
|
+
|
|
22
|
+
namespace expo {
|
|
23
|
+
|
|
24
|
+
void SyncCallInvoker::invokeAsync(std::function<void()> &&func) {
|
|
25
|
+
func();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
void SyncCallInvoker::invokeSync(std::function<void()> &&func) {
|
|
29
|
+
func();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
JavaScriptRuntime::JavaScriptRuntime()
|
|
33
|
+
: jsInvoker(std::make_shared<SyncCallInvoker>()),
|
|
34
|
+
nativeInvoker(std::make_shared<SyncCallInvoker>()) {
|
|
35
|
+
#if FOR_HERMES
|
|
36
|
+
auto config = ::hermes::vm::RuntimeConfig::Builder()
|
|
37
|
+
.withEnableSampleProfiling(false);
|
|
38
|
+
runtime = facebook::hermes::makeHermesRuntime(config.build());
|
|
39
|
+
|
|
40
|
+
// By default "global" property isn't set in the Hermes.
|
|
41
|
+
runtime->global().setProperty(
|
|
42
|
+
*runtime,
|
|
43
|
+
jsi::PropNameID::forUtf8(*runtime, "global"),
|
|
44
|
+
runtime->global()
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
// This version of the Hermes uses a Promise implementation that is provided by the RN.
|
|
48
|
+
// The `setImmediate` function isn't defined, but is required by the Promise implementation.
|
|
49
|
+
// That's why we inject it here.
|
|
50
|
+
auto setImmediatePropName = jsi::PropNameID::forUtf8(*runtime, "setImmediate");
|
|
51
|
+
runtime->global().setProperty(
|
|
52
|
+
*runtime,
|
|
53
|
+
setImmediatePropName,
|
|
54
|
+
jsi::Function::createFromHostFunction(
|
|
55
|
+
*runtime,
|
|
56
|
+
setImmediatePropName,
|
|
57
|
+
1,
|
|
58
|
+
[](jsi::Runtime &rt,
|
|
59
|
+
const jsi::Value &thisVal,
|
|
60
|
+
const jsi::Value *args,
|
|
61
|
+
size_t count) {
|
|
62
|
+
args[0].asObject(rt).asFunction(rt).call(rt);
|
|
63
|
+
return jsi::Value::undefined();
|
|
64
|
+
}
|
|
65
|
+
)
|
|
66
|
+
);
|
|
67
|
+
#else
|
|
68
|
+
runtime = facebook::jsc::makeJSCRuntime();
|
|
69
|
+
#endif
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
JavaScriptRuntime::JavaScriptRuntime(
|
|
73
|
+
jsi::Runtime *runtime,
|
|
74
|
+
std::shared_ptr<react::CallInvoker> jsInvoker,
|
|
75
|
+
std::shared_ptr<react::CallInvoker> nativeInvoker
|
|
76
|
+
) : jsInvoker(std::move(jsInvoker)), nativeInvoker(std::move(nativeInvoker)) {
|
|
77
|
+
// Creating a shared pointer that points to the runtime but doesn't own it, thus doesn't release it.
|
|
78
|
+
// In this code flow, the runtime should be owned by something else like the CatalystInstance.
|
|
79
|
+
// See explanation for constructor (8): https://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr
|
|
80
|
+
this->runtime = std::shared_ptr<jsi::Runtime>(std::shared_ptr<jsi::Runtime>(), runtime);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
jsi::Runtime *JavaScriptRuntime::get() {
|
|
84
|
+
return runtime.get();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
jni::local_ref<JavaScriptValue::javaobject>
|
|
88
|
+
JavaScriptRuntime::evaluateScript(const std::string &script) {
|
|
89
|
+
auto scriptBuffer = std::make_shared<jsi::StringBuffer>(script);
|
|
90
|
+
std::shared_ptr<jsi::Value> result;
|
|
91
|
+
try {
|
|
92
|
+
result = std::make_shared<jsi::Value>(
|
|
93
|
+
runtime->evaluateJavaScript(scriptBuffer, "<<evaluated>>")
|
|
94
|
+
);
|
|
95
|
+
} catch (const jsi::JSError &error) {
|
|
96
|
+
jni::throwNewJavaException(
|
|
97
|
+
JavaScriptEvaluateException::create(
|
|
98
|
+
error.getMessage(),
|
|
99
|
+
error.getStack()
|
|
100
|
+
).get()
|
|
101
|
+
);
|
|
102
|
+
} catch (const jsi::JSIException &error) {
|
|
103
|
+
jni::throwNewJavaException(
|
|
104
|
+
JavaScriptEvaluateException::create(
|
|
105
|
+
error.what(),
|
|
106
|
+
""
|
|
107
|
+
).get()
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return JavaScriptValue::newObjectCxxArgs(weak_from_this(), result);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
jni::local_ref<JavaScriptObject::javaobject> JavaScriptRuntime::global() {
|
|
115
|
+
auto global = std::make_shared<jsi::Object>(runtime->global());
|
|
116
|
+
return JavaScriptObject::newObjectCxxArgs(weak_from_this(), global);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
jni::local_ref<JavaScriptObject::javaobject> JavaScriptRuntime::createObject() {
|
|
120
|
+
auto newObject = std::make_shared<jsi::Object>(*runtime);
|
|
121
|
+
return JavaScriptObject::newObjectCxxArgs(weak_from_this(), newObject);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
void JavaScriptRuntime::drainJSEventLoop() {
|
|
125
|
+
while (!runtime->drainMicrotasks()) {}
|
|
126
|
+
}
|
|
127
|
+
} // namespace expo
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// Copyright © 2021-present 650 Industries, Inc. (aka Expo)
|
|
2
|
+
|
|
3
|
+
#pragma once
|
|
4
|
+
|
|
5
|
+
#include <jsi/jsi.h>
|
|
6
|
+
#include <fbjni/fbjni.h>
|
|
7
|
+
#include <ReactCommon/CallInvoker.h>
|
|
8
|
+
|
|
9
|
+
namespace jsi = facebook::jsi;
|
|
10
|
+
namespace jni = facebook::jni;
|
|
11
|
+
namespace react = facebook::react;
|
|
12
|
+
|
|
13
|
+
namespace expo {
|
|
14
|
+
class JavaScriptValue;
|
|
15
|
+
|
|
16
|
+
class JavaScriptObject;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Dummy CallInvoker that invokes everything immediately.
|
|
20
|
+
* Used in the test environment to check the async flow.
|
|
21
|
+
*/
|
|
22
|
+
class SyncCallInvoker : public react::CallInvoker {
|
|
23
|
+
public:
|
|
24
|
+
void invokeAsync(std::function<void()> &&func) override;
|
|
25
|
+
|
|
26
|
+
void invokeSync(std::function<void()> &&func) override;
|
|
27
|
+
|
|
28
|
+
~SyncCallInvoker() override = default;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* A wrapper for the jsi::Runtime.
|
|
33
|
+
* This class is used as a bridge between CPP and Kotlin and to encapsulate common runtime helper functions.
|
|
34
|
+
*
|
|
35
|
+
* Instances of this class should be managed using a shared smart pointer.
|
|
36
|
+
* To pass runtime information to all of `JavaScriptValue` and `JavaScriptObject` we use `weak_from_this()`
|
|
37
|
+
* that requires that the object is held via a smart pointer. Otherwise, `weak_from_this()` returns `nullptr`.
|
|
38
|
+
*/
|
|
39
|
+
class JavaScriptRuntime : public std::enable_shared_from_this<JavaScriptRuntime> {
|
|
40
|
+
public:
|
|
41
|
+
/**
|
|
42
|
+
* Initializes a runtime that is independent from React Native and its runtime initialization.
|
|
43
|
+
* This flow is mostly intended for tests. The JS call invoker is set to `SyncCallInvoker`.
|
|
44
|
+
*/
|
|
45
|
+
JavaScriptRuntime();
|
|
46
|
+
|
|
47
|
+
JavaScriptRuntime(
|
|
48
|
+
jsi::Runtime *runtime,
|
|
49
|
+
std::shared_ptr<react::CallInvoker> jsInvoker,
|
|
50
|
+
std::shared_ptr<react::CallInvoker> nativeInvoker
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Returns the underlying runtime object.
|
|
55
|
+
*/
|
|
56
|
+
jsi::Runtime *get();
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Evaluates given JavaScript source code.
|
|
60
|
+
* @throws if the input format is unknown, or evaluation causes an error,
|
|
61
|
+
* a jni::JniException<JavaScriptEvaluateException> will be thrown.
|
|
62
|
+
*/
|
|
63
|
+
jni::local_ref<jni::HybridClass<JavaScriptValue>::javaobject> evaluateScript(
|
|
64
|
+
const std::string &script
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Returns the runtime global object for use in Kotlin.
|
|
69
|
+
*/
|
|
70
|
+
jni::local_ref<jni::HybridClass<JavaScriptObject>::javaobject> global();
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Creates a new object for use in Kotlin.
|
|
74
|
+
*/
|
|
75
|
+
jni::local_ref<jni::HybridClass<JavaScriptObject>::javaobject> createObject();
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Drains the JavaScript VM internal Microtask (a.k.a. event loop) queue.
|
|
79
|
+
*/
|
|
80
|
+
void drainJSEventLoop();
|
|
81
|
+
|
|
82
|
+
std::shared_ptr<react::CallInvoker> jsInvoker;
|
|
83
|
+
std::shared_ptr<react::CallInvoker> nativeInvoker;
|
|
84
|
+
private:
|
|
85
|
+
std::shared_ptr<jsi::Runtime> runtime;
|
|
86
|
+
};
|
|
87
|
+
} // namespace expo
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
// Copyright © 2021-present 650 Industries, Inc. (aka Expo)
|
|
2
|
+
|
|
3
|
+
#include "JavaScriptValue.h"
|
|
4
|
+
|
|
5
|
+
#include "JavaScriptRuntime.h"
|
|
6
|
+
#include "JavaScriptObject.h"
|
|
7
|
+
|
|
8
|
+
namespace expo {
|
|
9
|
+
void JavaScriptValue::registerNatives() {
|
|
10
|
+
registerHybrid({
|
|
11
|
+
makeNativeMethod("kind", JavaScriptValue::jniKind),
|
|
12
|
+
makeNativeMethod("isNull", JavaScriptValue::isNull),
|
|
13
|
+
makeNativeMethod("isUndefined", JavaScriptValue::isUndefined),
|
|
14
|
+
makeNativeMethod("isBool", JavaScriptValue::isBool),
|
|
15
|
+
makeNativeMethod("isNumber", JavaScriptValue::isNumber),
|
|
16
|
+
makeNativeMethod("isString", JavaScriptValue::isString),
|
|
17
|
+
makeNativeMethod("isSymbol", JavaScriptValue::isSymbol),
|
|
18
|
+
makeNativeMethod("isFunction", JavaScriptValue::isFunction),
|
|
19
|
+
makeNativeMethod("isArray", JavaScriptValue::isArray),
|
|
20
|
+
makeNativeMethod("isObject", JavaScriptValue::isObject),
|
|
21
|
+
makeNativeMethod("getBool", JavaScriptValue::getBool),
|
|
22
|
+
makeNativeMethod("getDouble", JavaScriptValue::getDouble),
|
|
23
|
+
makeNativeMethod("getString", JavaScriptValue::jniGetString),
|
|
24
|
+
makeNativeMethod("getObject", JavaScriptValue::getObject),
|
|
25
|
+
makeNativeMethod("getArray", JavaScriptValue::getArray),
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
JavaScriptValue::JavaScriptValue(
|
|
30
|
+
std::weak_ptr<JavaScriptRuntime> runtime,
|
|
31
|
+
std::shared_ptr<jsi::Value> jsValue
|
|
32
|
+
) : runtimeHolder(std::move(runtime)), jsValue(std::move(jsValue)) {
|
|
33
|
+
assert(runtimeHolder.lock() != nullptr);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
std::shared_ptr<jsi::Value> JavaScriptValue::get() {
|
|
37
|
+
return jsValue;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
std::string JavaScriptValue::kind() {
|
|
41
|
+
if (isNull()) {
|
|
42
|
+
return "null";
|
|
43
|
+
}
|
|
44
|
+
if (isUndefined()) {
|
|
45
|
+
return "undefined";
|
|
46
|
+
}
|
|
47
|
+
if (isBool()) {
|
|
48
|
+
return "boolean";
|
|
49
|
+
}
|
|
50
|
+
if (isNumber()) {
|
|
51
|
+
return "number";
|
|
52
|
+
}
|
|
53
|
+
if (isString()) {
|
|
54
|
+
return "string";
|
|
55
|
+
}
|
|
56
|
+
if (isSymbol()) {
|
|
57
|
+
return "symbol";
|
|
58
|
+
}
|
|
59
|
+
if (isFunction()) {
|
|
60
|
+
return "function";
|
|
61
|
+
}
|
|
62
|
+
if (isArray()) {
|
|
63
|
+
return "array";
|
|
64
|
+
}
|
|
65
|
+
if (isObject()) {
|
|
66
|
+
return "object";
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// TODO(@lukmccall): maybe throw exception?
|
|
70
|
+
return "unknown";
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
bool JavaScriptValue::isNull() {
|
|
74
|
+
return jsValue->isNull();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
bool JavaScriptValue::isUndefined() {
|
|
78
|
+
return jsValue->isUndefined();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
bool JavaScriptValue::isBool() {
|
|
82
|
+
return jsValue->isBool();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
bool JavaScriptValue::isNumber() {
|
|
86
|
+
return jsValue->isNumber();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
bool JavaScriptValue::isString() {
|
|
90
|
+
return jsValue->isString();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
bool JavaScriptValue::isSymbol() {
|
|
94
|
+
return jsValue->isSymbol();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
bool JavaScriptValue::isFunction() {
|
|
98
|
+
if (jsValue->isObject()) {
|
|
99
|
+
auto runtime = runtimeHolder.lock();
|
|
100
|
+
assert(runtime != nullptr);
|
|
101
|
+
return jsValue->asObject(*runtime->get()).isFunction(*runtime->get());
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
bool JavaScriptValue::isArray() {
|
|
108
|
+
if (jsValue->isObject()) {
|
|
109
|
+
auto runtime = runtimeHolder.lock();
|
|
110
|
+
assert(runtime != nullptr);
|
|
111
|
+
return jsValue->asObject(*runtime->get()).isArray(*runtime->get());
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
bool JavaScriptValue::isObject() {
|
|
118
|
+
return jsValue->isObject();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
bool JavaScriptValue::getBool() {
|
|
122
|
+
return jsValue->getBool();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
double JavaScriptValue::getDouble() {
|
|
126
|
+
return jsValue->getNumber();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
std::string JavaScriptValue::getString() {
|
|
130
|
+
auto runtime = runtimeHolder.lock();
|
|
131
|
+
assert(runtime != nullptr);
|
|
132
|
+
return jsValue->getString(*runtime->get()).utf8(*runtime->get());
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
jni::local_ref<JavaScriptObject::javaobject> JavaScriptValue::getObject() {
|
|
136
|
+
auto runtime = runtimeHolder.lock();
|
|
137
|
+
assert(runtime != nullptr);
|
|
138
|
+
auto jsObject = std::make_shared<jsi::Object>(jsValue->getObject(*runtime->get()));
|
|
139
|
+
return JavaScriptObject::newObjectCxxArgs(runtimeHolder, jsObject);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
jni::local_ref<jni::JArrayClass<JavaScriptValue::javaobject>> JavaScriptValue::getArray() {
|
|
143
|
+
auto runtime = runtimeHolder.lock();
|
|
144
|
+
assert(runtime != nullptr);
|
|
145
|
+
|
|
146
|
+
auto jsArray = jsValue
|
|
147
|
+
->getObject(*runtime->get())
|
|
148
|
+
.asArray(*runtime->get());
|
|
149
|
+
size_t size = jsArray.size(*runtime->get());
|
|
150
|
+
|
|
151
|
+
auto result = jni::JArrayClass<JavaScriptValue::javaobject>::newArray(size);
|
|
152
|
+
for (size_t i = 0; i < size; i++) {
|
|
153
|
+
auto element = JavaScriptValue::newObjectCxxArgs(
|
|
154
|
+
runtimeHolder,
|
|
155
|
+
std::make_shared<jsi::Value>(jsArray.getValueAtIndex(*runtime->get(), i))
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
result->setElement(i, element.release());
|
|
159
|
+
}
|
|
160
|
+
return result;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
jni::local_ref<jstring> JavaScriptValue::jniKind() {
|
|
164
|
+
auto result = kind();
|
|
165
|
+
return jni::make_jstring(result);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
jni::local_ref<jstring> JavaScriptValue::jniGetString() {
|
|
169
|
+
auto result = getString();
|
|
170
|
+
return jni::make_jstring(result);
|
|
171
|
+
}
|
|
172
|
+
} // namespace expo
|