expo-modules-core 0.9.2 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -3
- package/README.md +3 -3
- package/android/CMakeLists.txt +163 -0
- package/android/build.gradle +343 -5
- package/android/src/main/cpp/CachedReferencesRegistry.cpp +65 -0
- package/android/src/main/cpp/CachedReferencesRegistry.h +80 -0
- package/android/src/main/cpp/Exceptions.cpp +22 -0
- package/android/src/main/cpp/Exceptions.h +38 -0
- package/android/src/main/cpp/ExpoModulesHostObject.cpp +47 -0
- package/android/src/main/cpp/ExpoModulesHostObject.h +32 -0
- package/android/src/main/cpp/JNIFunctionBody.cpp +44 -0
- package/android/src/main/cpp/JNIFunctionBody.h +50 -0
- package/android/src/main/cpp/JNIInjector.cpp +23 -0
- package/android/src/main/cpp/JSIInteropModuleRegistry.cpp +122 -0
- package/android/src/main/cpp/JSIInteropModuleRegistry.h +96 -0
- package/android/src/main/cpp/JSIObjectWrapper.h +33 -0
- package/android/src/main/cpp/JSITypeConverter.h +84 -0
- package/android/src/main/cpp/JavaScriptModuleObject.cpp +219 -0
- package/android/src/main/cpp/JavaScriptModuleObject.h +144 -0
- package/android/src/main/cpp/JavaScriptObject.cpp +125 -0
- package/android/src/main/cpp/JavaScriptObject.h +131 -0
- package/android/src/main/cpp/JavaScriptRuntime.cpp +127 -0
- package/android/src/main/cpp/JavaScriptRuntime.h +87 -0
- package/android/src/main/cpp/JavaScriptValue.cpp +172 -0
- package/android/src/main/cpp/JavaScriptValue.h +78 -0
- package/android/src/main/cpp/MethodMetadata.cpp +340 -0
- package/android/src/main/cpp/MethodMetadata.h +131 -0
- package/android/src/main/java/expo/modules/adapters/react/NativeModulesProxy.java +2 -0
- package/android/src/main/java/expo/modules/core/errors/ContextDestroyedException.kt +7 -0
- package/android/src/main/java/expo/modules/interfaces/permissions/Permissions.java +30 -0
- package/android/src/main/java/expo/modules/kotlin/AppContext.kt +98 -3
- package/android/src/main/java/expo/modules/kotlin/ConcatIterator.kt +18 -0
- package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +15 -12
- package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +45 -3
- package/android/src/main/java/expo/modules/kotlin/activityaware/AppCompatActivityAware.kt +49 -0
- package/android/src/main/java/expo/modules/kotlin/activityaware/AppCompatActivityAwareHelper.kt +43 -0
- package/android/src/main/java/expo/modules/kotlin/activityaware/OnActivityAvailableListener.kt +18 -0
- package/android/src/main/java/expo/modules/kotlin/activityresult/ActivityResultsManager.kt +99 -0
- package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultCaller.kt +25 -0
- package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultContract.kt +27 -0
- package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultFallbackCallback.kt +17 -0
- package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultLauncher.kt +30 -0
- package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultRegistry.kt +358 -0
- package/android/src/main/java/expo/modules/kotlin/activityresult/DataPersistor.kt +135 -0
- package/android/src/main/java/expo/modules/kotlin/defaultmodules/ErrorManagerModule.kt +2 -2
- package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +13 -0
- package/android/src/main/java/expo/modules/kotlin/exception/ExceptionDecorator.kt +2 -0
- package/android/src/main/java/expo/modules/kotlin/functions/AnyFunction.kt +53 -15
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunction.kt +35 -7
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionBuilder.kt +13 -121
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionComponent.kt +21 -0
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromiseComponent.kt +21 -0
- package/android/src/main/java/expo/modules/kotlin/functions/SuspendFunctionComponent.kt +63 -0
- package/android/src/main/java/expo/modules/kotlin/functions/SyncFunctionComponent.kt +36 -0
- package/android/src/main/java/expo/modules/kotlin/jni/CppType.kt +19 -0
- package/android/src/main/java/expo/modules/kotlin/jni/JNIFunctionBody.kt +39 -0
- package/android/src/main/java/expo/modules/kotlin/jni/JSIInteropModuleRegistry.kt +89 -0
- package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptModuleObject.kt +46 -0
- package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptObject.kt +113 -0
- package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptValue.kt +35 -0
- package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +16 -6
- package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +5 -500
- package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +30 -5
- package/android/src/main/java/expo/modules/kotlin/objects/ObjectDefinitionBuilder.kt +271 -0
- package/android/src/main/java/expo/modules/kotlin/objects/ObjectDefinitionData.kt +21 -0
- package/android/src/main/java/expo/modules/kotlin/objects/PropertyComponent.kt +54 -0
- package/android/src/main/java/expo/modules/kotlin/objects/PropertyComponentBuilder.kt +32 -0
- package/android/src/main/java/expo/modules/kotlin/providers/AppContextProvider.kt +14 -0
- package/android/src/main/java/expo/modules/kotlin/providers/CurrentActivityProvider.kt +22 -0
- package/android/src/main/java/expo/modules/kotlin/records/RecordTypeConverter.kt +19 -2
- package/android/src/main/java/expo/modules/kotlin/types/AnyType.kt +3 -2
- package/android/src/main/java/expo/modules/kotlin/types/AnyTypeConverter.kt +36 -0
- package/android/src/main/java/expo/modules/kotlin/types/ArrayTypeConverter.kt +7 -2
- package/android/src/main/java/expo/modules/kotlin/types/BasicTypeConverters.kt +68 -20
- package/android/src/main/java/expo/modules/kotlin/types/EnumTypeConverter.kt +50 -22
- package/android/src/main/java/expo/modules/kotlin/types/ListTypeConverter.kt +18 -2
- package/android/src/main/java/expo/modules/kotlin/types/MapTypeConverter.kt +18 -2
- package/android/src/main/java/expo/modules/kotlin/types/PairTypeConverter.kt +17 -2
- package/android/src/main/java/expo/modules/kotlin/types/TypeConverter.kt +43 -3
- package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +12 -0
- package/android/src/main/java/expo/modules/kotlin/views/ViewGroupDefinitionBuilder.kt +0 -41
- package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +0 -33
- package/build/NativeModulesProxy.native.d.ts.map +1 -1
- package/build/NativeModulesProxy.native.js +9 -3
- package/build/NativeModulesProxy.native.js.map +1 -1
- package/build/PermissionsInterface.d.ts +29 -0
- package/build/PermissionsInterface.d.ts.map +1 -1
- package/build/PermissionsInterface.js +9 -0
- package/build/PermissionsInterface.js.map +1 -1
- package/ios/AppDelegates/EXAppDelegatesLoader.m +1 -2
- package/ios/ExpoModulesCore.podspec +3 -2
- package/ios/JSI/EXJSIConversions.mm +6 -0
- package/ios/JSI/EXJSIInstaller.h +15 -21
- package/ios/JSI/EXJSIInstaller.mm +39 -3
- package/ios/JSI/EXJSIUtils.h +48 -3
- package/ios/JSI/EXJSIUtils.mm +88 -4
- package/ios/JSI/EXJavaScriptObject.h +11 -18
- package/ios/JSI/EXJavaScriptObject.mm +37 -18
- package/ios/JSI/EXJavaScriptRuntime.h +43 -9
- package/ios/JSI/EXJavaScriptRuntime.mm +70 -27
- package/ios/JSI/EXJavaScriptTypedArray.h +30 -0
- package/ios/JSI/EXJavaScriptTypedArray.mm +29 -0
- package/ios/JSI/EXJavaScriptValue.h +3 -2
- package/ios/JSI/EXJavaScriptValue.mm +17 -20
- package/ios/JSI/EXJavaScriptWeakObject.h +23 -0
- package/ios/JSI/EXJavaScriptWeakObject.mm +53 -0
- package/ios/JSI/EXObjectDeallocator.h +27 -0
- package/ios/JSI/ExpoModulesHostObject.h +3 -3
- package/ios/JSI/ExpoModulesHostObject.mm +4 -4
- package/ios/JSI/JavaScriptRuntime.swift +38 -1
- package/ios/JSI/JavaScriptValue.swift +7 -0
- package/ios/JSI/TypedArray.cpp +67 -0
- package/ios/JSI/TypedArray.h +46 -0
- package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +0 -11
- package/ios/NativeModulesProxy/EXNativeModulesProxy.h +17 -10
- package/ios/NativeModulesProxy/EXNativeModulesProxy.mm +86 -77
- package/ios/NativeModulesProxy/NativeModulesProxyModule.swift +17 -0
- package/ios/Services/EXReactNativeEventEmitter.h +2 -2
- package/ios/Services/EXReactNativeEventEmitter.m +11 -6
- package/ios/Swift/AppContext.swift +206 -28
- package/ios/Swift/Arguments/AnyArgument.swift +18 -0
- package/ios/Swift/Arguments/{Types/EnumArgumentType.swift → EnumArgument.swift} +2 -17
- package/ios/Swift/Classes/ClassComponent.swift +95 -0
- package/ios/Swift/Classes/ClassComponentElement.swift +33 -0
- package/ios/Swift/Classes/ClassComponentElementsBuilder.swift +34 -0
- package/ios/Swift/Classes/ClassComponentFactories.swift +96 -0
- package/ios/Swift/DynamicTypes/AnyDynamicType.swift +44 -0
- package/ios/Swift/DynamicTypes/DynamicArrayType.swift +56 -0
- package/ios/Swift/DynamicTypes/DynamicConvertibleType.swift +27 -0
- package/ios/Swift/DynamicTypes/DynamicEnumType.swift +27 -0
- package/ios/Swift/DynamicTypes/DynamicOptionalType.swift +63 -0
- package/ios/Swift/DynamicTypes/DynamicRawType.swift +33 -0
- package/ios/Swift/DynamicTypes/DynamicSharedObjectType.swift +37 -0
- package/ios/Swift/DynamicTypes/DynamicType.swift +39 -0
- package/ios/Swift/DynamicTypes/DynamicTypedArrayType.swift +46 -0
- package/ios/Swift/Exceptions/ChainableException.swift +3 -3
- package/ios/Swift/Exceptions/CodedError.swift +1 -1
- package/ios/Swift/Exceptions/Exception.swift +8 -6
- package/ios/Swift/Exceptions/UnexpectedException.swift +2 -1
- package/ios/Swift/ExpoBridgeModule.m +5 -0
- package/ios/Swift/ExpoBridgeModule.swift +79 -0
- package/ios/Swift/Functions/AnyFunction.swift +33 -31
- package/ios/Swift/Functions/AsyncFunctionComponent.swift +196 -59
- package/ios/Swift/Functions/SyncFunctionComponent.swift +142 -58
- package/ios/Swift/JavaScriptUtils.swift +32 -57
- package/ios/Swift/Logging/LogHandlers.swift +39 -0
- package/ios/Swift/Logging/LogType.swift +62 -0
- package/ios/Swift/Logging/Logger.swift +201 -0
- package/ios/Swift/ModuleHolder.swift +19 -54
- package/ios/Swift/ModuleRegistry.swift +7 -1
- package/ios/Swift/Modules/AnyModule.swift +3 -3
- package/ios/Swift/ModulesProvider.swift +2 -0
- package/ios/Swift/Objects/JavaScriptObjectBuilder.swift +37 -0
- package/ios/Swift/Objects/ObjectDefinition.swift +74 -1
- package/ios/Swift/Objects/ObjectDefinitionComponents.swift +77 -68
- package/ios/Swift/Objects/PropertyComponent.swift +147 -0
- package/ios/Swift/Promise.swift +17 -4
- package/ios/Swift/Records/Field.swift +2 -2
- package/ios/Swift/SharedObjects/SharedObject.swift +20 -0
- package/ios/Swift/SharedObjects/SharedObjectRegistry.swift +129 -0
- package/ios/Swift/TypedArrays/AnyTypedArray.swift +11 -0
- package/ios/Swift/TypedArrays/ConcreteTypedArrays.swift +56 -0
- package/ios/Swift/TypedArrays/GenericTypedArray.swift +49 -0
- package/ios/Swift/TypedArrays/TypedArray.swift +80 -0
- package/ios/Swift/Utilities.swift +28 -0
- package/ios/Swift/Views/ConcreteViewProp.swift +3 -3
- package/ios/Swift/Views/ViewManagerDefinitionComponents.swift +2 -2
- package/ios/Tests/ClassComponentSpec.swift +210 -0
- package/ios/Tests/DynamicTypeSpec.swift +336 -0
- package/ios/Tests/EnumArgumentSpec.swift +48 -0
- package/ios/Tests/ExpoModulesSpec.swift +17 -3
- package/ios/Tests/FunctionSpec.swift +167 -118
- package/ios/Tests/Mocks/ModuleMocks.swift +1 -1
- package/ios/Tests/PropertyComponentSpec.swift +95 -0
- package/ios/Tests/SharedObjectRegistrySpec.swift +109 -0
- package/ios/Tests/TypedArraysSpec.swift +136 -0
- package/package.json +2 -2
- package/src/NativeModulesProxy.native.ts +13 -3
- package/src/PermissionsInterface.ts +29 -0
- package/src/ts-declarations/ExpoModules.d.ts +7 -0
- package/tsconfig.json +1 -1
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromise.kt +0 -15
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncSuspendFunction.kt +0 -36
- package/ios/Swift/Arguments/AnyArgumentType.swift +0 -13
- package/ios/Swift/Arguments/ArgumentType.swift +0 -28
- package/ios/Swift/Arguments/Types/ArrayArgumentType.swift +0 -42
- package/ios/Swift/Arguments/Types/ConvertibleArgumentType.swift +0 -16
- package/ios/Swift/Arguments/Types/OptionalArgumentType.swift +0 -49
- package/ios/Swift/Arguments/Types/PromiseArgumentType.swift +0 -15
- package/ios/Swift/Arguments/Types/RawArgumentType.swift +0 -25
- package/ios/Swift/Functions/ConcreteFunction.swift +0 -103
- package/ios/Swift/SwiftInteropBridge.swift +0 -155
- package/ios/Tests/ArgumentTypeSpec.swift +0 -143
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
#include "MethodMetadata.h"
|
|
2
|
+
#include "JSIInteropModuleRegistry.h"
|
|
3
|
+
#include "JavaScriptValue.h"
|
|
4
|
+
#include "JavaScriptObject.h"
|
|
5
|
+
#include "CachedReferencesRegistry.h"
|
|
6
|
+
|
|
7
|
+
#include <utility>
|
|
8
|
+
|
|
9
|
+
#include "react/jni/ReadableNativeMap.h"
|
|
10
|
+
#include "react/jni/ReadableNativeArray.h"
|
|
11
|
+
|
|
12
|
+
namespace jni = facebook::jni;
|
|
13
|
+
namespace jsi = facebook::jsi;
|
|
14
|
+
namespace react = facebook::react;
|
|
15
|
+
|
|
16
|
+
namespace expo {
|
|
17
|
+
|
|
18
|
+
// Modified version of the RN implementation
|
|
19
|
+
// https://github.com/facebook/react-native/blob/7dceb9b63c0bfd5b13bf6d26f9530729506e9097/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.cpp#L57
|
|
20
|
+
jni::local_ref<react::JCxxCallbackImpl::JavaPart> createJavaCallbackFromJSIFunction(
|
|
21
|
+
jsi::Function &&function,
|
|
22
|
+
jsi::Runtime &rt,
|
|
23
|
+
std::shared_ptr<react::CallInvoker> jsInvoker
|
|
24
|
+
) {
|
|
25
|
+
auto weakWrapper = react::CallbackWrapper::createWeak(std::move(function), rt,
|
|
26
|
+
std::move(jsInvoker));
|
|
27
|
+
|
|
28
|
+
// This needs to be a shared_ptr because:
|
|
29
|
+
// 1. It cannot be unique_ptr. std::function is copyable but unique_ptr is
|
|
30
|
+
// not.
|
|
31
|
+
// 2. It cannot be weak_ptr since we need this object to live on.
|
|
32
|
+
// 3. It cannot be a value, because that would be deleted as soon as this
|
|
33
|
+
// function returns.
|
|
34
|
+
auto callbackWrapperOwner =
|
|
35
|
+
std::make_shared<react::RAIICallbackWrapperDestroyer>(weakWrapper);
|
|
36
|
+
|
|
37
|
+
std::function<void(folly::dynamic)> fn =
|
|
38
|
+
[weakWrapper, callbackWrapperOwner, wrapperWasCalled = false](
|
|
39
|
+
folly::dynamic responses) mutable {
|
|
40
|
+
if (wrapperWasCalled) {
|
|
41
|
+
throw std::runtime_error(
|
|
42
|
+
"callback 2 arg cannot be called more than once");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
auto strongWrapper = weakWrapper.lock();
|
|
46
|
+
if (!strongWrapper) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
strongWrapper->jsInvoker().invokeAsync(
|
|
51
|
+
[weakWrapper, callbackWrapperOwner, responses]() mutable {
|
|
52
|
+
auto strongWrapper2 = weakWrapper.lock();
|
|
53
|
+
if (!strongWrapper2) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
jsi::Value args =
|
|
58
|
+
jsi::valueFromDynamic(strongWrapper2->runtime(), responses);
|
|
59
|
+
auto argsArray = args.getObject(strongWrapper2->runtime())
|
|
60
|
+
.asArray(strongWrapper2->runtime());
|
|
61
|
+
jsi::Value arg = argsArray.getValueAtIndex(strongWrapper2->runtime(), 0);
|
|
62
|
+
|
|
63
|
+
strongWrapper2->callback().call(
|
|
64
|
+
strongWrapper2->runtime(),
|
|
65
|
+
(const jsi::Value *) &arg,
|
|
66
|
+
(size_t) 1
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
callbackWrapperOwner.reset();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
wrapperWasCalled = true;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
return react::JCxxCallbackImpl::newObjectCxxArgs(fn);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
std::vector<jvalue> MethodMetadata::convertJSIArgsToJNI(
|
|
79
|
+
JSIInteropModuleRegistry *moduleRegistry,
|
|
80
|
+
JNIEnv *env,
|
|
81
|
+
jsi::Runtime &rt,
|
|
82
|
+
const jsi::Value *args,
|
|
83
|
+
size_t count
|
|
84
|
+
) {
|
|
85
|
+
std::vector<jvalue> result(count);
|
|
86
|
+
|
|
87
|
+
for (unsigned int argIndex = 0; argIndex < count; argIndex++) {
|
|
88
|
+
const jsi::Value *arg = &args[argIndex];
|
|
89
|
+
jvalue *jarg = &result[argIndex];
|
|
90
|
+
int desiredType = desiredTypes[argIndex];
|
|
91
|
+
|
|
92
|
+
if (desiredType & CppType::JS_VALUE) {
|
|
93
|
+
jarg->l = JavaScriptValue::newObjectCxxArgs(
|
|
94
|
+
moduleRegistry->runtimeHolder->weak_from_this(),
|
|
95
|
+
// TODO(@lukmccall): make sure that copy here is necessary
|
|
96
|
+
std::make_shared<jsi::Value>(jsi::Value(rt, *arg))
|
|
97
|
+
).release();
|
|
98
|
+
} else if (desiredType & CppType::JS_OBJECT) {
|
|
99
|
+
jarg->l = JavaScriptObject::newObjectCxxArgs(
|
|
100
|
+
moduleRegistry->runtimeHolder->weak_from_this(),
|
|
101
|
+
std::make_shared<jsi::Object>(arg->getObject(rt))
|
|
102
|
+
).release();
|
|
103
|
+
} else if (arg->isNull() || arg->isUndefined()) {
|
|
104
|
+
jarg->l = nullptr;
|
|
105
|
+
} else if (arg->isNumber()) {
|
|
106
|
+
auto &doubleClass = CachedReferencesRegistry::instance()
|
|
107
|
+
->getJClass("java/lang/Double");
|
|
108
|
+
jmethodID doubleConstructor = doubleClass.getMethod("<init>", "(D)V");
|
|
109
|
+
jarg->l = env->NewObject(doubleClass.clazz, doubleConstructor, arg->getNumber());
|
|
110
|
+
} else if (arg->isBool()) {
|
|
111
|
+
auto &booleanClass = CachedReferencesRegistry::instance()
|
|
112
|
+
->getJClass("java/lang/Boolean");
|
|
113
|
+
jmethodID booleanConstructor = booleanClass.getMethod("<init>", "(Z)V");
|
|
114
|
+
jarg->l = env->NewObject(booleanClass.clazz, booleanConstructor, arg->getBool());
|
|
115
|
+
} else if (arg->isString()) {
|
|
116
|
+
jarg->l = env->NewStringUTF(arg->getString(rt).utf8(rt).c_str());
|
|
117
|
+
} else if (arg->isObject()) {
|
|
118
|
+
const jsi::Object object = arg->getObject(rt);
|
|
119
|
+
|
|
120
|
+
// TODO(@lukmccall): stop using dynamic
|
|
121
|
+
auto dynamic = jsi::dynamicFromValue(rt, *arg);
|
|
122
|
+
if (arg->getObject(rt).isArray(rt)) {
|
|
123
|
+
jarg->l = react::ReadableNativeArray::newObjectCxxArgs(std::move(dynamic)).release();
|
|
124
|
+
} else {
|
|
125
|
+
jarg->l = react::ReadableNativeMap::createWithContents(std::move(dynamic)).release();
|
|
126
|
+
}
|
|
127
|
+
} else {
|
|
128
|
+
// TODO(@lukmccall): throw an exception
|
|
129
|
+
jarg->l = nullptr;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return result;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
MethodMetadata::MethodMetadata(
|
|
137
|
+
std::string name,
|
|
138
|
+
int args,
|
|
139
|
+
bool isAsync,
|
|
140
|
+
std::unique_ptr<int[]> desiredTypes,
|
|
141
|
+
jni::global_ref<jobject> &&jBodyReference
|
|
142
|
+
) : name(std::move(name)),
|
|
143
|
+
args(args),
|
|
144
|
+
isAsync(isAsync),
|
|
145
|
+
desiredTypes(std::move(desiredTypes)),
|
|
146
|
+
jBodyReference(std::move(jBodyReference)) {}
|
|
147
|
+
|
|
148
|
+
std::shared_ptr<jsi::Function> MethodMetadata::toJSFunction(
|
|
149
|
+
jsi::Runtime &runtime,
|
|
150
|
+
JSIInteropModuleRegistry *moduleRegistry
|
|
151
|
+
) {
|
|
152
|
+
if (body == nullptr) {
|
|
153
|
+
if (isAsync) {
|
|
154
|
+
body = std::make_shared<jsi::Function>(toAsyncFunction(runtime, moduleRegistry));
|
|
155
|
+
} else {
|
|
156
|
+
body = std::make_shared<jsi::Function>(toSyncFunction(runtime, moduleRegistry));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return body;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
jsi::Function MethodMetadata::toSyncFunction(
|
|
164
|
+
jsi::Runtime &runtime,
|
|
165
|
+
JSIInteropModuleRegistry *moduleRegistry
|
|
166
|
+
) {
|
|
167
|
+
return jsi::Function::createFromHostFunction(
|
|
168
|
+
runtime,
|
|
169
|
+
jsi::PropNameID::forAscii(runtime, name),
|
|
170
|
+
args,
|
|
171
|
+
[this, moduleRegistry](
|
|
172
|
+
jsi::Runtime &rt,
|
|
173
|
+
const jsi::Value &thisValue,
|
|
174
|
+
const jsi::Value *args,
|
|
175
|
+
size_t count
|
|
176
|
+
) -> jsi::Value {
|
|
177
|
+
return this->callSync(
|
|
178
|
+
rt,
|
|
179
|
+
moduleRegistry,
|
|
180
|
+
args,
|
|
181
|
+
count
|
|
182
|
+
);
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
jsi::Value MethodMetadata::callSync(
|
|
187
|
+
jsi::Runtime &rt,
|
|
188
|
+
JSIInteropModuleRegistry *moduleRegistry,
|
|
189
|
+
const jsi::Value *args,
|
|
190
|
+
size_t count
|
|
191
|
+
) {
|
|
192
|
+
if (this->jBodyReference == nullptr) {
|
|
193
|
+
return jsi::Value::undefined();
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
JNIEnv *env = jni::Environment::current();
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* This will push a new JNI stack frame for the LocalReferences in this
|
|
200
|
+
* function call. When the stack frame for this lambda is popped,
|
|
201
|
+
* all LocalReferences are deleted.
|
|
202
|
+
*/
|
|
203
|
+
jni::JniLocalScope scope(env, (int) count);
|
|
204
|
+
|
|
205
|
+
std::vector<jvalue> convertedArgs = convertJSIArgsToJNI(moduleRegistry, env, rt, args, count);
|
|
206
|
+
|
|
207
|
+
// TODO(@lukmccall): Remove this temp array
|
|
208
|
+
auto tempArray = jni::JArrayClass<jobject>::newArray(count);
|
|
209
|
+
for (size_t i = 0; i < convertedArgs.size(); i++) {
|
|
210
|
+
tempArray->setElement(i, convertedArgs[i].l);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Cast in this place is safe, cause we know that this function is promise-less.
|
|
214
|
+
auto syncFunction = jni::static_ref_cast<JNIFunctionBody>(this->jBodyReference);
|
|
215
|
+
auto result = syncFunction->invoke(
|
|
216
|
+
std::move(tempArray)
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
if (result == nullptr) {
|
|
220
|
+
return jsi::Value::undefined();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return jsi::valueFromDynamic(rt, result->cthis()->consume())
|
|
224
|
+
.asObject(rt)
|
|
225
|
+
.asArray(rt)
|
|
226
|
+
.getValueAtIndex(rt, 0);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
jsi::Function MethodMetadata::toAsyncFunction(
|
|
230
|
+
jsi::Runtime &runtime,
|
|
231
|
+
JSIInteropModuleRegistry *moduleRegistry
|
|
232
|
+
) {
|
|
233
|
+
return jsi::Function::createFromHostFunction(
|
|
234
|
+
runtime,
|
|
235
|
+
jsi::PropNameID::forAscii(runtime, name),
|
|
236
|
+
args,
|
|
237
|
+
[this, moduleRegistry](
|
|
238
|
+
jsi::Runtime &rt,
|
|
239
|
+
const jsi::Value &thisValue,
|
|
240
|
+
const jsi::Value *args,
|
|
241
|
+
size_t count
|
|
242
|
+
) -> jsi::Value {
|
|
243
|
+
JNIEnv *env = jni::Environment::current();
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* This will push a new JNI stack frame for the LocalReferences in this
|
|
247
|
+
* function call. When the stack frame for this lambda is popped,
|
|
248
|
+
* all LocalReferences are deleted.
|
|
249
|
+
*/
|
|
250
|
+
jni::JniLocalScope scope(env, (int) count);
|
|
251
|
+
|
|
252
|
+
std::vector<jvalue> convertedArgs = convertJSIArgsToJNI(moduleRegistry, env, rt, args, count);
|
|
253
|
+
|
|
254
|
+
// TODO(@lukmccall): Remove this temp array
|
|
255
|
+
auto tempArray = jni::JArrayClass<jobject>::newArray(count);
|
|
256
|
+
for (size_t i = 0; i < convertedArgs.size(); i++) {
|
|
257
|
+
tempArray->setElement(i, convertedArgs[i].l);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
auto Promise = rt.global().getPropertyAsFunction(rt, "Promise");
|
|
261
|
+
// Creates a JSI promise
|
|
262
|
+
jsi::Value promise = Promise.callAsConstructor(
|
|
263
|
+
rt,
|
|
264
|
+
createPromiseBody(rt, moduleRegistry, std::move(tempArray))
|
|
265
|
+
);
|
|
266
|
+
return promise;
|
|
267
|
+
}
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
jsi::Function MethodMetadata::createPromiseBody(
|
|
272
|
+
jsi::Runtime &runtime,
|
|
273
|
+
JSIInteropModuleRegistry *moduleRegistry,
|
|
274
|
+
jni::local_ref<jni::JArrayClass<jobject>::javaobject> &&args
|
|
275
|
+
) {
|
|
276
|
+
return jsi::Function::createFromHostFunction(
|
|
277
|
+
runtime,
|
|
278
|
+
jsi::PropNameID::forAscii(runtime, "promiseFn"),
|
|
279
|
+
2,
|
|
280
|
+
[this, args = std::move(args), moduleRegistry](
|
|
281
|
+
jsi::Runtime &rt,
|
|
282
|
+
const jsi::Value &thisVal,
|
|
283
|
+
const jsi::Value *promiseConstructorArgs,
|
|
284
|
+
size_t promiseConstructorArgCount
|
|
285
|
+
) {
|
|
286
|
+
if (promiseConstructorArgCount != 2) {
|
|
287
|
+
throw std::invalid_argument("Promise fn arg count must be 2");
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
jsi::Function resolveJSIFn = promiseConstructorArgs[0].getObject(rt).getFunction(rt);
|
|
291
|
+
jsi::Function rejectJSIFn = promiseConstructorArgs[1].getObject(rt).getFunction(rt);
|
|
292
|
+
|
|
293
|
+
auto &runtimeHolder = moduleRegistry->runtimeHolder;
|
|
294
|
+
jobject resolve = createJavaCallbackFromJSIFunction(
|
|
295
|
+
std::move(resolveJSIFn),
|
|
296
|
+
rt,
|
|
297
|
+
runtimeHolder->jsInvoker
|
|
298
|
+
).release();
|
|
299
|
+
|
|
300
|
+
jobject reject = createJavaCallbackFromJSIFunction(
|
|
301
|
+
std::move(rejectJSIFn),
|
|
302
|
+
rt,
|
|
303
|
+
runtimeHolder->jsInvoker
|
|
304
|
+
).release();
|
|
305
|
+
|
|
306
|
+
JNIEnv *env = jni::Environment::current();
|
|
307
|
+
|
|
308
|
+
auto &jPromise = CachedReferencesRegistry::instance()->getJClass(
|
|
309
|
+
"com/facebook/react/bridge/PromiseImpl");
|
|
310
|
+
jmethodID jPromiseConstructor = jPromise.getMethod(
|
|
311
|
+
"<init>",
|
|
312
|
+
"(Lcom/facebook/react/bridge/Callback;Lcom/facebook/react/bridge/Callback;)V"
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
// Creates a promise object
|
|
316
|
+
jobject promise = env->NewObject(
|
|
317
|
+
jPromise.clazz,
|
|
318
|
+
jPromiseConstructor,
|
|
319
|
+
resolve,
|
|
320
|
+
reject
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
// Cast in this place is safe, cause we know that this function expects promise.
|
|
324
|
+
auto asyncFunction = jni::static_ref_cast<JNIAsyncFunctionBody>(this->jBodyReference);
|
|
325
|
+
asyncFunction->invoke(
|
|
326
|
+
args,
|
|
327
|
+
promise
|
|
328
|
+
);
|
|
329
|
+
|
|
330
|
+
// We have to remove the local reference to the promise object.
|
|
331
|
+
// It doesn't mean that the promise will be deallocated, but rather that we move
|
|
332
|
+
// the ownership to the `JNIAsyncFunctionBody`.
|
|
333
|
+
env->DeleteLocalRef(promise);
|
|
334
|
+
|
|
335
|
+
return jsi::Value::undefined();
|
|
336
|
+
}
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
} // namespace expo
|
|
@@ -0,0 +1,131 @@
|
|
|
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/TurboModuleUtils.h>
|
|
8
|
+
#include <react/jni/ReadableNativeArray.h>
|
|
9
|
+
#include <memory>
|
|
10
|
+
#include <folly/dynamic.h>
|
|
11
|
+
#include <jsi/JSIDynamic.h>
|
|
12
|
+
|
|
13
|
+
namespace jni = facebook::jni;
|
|
14
|
+
namespace jsi = facebook::jsi;
|
|
15
|
+
namespace react = facebook::react;
|
|
16
|
+
|
|
17
|
+
namespace expo {
|
|
18
|
+
class JSIInteropModuleRegistry;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* A cpp version of the `expo.modules.kotlin.jni.CppType` enum.
|
|
22
|
+
* Used to determine which representation of the js value should be sent to the Kotlin.
|
|
23
|
+
*/
|
|
24
|
+
enum CppType {
|
|
25
|
+
DOUBLE = 1 << 0,
|
|
26
|
+
BOOLEAN = 1 << 1,
|
|
27
|
+
STRING = 1 << 2,
|
|
28
|
+
JS_OBJECT = 1 << 3,
|
|
29
|
+
JS_VALUE = 1 << 4,
|
|
30
|
+
READABLE_ARRAY = 1 << 5,
|
|
31
|
+
READABLE_MAP = 1 << 6
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* A class that holds information about the exported function.
|
|
36
|
+
*/
|
|
37
|
+
class MethodMetadata {
|
|
38
|
+
public:
|
|
39
|
+
/**
|
|
40
|
+
* Function name
|
|
41
|
+
*/
|
|
42
|
+
std::string name;
|
|
43
|
+
/**
|
|
44
|
+
* Number of arguments
|
|
45
|
+
*/
|
|
46
|
+
int args;
|
|
47
|
+
/*
|
|
48
|
+
* Whether this function is async
|
|
49
|
+
*/
|
|
50
|
+
bool isAsync;
|
|
51
|
+
|
|
52
|
+
std::unique_ptr<int[]> desiredTypes;
|
|
53
|
+
|
|
54
|
+
MethodMetadata(
|
|
55
|
+
std::string name,
|
|
56
|
+
int args,
|
|
57
|
+
bool isAsync,
|
|
58
|
+
std::unique_ptr<int[]> desiredTypes,
|
|
59
|
+
jni::global_ref<jobject> &&jBodyReference
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
// We deleted the copy contractor to not deal with transforming the ownership of the `jBodyReference`.
|
|
63
|
+
MethodMetadata(const MethodMetadata &) = delete;
|
|
64
|
+
|
|
65
|
+
MethodMetadata(MethodMetadata &&other) = default;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* MethodMetadata owns the only reference to the Kotlin function.
|
|
69
|
+
* We have to clean that, cause it's a `global_ref`.
|
|
70
|
+
*/
|
|
71
|
+
~MethodMetadata() {
|
|
72
|
+
if (jBodyReference != nullptr) {
|
|
73
|
+
jBodyReference.release();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Transforms metadata to a jsi::Function.
|
|
79
|
+
*
|
|
80
|
+
* @param runtime
|
|
81
|
+
* @param moduleRegistry
|
|
82
|
+
* @return shared ptr to the jsi::Function that wrapped the underlying Kotlin's function.
|
|
83
|
+
*/
|
|
84
|
+
std::shared_ptr<jsi::Function> toJSFunction(
|
|
85
|
+
jsi::Runtime &runtime,
|
|
86
|
+
JSIInteropModuleRegistry *moduleRegistry
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Calls the underlying Kotlin function.
|
|
91
|
+
*/
|
|
92
|
+
jsi::Value callSync(
|
|
93
|
+
jsi::Runtime &rt,
|
|
94
|
+
JSIInteropModuleRegistry *moduleRegistry,
|
|
95
|
+
const jsi::Value *args,
|
|
96
|
+
size_t count
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
private:
|
|
100
|
+
/**
|
|
101
|
+
* Reference to one of two java objects - `JNIFunctionBody` or `JNIAsyncFunctionBody`.
|
|
102
|
+
*
|
|
103
|
+
* In case when `isAsync` is `true`, this variable will point to `JNIAsyncFunctionBody`.
|
|
104
|
+
* Otherwise to `JNIFunctionBody`
|
|
105
|
+
*/
|
|
106
|
+
jni::global_ref<jobject> jBodyReference;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* To not create a jsi::Function always when we need it, we cached that value.
|
|
110
|
+
*/
|
|
111
|
+
std::shared_ptr<jsi::Function> body = nullptr;
|
|
112
|
+
|
|
113
|
+
jsi::Function toSyncFunction(jsi::Runtime &runtime, JSIInteropModuleRegistry *moduleRegistry);
|
|
114
|
+
|
|
115
|
+
jsi::Function toAsyncFunction(jsi::Runtime &runtime, JSIInteropModuleRegistry *moduleRegistry);
|
|
116
|
+
|
|
117
|
+
jsi::Function createPromiseBody(
|
|
118
|
+
jsi::Runtime &runtime,
|
|
119
|
+
JSIInteropModuleRegistry *moduleRegistry,
|
|
120
|
+
jni::local_ref<jni::JArrayClass<jobject>::javaobject> &&args
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
std::vector<jvalue> convertJSIArgsToJNI(
|
|
124
|
+
JSIInteropModuleRegistry *moduleRegistry,
|
|
125
|
+
JNIEnv *env,
|
|
126
|
+
jsi::Runtime &rt,
|
|
127
|
+
const jsi::Value *args,
|
|
128
|
+
size_t count
|
|
129
|
+
);
|
|
130
|
+
};
|
|
131
|
+
} // namespace expo
|
|
@@ -92,6 +92,8 @@ public class NativeModulesProxy extends ReactContextBaseJavaModule {
|
|
|
92
92
|
@Override
|
|
93
93
|
public Map<String, Object> getConstants() {
|
|
94
94
|
mModuleRegistry.ensureIsInitialized();
|
|
95
|
+
getKotlinInteropModuleRegistry().installJSIInterop();
|
|
96
|
+
|
|
95
97
|
Collection<ExportedModule> exportedModules = mModuleRegistry.getAllExportedModules();
|
|
96
98
|
Collection<ViewManager> viewManagers = mModuleRegistry.getAllViewManagers();
|
|
97
99
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
package expo.modules.core.errors
|
|
2
|
+
|
|
3
|
+
import kotlinx.coroutines.CancellationException
|
|
4
|
+
|
|
5
|
+
private const val DEFAULT_MESSAGE = "App context destroyed. All coroutines are cancelled."
|
|
6
|
+
|
|
7
|
+
class ContextDestroyedException(message: String = DEFAULT_MESSAGE) : CancellationException(message)
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
package expo.modules.interfaces.permissions;
|
|
2
2
|
|
|
3
|
+
import androidx.annotation.NonNull;
|
|
4
|
+
import androidx.annotation.Nullable;
|
|
3
5
|
import expo.modules.core.Promise;
|
|
4
6
|
|
|
5
7
|
public interface Permissions {
|
|
@@ -12,6 +14,20 @@ public interface Permissions {
|
|
|
12
14
|
permissionsManager.getPermissionsWithPromise(promise, permissions);
|
|
13
15
|
}
|
|
14
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Compatibility method that accepts expo.modules.kotlin.Promise, but forward the logic to the other method
|
|
19
|
+
*/
|
|
20
|
+
static void getPermissionsWithPermissionsManager(
|
|
21
|
+
@Nullable Permissions permissionsManager,
|
|
22
|
+
@NonNull final expo.modules.kotlin.Promise promise,
|
|
23
|
+
@NonNull String... permissions
|
|
24
|
+
) {
|
|
25
|
+
getPermissionsWithPermissionsManager(permissionsManager, new Promise() {
|
|
26
|
+
@Override public void resolve(Object value) { promise.resolve(value); }
|
|
27
|
+
@Override public void reject(String c, String m, Throwable e) { promise.reject(c, m, e); }
|
|
28
|
+
}, permissions);
|
|
29
|
+
}
|
|
30
|
+
|
|
15
31
|
static void askForPermissionsWithPermissionsManager(Permissions permissionsManager, final Promise promise, String... permissions) {
|
|
16
32
|
if (permissionsManager == null) {
|
|
17
33
|
promise.reject("E_NO_PERMISSIONS", "Permissions module is null. Are you sure all the installed Expo modules are properly linked?");
|
|
@@ -20,6 +36,20 @@ public interface Permissions {
|
|
|
20
36
|
permissionsManager.askForPermissionsWithPromise(promise, permissions);
|
|
21
37
|
}
|
|
22
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Compatibility method that accepts expo.modules.kotlin.Promise, but forward the logic to the other method
|
|
41
|
+
*/
|
|
42
|
+
static void askForPermissionsWithPermissionsManager(
|
|
43
|
+
@Nullable Permissions permissionsManager,
|
|
44
|
+
@NonNull final expo.modules.kotlin.Promise promise,
|
|
45
|
+
@NonNull String... permissions
|
|
46
|
+
) {
|
|
47
|
+
askForPermissionsWithPermissionsManager(permissionsManager, new Promise() {
|
|
48
|
+
@Override public void resolve(Object value) { promise.resolve(value); }
|
|
49
|
+
@Override public void reject(String c, String m, Throwable e) { promise.reject(c, m, e); }
|
|
50
|
+
}, permissions);
|
|
51
|
+
}
|
|
52
|
+
|
|
23
53
|
void getPermissionsWithPromise(final Promise promise, String... permissions);
|
|
24
54
|
|
|
25
55
|
void getPermissions(final PermissionsResponseListener response, String... permissions);
|
|
@@ -1,9 +1,15 @@
|
|
|
1
|
+
@file:OptIn(DelicateCoroutinesApi::class)
|
|
2
|
+
|
|
1
3
|
package expo.modules.kotlin
|
|
2
4
|
|
|
3
5
|
import android.app.Activity
|
|
4
6
|
import android.content.Context
|
|
5
7
|
import android.content.Intent
|
|
8
|
+
import androidx.annotation.MainThread
|
|
9
|
+
import androidx.appcompat.app.AppCompatActivity
|
|
6
10
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
11
|
+
import com.facebook.react.turbomodule.core.CallInvokerHolderImpl
|
|
12
|
+
import expo.modules.core.errors.ContextDestroyedException
|
|
7
13
|
import expo.modules.core.interfaces.ActivityProvider
|
|
8
14
|
import expo.modules.interfaces.barcodescanner.BarCodeScannerInterface
|
|
9
15
|
import expo.modules.interfaces.camera.CameraViewInterface
|
|
@@ -14,35 +20,86 @@ import expo.modules.interfaces.imageloader.ImageLoaderInterface
|
|
|
14
20
|
import expo.modules.interfaces.permissions.Permissions
|
|
15
21
|
import expo.modules.interfaces.sensors.SensorServiceInterface
|
|
16
22
|
import expo.modules.interfaces.taskManager.TaskManagerInterface
|
|
23
|
+
import expo.modules.kotlin.activityresult.ActivityResultsManager
|
|
24
|
+
import expo.modules.kotlin.activityresult.AppContextActivityResultFallbackCallback
|
|
25
|
+
import expo.modules.kotlin.activityresult.AppContextActivityResultCaller
|
|
26
|
+
import expo.modules.kotlin.activityresult.AppContextActivityResultContract
|
|
27
|
+
import expo.modules.kotlin.activityresult.AppContextActivityResultLauncher
|
|
17
28
|
import expo.modules.kotlin.defaultmodules.ErrorManagerModule
|
|
18
29
|
import expo.modules.kotlin.events.EventEmitter
|
|
19
30
|
import expo.modules.kotlin.events.EventName
|
|
20
31
|
import expo.modules.kotlin.events.KEventEmitterWrapper
|
|
21
32
|
import expo.modules.kotlin.events.KModuleEventEmitterWrapper
|
|
22
33
|
import expo.modules.kotlin.events.OnActivityResultPayload
|
|
34
|
+
import expo.modules.kotlin.jni.JSIInteropModuleRegistry
|
|
23
35
|
import expo.modules.kotlin.modules.Module
|
|
36
|
+
import expo.modules.kotlin.providers.CurrentActivityProvider
|
|
37
|
+
import kotlinx.coroutines.CoroutineName
|
|
38
|
+
import kotlinx.coroutines.CoroutineScope
|
|
39
|
+
import kotlinx.coroutines.DelicateCoroutinesApi
|
|
40
|
+
import kotlinx.coroutines.SupervisorJob
|
|
41
|
+
import kotlinx.coroutines.cancel
|
|
42
|
+
import kotlinx.coroutines.newSingleThreadContext
|
|
43
|
+
import java.io.Serializable
|
|
24
44
|
import java.lang.ref.WeakReference
|
|
25
45
|
|
|
26
46
|
class AppContext(
|
|
27
47
|
modulesProvider: ModulesProvider,
|
|
28
48
|
val legacyModuleRegistry: expo.modules.core.ModuleRegistry,
|
|
29
49
|
private val reactContextHolder: WeakReference<ReactApplicationContext>
|
|
30
|
-
) {
|
|
50
|
+
) : CurrentActivityProvider, AppContextActivityResultCaller {
|
|
31
51
|
val registry = ModuleRegistry(WeakReference(this)).apply {
|
|
32
|
-
register(ErrorManagerModule())
|
|
33
|
-
register(modulesProvider)
|
|
34
52
|
}
|
|
35
53
|
private val reactLifecycleDelegate = ReactLifecycleDelegate(this)
|
|
36
54
|
|
|
55
|
+
// We postpone creating the `JSIInteropModuleRegistry` to not load so files in unit tests.
|
|
56
|
+
private lateinit var jsiInterop: JSIInteropModuleRegistry
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* A queue used to dispatch all async methods that are called via JSI.
|
|
60
|
+
*/
|
|
61
|
+
internal val modulesQueue = CoroutineScope(
|
|
62
|
+
// TODO(@lukmccall): maybe it will be better to use a thread pool
|
|
63
|
+
newSingleThreadContext("ExpoModulesCoreQueue") +
|
|
64
|
+
SupervisorJob() +
|
|
65
|
+
CoroutineName("ExpoModulesCoreCoroutineQueue")
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
private val activityResultsManager = ActivityResultsManager(this)
|
|
69
|
+
|
|
37
70
|
init {
|
|
38
71
|
requireNotNull(reactContextHolder.get()) {
|
|
39
72
|
"The app context should be created with valid react context."
|
|
40
73
|
}.apply {
|
|
41
74
|
addLifecycleEventListener(reactLifecycleDelegate)
|
|
42
75
|
addActivityEventListener(reactLifecycleDelegate)
|
|
76
|
+
|
|
77
|
+
// Registering modules has to happen at the very end of `AppContext` creation. Some modules need to access
|
|
78
|
+
// `AppContext` during their initialisation (or during `OnCreate` method), so we need to ensure all `AppContext`'s
|
|
79
|
+
// properties are initialized first. Not having that would trigger NPE.
|
|
80
|
+
registry.register(ErrorManagerModule())
|
|
81
|
+
registry.register(modulesProvider)
|
|
43
82
|
}
|
|
44
83
|
}
|
|
45
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Initializes a JSI part of the module registry.
|
|
87
|
+
* It will be a NOOP if the remote debugging was activated.
|
|
88
|
+
*/
|
|
89
|
+
fun installJSIInterop() {
|
|
90
|
+
jsiInterop = JSIInteropModuleRegistry(this)
|
|
91
|
+
val reactContext = reactContextHolder.get() ?: return
|
|
92
|
+
reactContext.javaScriptContextHolder?.get()
|
|
93
|
+
?.takeIf { it != 0L }
|
|
94
|
+
?.let {
|
|
95
|
+
jsiInterop.installJSI(
|
|
96
|
+
it,
|
|
97
|
+
reactContext.catalystInstance.jsCallInvokerHolder as CallInvokerHolderImpl,
|
|
98
|
+
reactContext.catalystInstance.nativeCallInvokerHolder as CallInvokerHolderImpl
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
46
103
|
/**
|
|
47
104
|
* Returns a legacy module implementing given interface.
|
|
48
105
|
*/
|
|
@@ -149,9 +206,15 @@ class AppContext(
|
|
|
149
206
|
reactContextHolder.get()?.removeLifecycleEventListener(reactLifecycleDelegate)
|
|
150
207
|
registry.post(EventName.MODULE_DESTROY)
|
|
151
208
|
registry.cleanUp()
|
|
209
|
+
modulesQueue.cancel(ContextDestroyedException())
|
|
152
210
|
}
|
|
153
211
|
|
|
154
212
|
fun onHostResume() {
|
|
213
|
+
activityResultsManager.onHostResume(
|
|
214
|
+
requireNotNull(currentActivity) {
|
|
215
|
+
"Current Activity is not available at this moment. This is an invalid state and this should never happen"
|
|
216
|
+
}
|
|
217
|
+
)
|
|
155
218
|
registry.post(EventName.ACTIVITY_ENTERS_FOREGROUND)
|
|
156
219
|
}
|
|
157
220
|
|
|
@@ -160,10 +223,16 @@ class AppContext(
|
|
|
160
223
|
}
|
|
161
224
|
|
|
162
225
|
fun onHostDestroy() {
|
|
226
|
+
activityResultsManager.onHostDestroy(
|
|
227
|
+
requireNotNull(currentActivity) {
|
|
228
|
+
"Current Activity is not available at this moment. This is an invalid state and this should never happen"
|
|
229
|
+
}
|
|
230
|
+
)
|
|
163
231
|
registry.post(EventName.ACTIVITY_DESTROYS)
|
|
164
232
|
}
|
|
165
233
|
|
|
166
234
|
fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int, data: Intent?) {
|
|
235
|
+
activityResultsManager.onActivityResult(activity, requestCode, resultCode, data)
|
|
167
236
|
registry.post(
|
|
168
237
|
EventName.ON_ACTIVITY_RESULT,
|
|
169
238
|
activity,
|
|
@@ -181,4 +250,30 @@ class AppContext(
|
|
|
181
250
|
intent
|
|
182
251
|
)
|
|
183
252
|
}
|
|
253
|
+
|
|
254
|
+
// region CurrentActivityProvider
|
|
255
|
+
|
|
256
|
+
override val currentActivity: AppCompatActivity?
|
|
257
|
+
get() {
|
|
258
|
+
val currentActivity = this.activityProvider?.currentActivity ?: return null
|
|
259
|
+
|
|
260
|
+
check(currentActivity is AppCompatActivity) {
|
|
261
|
+
"Current Activity is of incorrect class, expected AppCompatActivity, received ${currentActivity.localClassName}"
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return currentActivity
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// endregion
|
|
268
|
+
|
|
269
|
+
// region AppContextActivityResultCaller
|
|
270
|
+
|
|
271
|
+
@MainThread
|
|
272
|
+
override suspend fun <I : Serializable, O> registerForActivityResult(
|
|
273
|
+
contract: AppContextActivityResultContract<I, O>,
|
|
274
|
+
fallbackCallback: AppContextActivityResultFallbackCallback<I, O>
|
|
275
|
+
): AppContextActivityResultLauncher<I, O> =
|
|
276
|
+
activityResultsManager.registerForActivityResult(contract, fallbackCallback)
|
|
277
|
+
|
|
278
|
+
// endregion
|
|
184
279
|
}
|