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,65 @@
1
+ // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2
+
3
+ #include "CachedReferencesRegistry.h"
4
+
5
+ #include <utility>
6
+
7
+ namespace expo {
8
+ std::shared_ptr<CachedReferencesRegistry> CachedReferencesRegistry::instance() {
9
+ static std::shared_ptr<CachedReferencesRegistry> singleton{new CachedReferencesRegistry};
10
+ return singleton;
11
+ }
12
+
13
+ void CachedReferencesRegistry::loadJClasses(JNIEnv *env) {
14
+ loadJClass(env, "java/lang/Double", {
15
+ {"<init>", "(D)V"}
16
+ });
17
+
18
+ loadJClass(env, "java/lang/Boolean", {
19
+ {"<init>", "(Z)V"}
20
+ });
21
+
22
+ loadJClass(env, "com/facebook/react/bridge/PromiseImpl", {
23
+ {"<init>", "(Lcom/facebook/react/bridge/Callback;Lcom/facebook/react/bridge/Callback;)V"}
24
+ });
25
+ }
26
+
27
+ void CachedReferencesRegistry::loadJClass(
28
+ JNIEnv *env,
29
+ const std::string &name,
30
+ const std::vector<std::pair<std::string, std::string>> &methodsNames
31
+ ) {
32
+ // Note this clazz variable points to a leaked global reference.
33
+ // This is appropriate for classes that are never unloaded which is any class in an Android app.
34
+ auto clazz = (jclass) env->NewGlobalRef(env->FindClass(name.c_str()));
35
+
36
+ MethodHashMap methods;
37
+ methods.reserve(methodsNames.size());
38
+
39
+ for (auto &method: methodsNames) {
40
+ methods.insert(
41
+ {method, env->GetMethodID(clazz, method.first.c_str(), method.second.c_str())}
42
+ );
43
+ }
44
+
45
+ jClassRegistry.insert(
46
+ {name, CachedJClass(clazz, std::move(methods))}
47
+ );
48
+ }
49
+
50
+ CachedReferencesRegistry::CachedJClass &CachedReferencesRegistry::getJClass(
51
+ const std::string &className
52
+ ) {
53
+ return jClassRegistry.at(className);
54
+ }
55
+
56
+ jmethodID CachedReferencesRegistry::CachedJClass::getMethod(const std::string &name,
57
+ const std::string &signature) {
58
+ return methods.at({name, signature});
59
+ }
60
+
61
+ CachedReferencesRegistry::CachedJClass::CachedJClass(
62
+ jclass clazz,
63
+ MethodHashMap methods
64
+ ) : clazz(clazz), methods(std::move(methods)) {}
65
+ } // namespace expo
@@ -0,0 +1,80 @@
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 "boost/functional/hash.hpp"
8
+
9
+ #include <memory>
10
+ #include <unordered_map>
11
+
12
+ namespace jni = facebook::jni;
13
+ namespace jsi = facebook::jsi;
14
+
15
+ namespace expo {
16
+ using MethodHashMap = std::unordered_map<
17
+ std::pair<std::string, std::string>,
18
+ jmethodID,
19
+ boost::hash<std::pair<std::string, std::string>>
20
+ >;
21
+
22
+ /**
23
+ * Singleton registry used to store references to often used Java classes.
24
+ *
25
+ * TODO(@lukmccall): also store reference to jsi objects like `Promise`.
26
+ */
27
+ class CachedReferencesRegistry {
28
+ public:
29
+ /**
30
+ * An entry in the Java class registry.
31
+ */
32
+ class CachedJClass {
33
+ public:
34
+ CachedJClass(jclass clazz, MethodHashMap methods);
35
+
36
+ /**
37
+ * A bare reference to the class object.
38
+ */
39
+ jclass clazz;
40
+
41
+ /**
42
+ * Returns a cached method id for provided method name and signature.
43
+ */
44
+ jmethodID getMethod(const std::string &name, const std::string &signature);
45
+
46
+ private:
47
+ MethodHashMap methods;
48
+ };
49
+
50
+ CachedReferencesRegistry(CachedReferencesRegistry const &) = delete;
51
+
52
+ CachedReferencesRegistry &operator=(CachedReferencesRegistry const &) = delete;
53
+
54
+ /**
55
+ * Gets a singleton instance
56
+ */
57
+ static std::shared_ptr<CachedReferencesRegistry> instance();
58
+
59
+ /**
60
+ * Gets a cached Java class entry.
61
+ */
62
+ CachedJClass &getJClass(const std::string &className);
63
+
64
+ /**
65
+ * Loads predefined set of Java classes and stores them
66
+ */
67
+ void loadJClasses(JNIEnv *env);
68
+
69
+ private:
70
+ CachedReferencesRegistry() = default;
71
+
72
+ std::unordered_map<std::string, CachedJClass> jClassRegistry;
73
+
74
+ void loadJClass(
75
+ JNIEnv *env,
76
+ const std::string &name,
77
+ const std::vector<std::pair<std::string, std::string>> &methods
78
+ );
79
+ };
80
+ } // namespace expo
@@ -0,0 +1,22 @@
1
+ // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2
+
3
+ #include "Exceptions.h"
4
+
5
+ namespace jni = facebook::jni;
6
+
7
+ namespace expo {
8
+
9
+ jni::local_ref<CodedException> CodedException::create(const std::string &message) {
10
+ return CodedException::newInstance(jni::make_jstring(message));
11
+ }
12
+
13
+ jni::local_ref<JavaScriptEvaluateException> JavaScriptEvaluateException::create(
14
+ const std::string &message,
15
+ const std::string &jsStack
16
+ ) {
17
+ return JavaScriptEvaluateException::newInstance(
18
+ jni::make_jstring(message),
19
+ jni::make_jstring(jsStack)
20
+ );
21
+ }
22
+ } // namespace expo
@@ -0,0 +1,38 @@
1
+ // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2
+
3
+ #pragma once
4
+
5
+ #include <fbjni/fbjni.h>
6
+
7
+ namespace jni = facebook::jni;
8
+
9
+ namespace expo {
10
+ /**
11
+ * A convenient wrapper for the Kotlin CodedException.
12
+ * It can be used with the `jni::throwNewJavaException` function to throw a cpp exception that
13
+ * will be automatically changed to the corresponding Java/Kotlin exception.
14
+ * `jni::throwNewJavaException` creates and throws a C++ exception which wraps a Java exception,
15
+ * so the C++ flow is interrupted. Then, when translatePendingCppExceptionToJavaException
16
+ * is called at the topmost level of the native stack, the wrapped Java exception is thrown to the java caller.
17
+ */
18
+ class CodedException : public jni::JavaClass<CodedException, jni::JThrowable> {
19
+ public:
20
+ static auto constexpr kJavaDescriptor = "Lexpo/modules/kotlin/exception/CodedException;";
21
+
22
+ static jni::local_ref<CodedException> create(const std::string &message);
23
+ };
24
+
25
+ /**
26
+ * A convenient wrapper for the Kotlin JavaScriptEvaluateException.
27
+ */
28
+ class JavaScriptEvaluateException
29
+ : public jni::JavaClass<JavaScriptEvaluateException, CodedException> {
30
+ public:
31
+ static auto constexpr kJavaDescriptor = "Lexpo/modules/kotlin/exception/JavaScriptEvaluateException;";
32
+
33
+ static jni::local_ref<JavaScriptEvaluateException> create(
34
+ const std::string &message,
35
+ const std::string &jsStack
36
+ );
37
+ };
38
+ } // namespace expo
@@ -0,0 +1,47 @@
1
+ // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2
+
3
+ #include "ExpoModulesHostObject.h"
4
+
5
+ #include <folly/dynamic.h>
6
+ #include <jsi/JSIDynamic.h>
7
+
8
+ namespace jsi = facebook::jsi;
9
+
10
+ namespace expo {
11
+
12
+ ExpoModulesHostObject::ExpoModulesHostObject(JSIInteropModuleRegistry *installer)
13
+ : installer(installer) {}
14
+
15
+ jsi::Value ExpoModulesHostObject::get(jsi::Runtime &runtime, const jsi::PropNameID &name) {
16
+ auto cName = name.utf8(runtime);
17
+ auto module = installer->getModule(cName);
18
+ if (module == nullptr) {
19
+ return jsi::Value::undefined();
20
+ }
21
+
22
+ module->cthis()->jsiInteropModuleRegistry = installer;
23
+ auto jsiObject = module->cthis()->getJSIObject(runtime);
24
+ return jsi::Value(runtime, *jsiObject);
25
+ }
26
+
27
+ void ExpoModulesHostObject::set(jsi::Runtime &runtime, const jsi::PropNameID &name,
28
+ const jsi::Value &value) {
29
+ throw jsi::JSError(
30
+ runtime,
31
+ "RuntimeError: Cannot override the host object for expo module '" + name.utf8(runtime) + "'"
32
+ );
33
+ }
34
+
35
+ std::vector<jsi::PropNameID> ExpoModulesHostObject::getPropertyNames(jsi::Runtime &rt) {
36
+ auto names = installer->getModulesName();
37
+ size_t size = names->size();
38
+ std::vector<jsi::PropNameID> result;
39
+ result.reserve(size);
40
+ for (int i = 0; i < size; i++) {
41
+ result.push_back(
42
+ jsi::PropNameID::forUtf8(rt, names->getElement(i)->toStdString())
43
+ );
44
+ }
45
+ return result;
46
+ }
47
+ } // namespace expo
@@ -0,0 +1,32 @@
1
+ // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2
+
3
+ #pragma once
4
+
5
+ #include "JSIInteropModuleRegistry.h"
6
+
7
+ #include <jsi/jsi.h>
8
+
9
+ #include <vector>
10
+
11
+ namespace jsi = facebook::jsi;
12
+
13
+ namespace expo {
14
+ /**
15
+ * An entry point to all exported functionalities like modules.
16
+ *
17
+ * An instance of this class will be added to the JS global object.
18
+ */
19
+ class ExpoModulesHostObject : public jsi::HostObject {
20
+ public:
21
+ ExpoModulesHostObject(JSIInteropModuleRegistry *installer);
22
+
23
+ jsi::Value get(jsi::Runtime &, const jsi::PropNameID &name) override;
24
+
25
+ void set(jsi::Runtime &, const jsi::PropNameID &name, const jsi::Value &value) override;
26
+
27
+ std::vector<jsi::PropNameID> getPropertyNames(jsi::Runtime &rt) override;
28
+
29
+ private:
30
+ JSIInteropModuleRegistry *installer;
31
+ };
32
+ } // namespace expo
@@ -0,0 +1,44 @@
1
+ // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2
+
3
+ #include "JNIFunctionBody.h"
4
+
5
+ namespace jni = facebook::jni;
6
+ namespace react = facebook::react;
7
+
8
+ namespace expo {
9
+ jni::local_ref<react::ReadableNativeArray::javaobject>
10
+ JNIFunctionBody::invoke(jni::local_ref<jni::JArrayClass<jobject>> &&args) {
11
+ // Do NOT use getClass here!
12
+ // Method obtained from `getClass` will point to the overridden version of the method.
13
+ // Because of that, it can't be cached - we will try to invoke the nonexistent method
14
+ // if we receive an object of a different class than the one used to obtain the method id.
15
+ // The only cacheable method id can be obtain from the base class.
16
+ static const auto method = jni::findClassLocal("expo/modules/kotlin/jni/JNIFunctionBody")
17
+ ->getMethod<
18
+ react::ReadableNativeArray::javaobject(jni::local_ref<jni::JArrayClass<jobject>>)
19
+ >(
20
+ "invoke"
21
+ );
22
+
23
+ return method(this->self(), args);
24
+ }
25
+
26
+ void JNIAsyncFunctionBody::invoke(
27
+ jni::local_ref<jni::JArrayClass<jobject>> &&args,
28
+ jobject promise
29
+ ) {
30
+ // Do NOT use getClass here!
31
+ // Method obtained from `getClass` will point to the overridden version of the method.
32
+ // Because of that, it can't be cached - we will try to invoke the nonexistent method
33
+ // if we receive an object of a different class than the one used to obtain the method id.
34
+ // The only cacheable method id can be obtain from the base class.
35
+ static const auto method = jni::findClassLocal("expo/modules/kotlin/jni/JNIAsyncFunctionBody")
36
+ ->getMethod<
37
+ void(jni::local_ref<jni::JArrayClass<jobject>>, jobject)
38
+ >(
39
+ "invoke"
40
+ );
41
+
42
+ method(this->self(), args, promise);
43
+ }
44
+ } // namespace expo
@@ -0,0 +1,50 @@
1
+ // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2
+
3
+ #pragma once
4
+
5
+ #include <fbjni/fbjni.h>
6
+ #include <react/jni/ReadableNativeArray.h>
7
+
8
+ namespace jni = facebook::jni;
9
+ namespace react = facebook::react;
10
+
11
+ namespace expo {
12
+ /**
13
+ * A CPP part of the expo.modules.kotlin.jni.JNIFunctionBody class.
14
+ * It represents the Kotlin's promise-less function.
15
+ */
16
+ class JNIFunctionBody : public jni::JavaClass<JNIFunctionBody> {
17
+ public:
18
+ static auto constexpr kJavaDescriptor = "Lexpo/modules/kotlin/jni/JNIFunctionBody;";
19
+
20
+ /**
21
+ * Invokes a Kotlin's implementation of this function.
22
+ *
23
+ * @param args
24
+ * @return result of the Kotlin function
25
+ */
26
+ jni::local_ref<react::ReadableNativeArray::javaobject> invoke(
27
+ jni::local_ref<jni::JArrayClass<jobject>> &&args
28
+ );
29
+ };
30
+
31
+ /**
32
+ * A CPP part of the expo.modules.kotlin.jni.JNIAsyncFunctionBody class.
33
+ * It represents the Kotlin's promise function.
34
+ */
35
+ class JNIAsyncFunctionBody : public jni::JavaClass<JNIAsyncFunctionBody> {
36
+ public:
37
+ static auto constexpr kJavaDescriptor = "Lexpo/modules/kotlin/jni/JNIAsyncFunctionBody;";
38
+
39
+ /**
40
+ * Invokes a Kotlin's implementation of this async function.
41
+ *
42
+ * @param args
43
+ * @param promise that will be resolve or rejected in the Kotlin's implementation
44
+ */
45
+ void invoke(
46
+ jni::local_ref<jni::JArrayClass<jobject>> &&args,
47
+ jobject promise
48
+ );
49
+ };
50
+ } // namespace expo
@@ -0,0 +1,23 @@
1
+ // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2
+
3
+ #include "JSIInteropModuleRegistry.h"
4
+ #include "JavaScriptModuleObject.h"
5
+ #include "JavaScriptValue.h"
6
+ #include "JavaScriptObject.h"
7
+ #include "CachedReferencesRegistry.h"
8
+
9
+ #include <jni.h>
10
+ #include <fbjni/fbjni.h>
11
+
12
+ // Install all jni bindings
13
+ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
14
+ return facebook::jni::initialize(vm, [] {
15
+ // Loads references to often use Java classes
16
+ expo::CachedReferencesRegistry::instance()->loadJClasses(jni::Environment::current());
17
+
18
+ expo::JSIInteropModuleRegistry::registerNatives();
19
+ expo::JavaScriptModuleObject::registerNatives();
20
+ expo::JavaScriptValue::registerNatives();
21
+ expo::JavaScriptObject::registerNatives();
22
+ });
23
+ }
@@ -0,0 +1,122 @@
1
+ // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2
+
3
+ #include "JSIInteropModuleRegistry.h"
4
+ #include "ExpoModulesHostObject.h"
5
+
6
+ #include <fbjni/detail/Meta.h>
7
+ #include <fbjni/fbjni.h>
8
+
9
+ #include <memory>
10
+
11
+ namespace jni = facebook::jni;
12
+ namespace jsi = facebook::jsi;
13
+
14
+ namespace expo {
15
+ jni::local_ref<JSIInteropModuleRegistry::jhybriddata>
16
+ JSIInteropModuleRegistry::initHybrid(jni::alias_ref<jhybridobject> jThis) {
17
+ return makeCxxInstance(jThis);
18
+ }
19
+
20
+ void JSIInteropModuleRegistry::registerNatives() {
21
+ registerHybrid({
22
+ makeNativeMethod("initHybrid", JSIInteropModuleRegistry::initHybrid),
23
+ makeNativeMethod("installJSI", JSIInteropModuleRegistry::installJSI),
24
+ makeNativeMethod("installJSIForTests",
25
+ JSIInteropModuleRegistry::installJSIForTests),
26
+ makeNativeMethod("evaluateScript", JSIInteropModuleRegistry::evaluateScript),
27
+ makeNativeMethod("global", JSIInteropModuleRegistry::global),
28
+ makeNativeMethod("createObject", JSIInteropModuleRegistry::createObject),
29
+ makeNativeMethod("drainJSEventLoop", JSIInteropModuleRegistry::drainJSEventLoop),
30
+ });
31
+ }
32
+
33
+ JSIInteropModuleRegistry::JSIInteropModuleRegistry(jni::alias_ref<jhybridobject> jThis)
34
+ : javaPart_(jni::make_global(jThis)) {}
35
+
36
+ void JSIInteropModuleRegistry::installJSI(
37
+ jlong jsRuntimePointer,
38
+ jni::alias_ref<react::CallInvokerHolder::javaobject> jsInvokerHolder,
39
+ jni::alias_ref<react::CallInvokerHolder::javaobject> nativeInvokerHolder
40
+ ) {
41
+ auto runtime = reinterpret_cast<jsi::Runtime *>(jsRuntimePointer);
42
+ runtimeHolder = std::make_shared<JavaScriptRuntime>(
43
+ runtime,
44
+ jsInvokerHolder->cthis()->getCallInvoker(),
45
+ nativeInvokerHolder->cthis()->getCallInvoker()
46
+ );
47
+
48
+ auto expoModules = std::make_shared<ExpoModulesHostObject>(this);
49
+ auto expoModulesObject = jsi::Object::createFromHostObject(*runtime, expoModules);
50
+
51
+ runtime
52
+ ->global()
53
+ .setProperty(
54
+ *runtime,
55
+ "ExpoModules",
56
+ std::move(expoModulesObject)
57
+ );
58
+ }
59
+
60
+ void JSIInteropModuleRegistry::installJSIForTests() {
61
+ runtimeHolder = std::make_shared<JavaScriptRuntime>();
62
+ jsi::Runtime &jsiRuntime = *runtimeHolder->get();
63
+
64
+ auto expoModules = std::make_shared<ExpoModulesHostObject>(this);
65
+ auto expoModulesObject = jsi::Object::createFromHostObject(jsiRuntime, expoModules);
66
+
67
+ jsiRuntime
68
+ .global()
69
+ .setProperty(
70
+ jsiRuntime,
71
+ "ExpoModules",
72
+ std::move(expoModulesObject)
73
+ );
74
+ }
75
+
76
+ jni::local_ref<JavaScriptModuleObject::javaobject>
77
+ JSIInteropModuleRegistry::callGetJavaScriptModuleObjectMethod(const std::string &moduleName) const {
78
+ const static auto method = expo::JSIInteropModuleRegistry::javaClassLocal()
79
+ ->getMethod<jni::local_ref<JavaScriptModuleObject::javaobject>(
80
+ std::string)>(
81
+ "getJavaScriptModuleObject"
82
+ );
83
+
84
+ return method(javaPart_, moduleName);
85
+ }
86
+
87
+ jni::local_ref<jni::JArrayClass<jni::JString>>
88
+ JSIInteropModuleRegistry::callGetJavaScriptModulesNames() const {
89
+ const static auto method = expo::JSIInteropModuleRegistry::javaClassLocal()
90
+ ->getMethod<jni::local_ref<jni::JArrayClass<jni::JString>>()>(
91
+ "getJavaScriptModulesName"
92
+ );
93
+ return method(javaPart_);
94
+ }
95
+
96
+ jni::local_ref<JavaScriptModuleObject::javaobject>
97
+ JSIInteropModuleRegistry::getModule(const std::string &moduleName) const {
98
+ return callGetJavaScriptModuleObjectMethod(moduleName);
99
+ }
100
+
101
+ jni::local_ref<jni::JArrayClass<jni::JString>> JSIInteropModuleRegistry::getModulesName() const {
102
+ return callGetJavaScriptModulesNames();
103
+ }
104
+
105
+ jni::local_ref<JavaScriptValue::javaobject> JSIInteropModuleRegistry::evaluateScript(
106
+ jni::JString script
107
+ ) {
108
+ return runtimeHolder->evaluateScript(script.toStdString());
109
+ }
110
+
111
+ jni::local_ref<JavaScriptObject::javaobject> JSIInteropModuleRegistry::global() {
112
+ return runtimeHolder->global();
113
+ }
114
+
115
+ jni::local_ref<JavaScriptObject::javaobject> JSIInteropModuleRegistry::createObject() {
116
+ return runtimeHolder->createObject();
117
+ }
118
+
119
+ void JSIInteropModuleRegistry::drainJSEventLoop() {
120
+ runtimeHolder->drainJSEventLoop();
121
+ }
122
+ } // namespace expo
@@ -0,0 +1,96 @@
1
+ // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2
+
3
+ #pragma once
4
+
5
+ #include "JavaScriptRuntime.h"
6
+ #include "JavaScriptModuleObject.h"
7
+ #include "JavaScriptValue.h"
8
+ #include "JavaScriptObject.h"
9
+
10
+ #include <fbjni/fbjni.h>
11
+ #include <jsi/jsi.h>
12
+ #include <ReactCommon/CallInvokerHolder.h>
13
+ #include <ReactCommon/CallInvoker.h>
14
+
15
+ #include <memory>
16
+
17
+ namespace jni = facebook::jni;
18
+ namespace jsi = facebook::jsi;
19
+ namespace react = facebook::react;
20
+
21
+ namespace expo {
22
+ /**
23
+ * A JNI wrapper to initialize CPP part of modules and access all data from the module registry.
24
+ */
25
+ class JSIInteropModuleRegistry : public jni::HybridClass<JSIInteropModuleRegistry> {
26
+ public:
27
+ static auto constexpr
28
+ kJavaDescriptor = "Lexpo/modules/kotlin/jni/JSIInteropModuleRegistry;";
29
+ static auto constexpr TAG = "JSIInteropModuleRegistry";
30
+
31
+ static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jhybridobject> jThis);
32
+
33
+ static void registerNatives();
34
+
35
+ /**
36
+ * Initializes the `ExpoModulesHostObject` and adds it to the global object.
37
+ */
38
+ void installJSI(
39
+ jlong jsRuntimePointer,
40
+ jni::alias_ref<react::CallInvokerHolder::javaobject> jsInvokerHolder,
41
+ jni::alias_ref<react::CallInvokerHolder::javaobject> nativeInvokerHolder
42
+ );
43
+
44
+ /**
45
+ * Initializes the test runtime. Shouldn't be used in the production.
46
+ */
47
+ void installJSIForTests();
48
+
49
+ /**
50
+ * Gets a module for a given name. It will throw an exception if the module doesn't exist.
51
+ *
52
+ * @param moduleName
53
+ * @return An instance of `JavaScriptModuleObject`
54
+ */
55
+ jni::local_ref<JavaScriptModuleObject::javaobject> getModule(const std::string &moduleName) const;
56
+
57
+ /**
58
+ * Gets names of all available modules.
59
+ */
60
+ jni::local_ref<jni::JArrayClass<jni::JString>> getModulesName() const;
61
+
62
+ /**
63
+ * Exposes a `JavaScriptRuntime::evaluateScript` function to Kotlin
64
+ */
65
+ jni::local_ref<JavaScriptValue::javaobject> evaluateScript(jni::JString script);
66
+
67
+ /**
68
+ * Exposes a `JavaScriptRuntime::global` function to Kotlin
69
+ */
70
+ jni::local_ref<JavaScriptObject::javaobject> global();
71
+
72
+ /**
73
+ * Exposes a `JavaScriptRuntime::createObject` function to Kotlin
74
+ */
75
+ jni::local_ref<JavaScriptObject::javaobject> createObject();
76
+
77
+ /**
78
+ * Exposes a `JavaScriptRuntime::drainJSEventLoop` function to Kotlin
79
+ */
80
+ void drainJSEventLoop();
81
+
82
+ std::shared_ptr<react::CallInvoker> jsInvoker;
83
+ std::shared_ptr<react::CallInvoker> nativeInvoker;
84
+ std::shared_ptr<JavaScriptRuntime> runtimeHolder;
85
+ private:
86
+ friend HybridBase;
87
+ jni::global_ref<JSIInteropModuleRegistry::javaobject> javaPart_;
88
+
89
+ explicit JSIInteropModuleRegistry(jni::alias_ref<jhybridobject> jThis);
90
+
91
+ inline jni::local_ref<JavaScriptModuleObject::javaobject>
92
+ callGetJavaScriptModuleObjectMethod(const std::string &moduleName) const;
93
+
94
+ inline jni::local_ref<jni::JArrayClass<jni::JString>> callGetJavaScriptModulesNames() const;
95
+ };
96
+ } // namespace expo
@@ -0,0 +1,33 @@
1
+ // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2
+
3
+ #pragma once
4
+
5
+ #include <jsi/jsi.h>
6
+
7
+ #include <memory>
8
+
9
+ namespace jsi = facebook::jsi;
10
+
11
+ namespace expo {
12
+ /**
13
+ * An interface for classes which wrap jsi::Object.
14
+ */
15
+ class JSIObjectWrapper {
16
+ public:
17
+ /**
18
+ * @return a pointer to the underlying jsi::Object.
19
+ */
20
+ virtual std::shared_ptr<jsi::Object> get() = 0;
21
+ };
22
+
23
+ /**
24
+ * An interface for classes which wrap jsi::Value.
25
+ */
26
+ class JSIValueWrapper {
27
+ public:
28
+ /**
29
+ * @return a pointer to the underlying jsi::Value.
30
+ */
31
+ virtual std::shared_ptr<jsi::Value> get() = 0;
32
+ };
33
+ } // namespace expo