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.
Files changed (193) hide show
  1. package/CHANGELOG.md +33 -3
  2. package/README.md +3 -3
  3. package/android/CMakeLists.txt +163 -0
  4. package/android/build.gradle +343 -5
  5. package/android/src/main/cpp/CachedReferencesRegistry.cpp +65 -0
  6. package/android/src/main/cpp/CachedReferencesRegistry.h +80 -0
  7. package/android/src/main/cpp/Exceptions.cpp +22 -0
  8. package/android/src/main/cpp/Exceptions.h +38 -0
  9. package/android/src/main/cpp/ExpoModulesHostObject.cpp +47 -0
  10. package/android/src/main/cpp/ExpoModulesHostObject.h +32 -0
  11. package/android/src/main/cpp/JNIFunctionBody.cpp +44 -0
  12. package/android/src/main/cpp/JNIFunctionBody.h +50 -0
  13. package/android/src/main/cpp/JNIInjector.cpp +23 -0
  14. package/android/src/main/cpp/JSIInteropModuleRegistry.cpp +122 -0
  15. package/android/src/main/cpp/JSIInteropModuleRegistry.h +96 -0
  16. package/android/src/main/cpp/JSIObjectWrapper.h +33 -0
  17. package/android/src/main/cpp/JSITypeConverter.h +84 -0
  18. package/android/src/main/cpp/JavaScriptModuleObject.cpp +219 -0
  19. package/android/src/main/cpp/JavaScriptModuleObject.h +144 -0
  20. package/android/src/main/cpp/JavaScriptObject.cpp +125 -0
  21. package/android/src/main/cpp/JavaScriptObject.h +131 -0
  22. package/android/src/main/cpp/JavaScriptRuntime.cpp +127 -0
  23. package/android/src/main/cpp/JavaScriptRuntime.h +87 -0
  24. package/android/src/main/cpp/JavaScriptValue.cpp +172 -0
  25. package/android/src/main/cpp/JavaScriptValue.h +78 -0
  26. package/android/src/main/cpp/MethodMetadata.cpp +340 -0
  27. package/android/src/main/cpp/MethodMetadata.h +131 -0
  28. package/android/src/main/java/expo/modules/adapters/react/NativeModulesProxy.java +2 -0
  29. package/android/src/main/java/expo/modules/core/errors/ContextDestroyedException.kt +7 -0
  30. package/android/src/main/java/expo/modules/interfaces/permissions/Permissions.java +30 -0
  31. package/android/src/main/java/expo/modules/kotlin/AppContext.kt +98 -3
  32. package/android/src/main/java/expo/modules/kotlin/ConcatIterator.kt +18 -0
  33. package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +15 -12
  34. package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +45 -3
  35. package/android/src/main/java/expo/modules/kotlin/activityaware/AppCompatActivityAware.kt +49 -0
  36. package/android/src/main/java/expo/modules/kotlin/activityaware/AppCompatActivityAwareHelper.kt +43 -0
  37. package/android/src/main/java/expo/modules/kotlin/activityaware/OnActivityAvailableListener.kt +18 -0
  38. package/android/src/main/java/expo/modules/kotlin/activityresult/ActivityResultsManager.kt +99 -0
  39. package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultCaller.kt +25 -0
  40. package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultContract.kt +27 -0
  41. package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultFallbackCallback.kt +17 -0
  42. package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultLauncher.kt +30 -0
  43. package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultRegistry.kt +358 -0
  44. package/android/src/main/java/expo/modules/kotlin/activityresult/DataPersistor.kt +135 -0
  45. package/android/src/main/java/expo/modules/kotlin/defaultmodules/ErrorManagerModule.kt +2 -2
  46. package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +13 -0
  47. package/android/src/main/java/expo/modules/kotlin/exception/ExceptionDecorator.kt +2 -0
  48. package/android/src/main/java/expo/modules/kotlin/functions/AnyFunction.kt +53 -15
  49. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunction.kt +35 -7
  50. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionBuilder.kt +13 -121
  51. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionComponent.kt +21 -0
  52. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromiseComponent.kt +21 -0
  53. package/android/src/main/java/expo/modules/kotlin/functions/SuspendFunctionComponent.kt +63 -0
  54. package/android/src/main/java/expo/modules/kotlin/functions/SyncFunctionComponent.kt +36 -0
  55. package/android/src/main/java/expo/modules/kotlin/jni/CppType.kt +19 -0
  56. package/android/src/main/java/expo/modules/kotlin/jni/JNIFunctionBody.kt +39 -0
  57. package/android/src/main/java/expo/modules/kotlin/jni/JSIInteropModuleRegistry.kt +89 -0
  58. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptModuleObject.kt +46 -0
  59. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptObject.kt +113 -0
  60. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptValue.kt +35 -0
  61. package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +16 -6
  62. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +5 -500
  63. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +30 -5
  64. package/android/src/main/java/expo/modules/kotlin/objects/ObjectDefinitionBuilder.kt +271 -0
  65. package/android/src/main/java/expo/modules/kotlin/objects/ObjectDefinitionData.kt +21 -0
  66. package/android/src/main/java/expo/modules/kotlin/objects/PropertyComponent.kt +54 -0
  67. package/android/src/main/java/expo/modules/kotlin/objects/PropertyComponentBuilder.kt +32 -0
  68. package/android/src/main/java/expo/modules/kotlin/providers/AppContextProvider.kt +14 -0
  69. package/android/src/main/java/expo/modules/kotlin/providers/CurrentActivityProvider.kt +22 -0
  70. package/android/src/main/java/expo/modules/kotlin/records/RecordTypeConverter.kt +19 -2
  71. package/android/src/main/java/expo/modules/kotlin/types/AnyType.kt +3 -2
  72. package/android/src/main/java/expo/modules/kotlin/types/AnyTypeConverter.kt +36 -0
  73. package/android/src/main/java/expo/modules/kotlin/types/ArrayTypeConverter.kt +7 -2
  74. package/android/src/main/java/expo/modules/kotlin/types/BasicTypeConverters.kt +68 -20
  75. package/android/src/main/java/expo/modules/kotlin/types/EnumTypeConverter.kt +50 -22
  76. package/android/src/main/java/expo/modules/kotlin/types/ListTypeConverter.kt +18 -2
  77. package/android/src/main/java/expo/modules/kotlin/types/MapTypeConverter.kt +18 -2
  78. package/android/src/main/java/expo/modules/kotlin/types/PairTypeConverter.kt +17 -2
  79. package/android/src/main/java/expo/modules/kotlin/types/TypeConverter.kt +43 -3
  80. package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +12 -0
  81. package/android/src/main/java/expo/modules/kotlin/views/ViewGroupDefinitionBuilder.kt +0 -41
  82. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +0 -33
  83. package/build/NativeModulesProxy.native.d.ts.map +1 -1
  84. package/build/NativeModulesProxy.native.js +9 -3
  85. package/build/NativeModulesProxy.native.js.map +1 -1
  86. package/build/PermissionsInterface.d.ts +29 -0
  87. package/build/PermissionsInterface.d.ts.map +1 -1
  88. package/build/PermissionsInterface.js +9 -0
  89. package/build/PermissionsInterface.js.map +1 -1
  90. package/ios/AppDelegates/EXAppDelegatesLoader.m +1 -2
  91. package/ios/ExpoModulesCore.podspec +3 -2
  92. package/ios/JSI/EXJSIConversions.mm +6 -0
  93. package/ios/JSI/EXJSIInstaller.h +15 -21
  94. package/ios/JSI/EXJSIInstaller.mm +39 -3
  95. package/ios/JSI/EXJSIUtils.h +48 -3
  96. package/ios/JSI/EXJSIUtils.mm +88 -4
  97. package/ios/JSI/EXJavaScriptObject.h +11 -18
  98. package/ios/JSI/EXJavaScriptObject.mm +37 -18
  99. package/ios/JSI/EXJavaScriptRuntime.h +43 -9
  100. package/ios/JSI/EXJavaScriptRuntime.mm +70 -27
  101. package/ios/JSI/EXJavaScriptTypedArray.h +30 -0
  102. package/ios/JSI/EXJavaScriptTypedArray.mm +29 -0
  103. package/ios/JSI/EXJavaScriptValue.h +3 -2
  104. package/ios/JSI/EXJavaScriptValue.mm +17 -20
  105. package/ios/JSI/EXJavaScriptWeakObject.h +23 -0
  106. package/ios/JSI/EXJavaScriptWeakObject.mm +53 -0
  107. package/ios/JSI/EXObjectDeallocator.h +27 -0
  108. package/ios/JSI/ExpoModulesHostObject.h +3 -3
  109. package/ios/JSI/ExpoModulesHostObject.mm +4 -4
  110. package/ios/JSI/JavaScriptRuntime.swift +38 -1
  111. package/ios/JSI/JavaScriptValue.swift +7 -0
  112. package/ios/JSI/TypedArray.cpp +67 -0
  113. package/ios/JSI/TypedArray.h +46 -0
  114. package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +0 -11
  115. package/ios/NativeModulesProxy/EXNativeModulesProxy.h +17 -10
  116. package/ios/NativeModulesProxy/EXNativeModulesProxy.mm +86 -77
  117. package/ios/NativeModulesProxy/NativeModulesProxyModule.swift +17 -0
  118. package/ios/Services/EXReactNativeEventEmitter.h +2 -2
  119. package/ios/Services/EXReactNativeEventEmitter.m +11 -6
  120. package/ios/Swift/AppContext.swift +206 -28
  121. package/ios/Swift/Arguments/AnyArgument.swift +18 -0
  122. package/ios/Swift/Arguments/{Types/EnumArgumentType.swift → EnumArgument.swift} +2 -17
  123. package/ios/Swift/Classes/ClassComponent.swift +95 -0
  124. package/ios/Swift/Classes/ClassComponentElement.swift +33 -0
  125. package/ios/Swift/Classes/ClassComponentElementsBuilder.swift +34 -0
  126. package/ios/Swift/Classes/ClassComponentFactories.swift +96 -0
  127. package/ios/Swift/DynamicTypes/AnyDynamicType.swift +44 -0
  128. package/ios/Swift/DynamicTypes/DynamicArrayType.swift +56 -0
  129. package/ios/Swift/DynamicTypes/DynamicConvertibleType.swift +27 -0
  130. package/ios/Swift/DynamicTypes/DynamicEnumType.swift +27 -0
  131. package/ios/Swift/DynamicTypes/DynamicOptionalType.swift +63 -0
  132. package/ios/Swift/DynamicTypes/DynamicRawType.swift +33 -0
  133. package/ios/Swift/DynamicTypes/DynamicSharedObjectType.swift +37 -0
  134. package/ios/Swift/DynamicTypes/DynamicType.swift +39 -0
  135. package/ios/Swift/DynamicTypes/DynamicTypedArrayType.swift +46 -0
  136. package/ios/Swift/Exceptions/ChainableException.swift +3 -3
  137. package/ios/Swift/Exceptions/CodedError.swift +1 -1
  138. package/ios/Swift/Exceptions/Exception.swift +8 -6
  139. package/ios/Swift/Exceptions/UnexpectedException.swift +2 -1
  140. package/ios/Swift/ExpoBridgeModule.m +5 -0
  141. package/ios/Swift/ExpoBridgeModule.swift +79 -0
  142. package/ios/Swift/Functions/AnyFunction.swift +33 -31
  143. package/ios/Swift/Functions/AsyncFunctionComponent.swift +196 -59
  144. package/ios/Swift/Functions/SyncFunctionComponent.swift +142 -58
  145. package/ios/Swift/JavaScriptUtils.swift +32 -57
  146. package/ios/Swift/Logging/LogHandlers.swift +39 -0
  147. package/ios/Swift/Logging/LogType.swift +62 -0
  148. package/ios/Swift/Logging/Logger.swift +201 -0
  149. package/ios/Swift/ModuleHolder.swift +19 -54
  150. package/ios/Swift/ModuleRegistry.swift +7 -1
  151. package/ios/Swift/Modules/AnyModule.swift +3 -3
  152. package/ios/Swift/ModulesProvider.swift +2 -0
  153. package/ios/Swift/Objects/JavaScriptObjectBuilder.swift +37 -0
  154. package/ios/Swift/Objects/ObjectDefinition.swift +74 -1
  155. package/ios/Swift/Objects/ObjectDefinitionComponents.swift +77 -68
  156. package/ios/Swift/Objects/PropertyComponent.swift +147 -0
  157. package/ios/Swift/Promise.swift +17 -4
  158. package/ios/Swift/Records/Field.swift +2 -2
  159. package/ios/Swift/SharedObjects/SharedObject.swift +20 -0
  160. package/ios/Swift/SharedObjects/SharedObjectRegistry.swift +129 -0
  161. package/ios/Swift/TypedArrays/AnyTypedArray.swift +11 -0
  162. package/ios/Swift/TypedArrays/ConcreteTypedArrays.swift +56 -0
  163. package/ios/Swift/TypedArrays/GenericTypedArray.swift +49 -0
  164. package/ios/Swift/TypedArrays/TypedArray.swift +80 -0
  165. package/ios/Swift/Utilities.swift +28 -0
  166. package/ios/Swift/Views/ConcreteViewProp.swift +3 -3
  167. package/ios/Swift/Views/ViewManagerDefinitionComponents.swift +2 -2
  168. package/ios/Tests/ClassComponentSpec.swift +210 -0
  169. package/ios/Tests/DynamicTypeSpec.swift +336 -0
  170. package/ios/Tests/EnumArgumentSpec.swift +48 -0
  171. package/ios/Tests/ExpoModulesSpec.swift +17 -3
  172. package/ios/Tests/FunctionSpec.swift +167 -118
  173. package/ios/Tests/Mocks/ModuleMocks.swift +1 -1
  174. package/ios/Tests/PropertyComponentSpec.swift +95 -0
  175. package/ios/Tests/SharedObjectRegistrySpec.swift +109 -0
  176. package/ios/Tests/TypedArraysSpec.swift +136 -0
  177. package/package.json +2 -2
  178. package/src/NativeModulesProxy.native.ts +13 -3
  179. package/src/PermissionsInterface.ts +29 -0
  180. package/src/ts-declarations/ExpoModules.d.ts +7 -0
  181. package/tsconfig.json +1 -1
  182. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromise.kt +0 -15
  183. package/android/src/main/java/expo/modules/kotlin/functions/AsyncSuspendFunction.kt +0 -36
  184. package/ios/Swift/Arguments/AnyArgumentType.swift +0 -13
  185. package/ios/Swift/Arguments/ArgumentType.swift +0 -28
  186. package/ios/Swift/Arguments/Types/ArrayArgumentType.swift +0 -42
  187. package/ios/Swift/Arguments/Types/ConvertibleArgumentType.swift +0 -16
  188. package/ios/Swift/Arguments/Types/OptionalArgumentType.swift +0 -49
  189. package/ios/Swift/Arguments/Types/PromiseArgumentType.swift +0 -15
  190. package/ios/Swift/Arguments/Types/RawArgumentType.swift +0 -25
  191. package/ios/Swift/Functions/ConcreteFunction.swift +0 -103
  192. package/ios/Swift/SwiftInteropBridge.swift +0 -155
  193. 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