expo-modules-core 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/android/CMakeLists.txt +154 -0
- package/android/build.gradle +293 -5
- package/android/src/main/cpp/Exceptions.cpp +22 -0
- package/android/src/main/cpp/Exceptions.h +38 -0
- package/android/src/main/cpp/ExpoModulesHostObject.cpp +47 -0
- package/android/src/main/cpp/ExpoModulesHostObject.h +32 -0
- package/android/src/main/cpp/JNIFunctionBody.cpp +29 -0
- package/android/src/main/cpp/JNIFunctionBody.h +50 -0
- package/android/src/main/cpp/JNIInjector.cpp +19 -0
- package/android/src/main/cpp/JSIInteropModuleRegistry.cpp +122 -0
- package/android/src/main/cpp/JSIInteropModuleRegistry.h +96 -0
- package/android/src/main/cpp/JSIObjectWrapper.h +33 -0
- package/android/src/main/cpp/JSITypeConverter.h +84 -0
- package/android/src/main/cpp/JavaScriptModuleObject.cpp +138 -0
- package/android/src/main/cpp/JavaScriptModuleObject.h +122 -0
- package/android/src/main/cpp/JavaScriptObject.cpp +125 -0
- package/android/src/main/cpp/JavaScriptObject.h +131 -0
- package/android/src/main/cpp/JavaScriptRuntime.cpp +127 -0
- package/android/src/main/cpp/JavaScriptRuntime.h +87 -0
- package/android/src/main/cpp/JavaScriptValue.cpp +172 -0
- package/android/src/main/cpp/JavaScriptValue.h +78 -0
- package/android/src/main/cpp/MethodMetadata.cpp +230 -0
- package/android/src/main/cpp/MethodMetadata.h +92 -0
- package/android/src/main/java/expo/modules/adapters/react/NativeModulesProxy.java +2 -0
- package/android/src/main/java/expo/modules/core/errors/ContextDestroyedException.kt +7 -0
- package/android/src/main/java/expo/modules/interfaces/permissions/Permissions.java +30 -0
- package/android/src/main/java/expo/modules/kotlin/AppContext.kt +49 -1
- package/android/src/main/java/expo/modules/kotlin/ConcatIterator.kt +18 -0
- package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +15 -12
- package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +39 -3
- package/android/src/main/java/expo/modules/kotlin/defaultmodules/ErrorManagerModule.kt +2 -2
- package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +13 -0
- package/android/src/main/java/expo/modules/kotlin/exception/ExceptionDecorator.kt +2 -0
- package/android/src/main/java/expo/modules/kotlin/functions/AnyFunction.kt +19 -14
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunction.kt +29 -7
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionBuilder.kt +13 -13
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionComponent.kt +18 -0
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromiseComponent.kt +18 -0
- package/android/src/main/java/expo/modules/kotlin/functions/SuspendFunctionComponent.kt +56 -0
- package/android/src/main/java/expo/modules/kotlin/functions/SyncFunctionComponent.kt +28 -0
- package/android/src/main/java/expo/modules/kotlin/jni/CppType.kt +18 -0
- package/android/src/main/java/expo/modules/kotlin/jni/JNIFunctionBody.kt +39 -0
- package/android/src/main/java/expo/modules/kotlin/jni/JSIInteropModuleRegistry.kt +89 -0
- package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptModuleObject.kt +44 -0
- package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptObject.kt +113 -0
- package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptValue.kt +35 -0
- package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +15 -5
- package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +65 -111
- package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +35 -2
- package/android/src/main/java/expo/modules/kotlin/providers/AppContextProvider.kt +14 -0
- package/android/src/main/java/expo/modules/kotlin/providers/CurrentActivityProvider.kt +22 -0
- package/android/src/main/java/expo/modules/kotlin/records/RecordTypeConverter.kt +19 -2
- package/android/src/main/java/expo/modules/kotlin/types/AnyType.kt +3 -2
- package/android/src/main/java/expo/modules/kotlin/types/ArrayTypeConverter.kt +7 -2
- package/android/src/main/java/expo/modules/kotlin/types/BasicTypeConverters.kt +68 -20
- package/android/src/main/java/expo/modules/kotlin/types/EnumTypeConverter.kt +50 -22
- package/android/src/main/java/expo/modules/kotlin/types/ListTypeConverter.kt +18 -2
- package/android/src/main/java/expo/modules/kotlin/types/MapTypeConverter.kt +18 -2
- package/android/src/main/java/expo/modules/kotlin/types/PairTypeConverter.kt +17 -2
- package/android/src/main/java/expo/modules/kotlin/types/TypeConverter.kt +43 -3
- package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +5 -0
- package/build/NativeModulesProxy.native.d.ts.map +1 -1
- package/build/NativeModulesProxy.native.js +9 -3
- package/build/NativeModulesProxy.native.js.map +1 -1
- package/ios/AppDelegates/EXAppDelegatesLoader.m +1 -2
- package/ios/ExpoModulesCore.podspec +1 -1
- package/ios/JSI/EXJSIConversions.mm +6 -0
- package/ios/JSI/EXJSIInstaller.h +15 -21
- package/ios/JSI/EXJSIInstaller.mm +39 -3
- package/ios/JSI/EXJSIUtils.h +47 -3
- package/ios/JSI/EXJSIUtils.mm +88 -4
- package/ios/JSI/EXJavaScriptObject.h +11 -18
- package/ios/JSI/EXJavaScriptObject.mm +37 -18
- package/ios/JSI/EXJavaScriptRuntime.h +43 -9
- package/ios/JSI/EXJavaScriptRuntime.mm +70 -27
- package/ios/JSI/EXJavaScriptTypedArray.h +30 -0
- package/ios/JSI/EXJavaScriptTypedArray.mm +29 -0
- package/ios/JSI/EXJavaScriptValue.h +3 -2
- package/ios/JSI/EXJavaScriptValue.mm +17 -20
- package/ios/JSI/EXJavaScriptWeakObject.h +23 -0
- package/ios/JSI/EXJavaScriptWeakObject.mm +53 -0
- package/ios/JSI/EXObjectDeallocator.h +27 -0
- package/ios/JSI/ExpoModulesHostObject.h +3 -3
- package/ios/JSI/ExpoModulesHostObject.mm +4 -4
- package/ios/JSI/JavaScriptRuntime.swift +38 -1
- package/ios/JSI/JavaScriptValue.swift +7 -0
- package/ios/JSI/TypedArray.cpp +67 -0
- package/ios/JSI/TypedArray.h +46 -0
- package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +0 -11
- package/ios/NativeModulesProxy/EXNativeModulesProxy.h +17 -10
- package/ios/NativeModulesProxy/EXNativeModulesProxy.mm +88 -77
- package/ios/NativeModulesProxy/NativeModulesProxyModule.swift +17 -0
- package/ios/Services/EXReactNativeEventEmitter.h +2 -2
- package/ios/Services/EXReactNativeEventEmitter.m +11 -6
- package/ios/Swift/AppContext.swift +208 -28
- package/ios/Swift/Arguments/AnyArgument.swift +18 -0
- package/ios/Swift/Arguments/{Types/EnumArgumentType.swift → EnumArgument.swift} +2 -17
- package/ios/Swift/Classes/ClassComponent.swift +95 -0
- package/ios/Swift/Classes/ClassComponentElement.swift +33 -0
- package/ios/Swift/Classes/ClassComponentElementsBuilder.swift +34 -0
- package/ios/Swift/Classes/ClassComponentFactories.swift +96 -0
- package/ios/Swift/DynamicTypes/AnyDynamicType.swift +44 -0
- package/ios/Swift/DynamicTypes/DynamicArrayType.swift +56 -0
- package/ios/Swift/DynamicTypes/DynamicConvertibleType.swift +27 -0
- package/ios/Swift/DynamicTypes/DynamicEnumType.swift +27 -0
- package/ios/Swift/DynamicTypes/DynamicOptionalType.swift +63 -0
- package/ios/Swift/DynamicTypes/DynamicRawType.swift +33 -0
- package/ios/Swift/DynamicTypes/DynamicSharedObjectType.swift +37 -0
- package/ios/Swift/DynamicTypes/DynamicType.swift +39 -0
- package/ios/Swift/DynamicTypes/DynamicTypedArrayType.swift +46 -0
- package/ios/Swift/Exceptions/CodedError.swift +1 -1
- package/ios/Swift/Exceptions/Exception.swift +8 -6
- package/ios/Swift/Exceptions/UnexpectedException.swift +2 -1
- package/ios/Swift/ExpoBridgeModule.m +5 -0
- package/ios/Swift/ExpoBridgeModule.swift +65 -0
- package/ios/Swift/Functions/AnyFunction.swift +33 -31
- package/ios/Swift/Functions/AsyncFunctionComponent.swift +196 -59
- package/ios/Swift/Functions/SyncFunctionComponent.swift +142 -58
- package/ios/Swift/JavaScriptUtils.swift +32 -57
- package/ios/Swift/Logging/LogHandlers.swift +39 -0
- package/ios/Swift/Logging/LogType.swift +62 -0
- package/ios/Swift/Logging/Logger.swift +198 -0
- package/ios/Swift/ModuleHolder.swift +19 -54
- package/ios/Swift/ModuleRegistry.swift +7 -1
- package/ios/Swift/Modules/AnyModule.swift +3 -3
- package/ios/Swift/ModulesProvider.swift +2 -0
- package/ios/Swift/Objects/JavaScriptObjectBuilder.swift +37 -0
- package/ios/Swift/Objects/ObjectDefinition.swift +74 -1
- package/ios/Swift/Objects/ObjectDefinitionComponents.swift +77 -68
- package/ios/Swift/Objects/PropertyComponent.swift +147 -0
- package/ios/Swift/Promise.swift +12 -3
- package/ios/Swift/Records/Field.swift +2 -2
- package/ios/Swift/SharedObjects/SharedObject.swift +20 -0
- package/ios/Swift/SharedObjects/SharedObjectRegistry.swift +129 -0
- package/ios/Swift/TypedArrays/AnyTypedArray.swift +11 -0
- package/ios/Swift/TypedArrays/ConcreteTypedArrays.swift +56 -0
- package/ios/Swift/TypedArrays/GenericTypedArray.swift +49 -0
- package/ios/Swift/TypedArrays/TypedArray.swift +80 -0
- package/ios/Swift/Utilities.swift +28 -0
- package/ios/Swift/Views/ConcreteViewProp.swift +3 -3
- package/ios/Swift/Views/ViewManagerDefinitionComponents.swift +2 -2
- package/ios/Tests/ClassComponentSpec.swift +210 -0
- package/ios/Tests/DynamicTypeSpec.swift +336 -0
- package/ios/Tests/EnumArgumentSpec.swift +48 -0
- package/ios/Tests/ExpoModulesSpec.swift +17 -3
- package/ios/Tests/FunctionSpec.swift +167 -118
- package/ios/Tests/Mocks/ModuleMocks.swift +1 -1
- package/ios/Tests/PropertyComponentSpec.swift +95 -0
- package/ios/Tests/SharedObjectRegistrySpec.swift +109 -0
- package/ios/Tests/TypedArraysSpec.swift +136 -0
- package/package.json +2 -2
- package/src/NativeModulesProxy.native.ts +13 -3
- package/src/ts-declarations/ExpoModules.d.ts +7 -0
- package/tsconfig.json +1 -1
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromise.kt +0 -15
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncSuspendFunction.kt +0 -36
- package/ios/Swift/Arguments/AnyArgumentType.swift +0 -13
- package/ios/Swift/Arguments/ArgumentType.swift +0 -28
- package/ios/Swift/Arguments/Types/ArrayArgumentType.swift +0 -42
- package/ios/Swift/Arguments/Types/ConvertibleArgumentType.swift +0 -16
- package/ios/Swift/Arguments/Types/OptionalArgumentType.swift +0 -49
- package/ios/Swift/Arguments/Types/PromiseArgumentType.swift +0 -15
- package/ios/Swift/Arguments/Types/RawArgumentType.swift +0 -25
- package/ios/Swift/Functions/ConcreteFunction.swift +0 -103
- package/ios/Swift/SwiftInteropBridge.swift +0 -155
- package/ios/Tests/ArgumentTypeSpec.swift +0 -143
|
@@ -9,8 +9,8 @@ private const val onNewException = "ExpoModulesCoreErrorManager.onNewException"
|
|
|
9
9
|
|
|
10
10
|
class ErrorManagerModule : Module() {
|
|
11
11
|
override fun definition() = ModuleDefinition {
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
Name("ExpoModulesCoreErrorManager")
|
|
13
|
+
Events(onNewException)
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
fun reportExceptionToLogBox(codedException: CodedException) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package expo.modules.kotlin.exception
|
|
2
2
|
|
|
3
3
|
import com.facebook.react.bridge.ReadableType
|
|
4
|
+
import expo.modules.core.interfaces.DoNotStrip
|
|
4
5
|
import java.util.*
|
|
5
6
|
import kotlin.reflect.KProperty1
|
|
6
7
|
import kotlin.reflect.KType
|
|
@@ -8,6 +9,7 @@ import kotlin.reflect.KType
|
|
|
8
9
|
/**
|
|
9
10
|
* A class for errors specifying its `code` and providing the `description`.
|
|
10
11
|
*/
|
|
12
|
+
@DoNotStrip
|
|
11
13
|
open class CodedException(
|
|
12
14
|
message: String?,
|
|
13
15
|
cause: Throwable?
|
|
@@ -152,3 +154,14 @@ internal class CollectionElementCastException(
|
|
|
152
154
|
message = "Cannot cast '${providedType.name}' to '$elementType' required by the collection of type: '$collectionType'.",
|
|
153
155
|
cause
|
|
154
156
|
)
|
|
157
|
+
|
|
158
|
+
@DoNotStrip
|
|
159
|
+
class JavaScriptEvaluateException(
|
|
160
|
+
message: String,
|
|
161
|
+
val jsStack: String
|
|
162
|
+
) : CodedException(
|
|
163
|
+
message = """
|
|
164
|
+
Cannot evaluate JavaScript code: $message.
|
|
165
|
+
$jsStack
|
|
166
|
+
""".trimIndent()
|
|
167
|
+
)
|
|
@@ -5,6 +5,8 @@ internal inline fun <T> exceptionDecorator(decoratorBlock: (e: CodedException) -
|
|
|
5
5
|
block()
|
|
6
6
|
} catch (e: CodedException) {
|
|
7
7
|
throw decoratorBlock(e)
|
|
8
|
+
} catch (e: expo.modules.core.errors.CodedException) {
|
|
9
|
+
throw decoratorBlock(CodedException(e.code, e.message, e.cause))
|
|
8
10
|
} catch (e: Throwable) {
|
|
9
11
|
throw decoratorBlock(UnexpectedException(e))
|
|
10
12
|
}
|
|
@@ -1,37 +1,37 @@
|
|
|
1
1
|
package expo.modules.kotlin.functions
|
|
2
2
|
|
|
3
3
|
import com.facebook.react.bridge.ReadableArray
|
|
4
|
-
import expo.modules.kotlin.
|
|
5
|
-
import expo.modules.kotlin.Promise
|
|
4
|
+
import expo.modules.kotlin.AppContext
|
|
6
5
|
import expo.modules.kotlin.exception.ArgumentCastException
|
|
7
6
|
import expo.modules.kotlin.exception.CodedException
|
|
8
7
|
import expo.modules.kotlin.exception.InvalidArgsNumberException
|
|
9
8
|
import expo.modules.kotlin.exception.exceptionDecorator
|
|
10
9
|
import expo.modules.kotlin.iterator
|
|
10
|
+
import expo.modules.kotlin.jni.JavaScriptModuleObject
|
|
11
11
|
import expo.modules.kotlin.recycle
|
|
12
12
|
import expo.modules.kotlin.types.AnyType
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Base class of all exported functions
|
|
16
|
+
*/
|
|
14
17
|
abstract class AnyFunction(
|
|
15
18
|
protected val name: String,
|
|
16
19
|
private val desiredArgsTypes: Array<AnyType>
|
|
17
20
|
) {
|
|
21
|
+
internal val argsCount get() = desiredArgsTypes.size
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Tries to convert arguments from RN representation to expected types.
|
|
25
|
+
*
|
|
26
|
+
* @return An array of converted arguments
|
|
27
|
+
* @throws `CodedException` if conversion isn't possible
|
|
28
|
+
*/
|
|
18
29
|
@Throws(CodedException::class)
|
|
19
|
-
fun
|
|
30
|
+
protected fun convertArgs(args: ReadableArray): Array<out Any?> {
|
|
20
31
|
if (desiredArgsTypes.size != args.size()) {
|
|
21
32
|
throw InvalidArgsNumberException(args.size(), desiredArgsTypes.size)
|
|
22
33
|
}
|
|
23
34
|
|
|
24
|
-
val convertedArgs = convertArgs(args)
|
|
25
|
-
callImplementation(module, convertedArgs, promise)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
@Throws(CodedException::class)
|
|
29
|
-
internal abstract fun callImplementation(holder: ModuleHolder, args: Array<out Any?>, promise: Promise)
|
|
30
|
-
|
|
31
|
-
val argsCount get() = desiredArgsTypes.size
|
|
32
|
-
|
|
33
|
-
@Throws(CodedException::class)
|
|
34
|
-
private fun convertArgs(args: ReadableArray): Array<out Any?> {
|
|
35
35
|
val finalArgs = Array<Any?>(desiredArgsTypes.size) { null }
|
|
36
36
|
val argIterator = args.iterator()
|
|
37
37
|
desiredArgsTypes
|
|
@@ -47,4 +47,9 @@ abstract class AnyFunction(
|
|
|
47
47
|
}
|
|
48
48
|
return finalArgs
|
|
49
49
|
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Attaches current function to the provided js object.
|
|
53
|
+
*/
|
|
54
|
+
abstract fun attachToJSObject(appContext: AppContext, jsObject: JavaScriptModuleObject)
|
|
50
55
|
}
|
|
@@ -1,15 +1,37 @@
|
|
|
1
1
|
package expo.modules.kotlin.functions
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import com.facebook.react.bridge.ReadableArray
|
|
4
|
+
import expo.modules.kotlin.AppContext
|
|
5
|
+
import expo.modules.kotlin.KPromiseWrapper
|
|
4
6
|
import expo.modules.kotlin.Promise
|
|
7
|
+
import expo.modules.kotlin.exception.CodedException
|
|
8
|
+
import expo.modules.kotlin.exception.UnexpectedException
|
|
9
|
+
import expo.modules.kotlin.jni.JavaScriptModuleObject
|
|
5
10
|
import expo.modules.kotlin.types.AnyType
|
|
11
|
+
import kotlinx.coroutines.launch
|
|
6
12
|
|
|
7
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Base class of all function components that require a promise to be called.
|
|
15
|
+
*/
|
|
16
|
+
abstract class AsyncFunction(
|
|
8
17
|
name: String,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
18
|
+
desiredArgsTypes: Array<AnyType>
|
|
19
|
+
) : AnyFunction(name, desiredArgsTypes) {
|
|
20
|
+
@Throws(CodedException::class)
|
|
21
|
+
abstract fun call(args: ReadableArray, promise: Promise)
|
|
22
|
+
|
|
23
|
+
override fun attachToJSObject(appContext: AppContext, jsObject: JavaScriptModuleObject) {
|
|
24
|
+
jsObject.registerAsyncFunction(name, argsCount) { args, bridgePromise ->
|
|
25
|
+
val kotlinPromise = KPromiseWrapper(bridgePromise as com.facebook.react.bridge.Promise)
|
|
26
|
+
appContext.modulesQueue.launch {
|
|
27
|
+
try {
|
|
28
|
+
call(args, kotlinPromise)
|
|
29
|
+
} catch (e: CodedException) {
|
|
30
|
+
kotlinPromise.reject(e)
|
|
31
|
+
} catch (e: Throwable) {
|
|
32
|
+
kotlinPromise.reject(UnexpectedException(e))
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
14
36
|
}
|
|
15
37
|
}
|
|
@@ -6,9 +6,9 @@ package expo.modules.kotlin.functions
|
|
|
6
6
|
import expo.modules.kotlin.types.toAnyType
|
|
7
7
|
import kotlin.reflect.typeOf
|
|
8
8
|
|
|
9
|
-
class AsyncFunctionBuilder(val name: String) {
|
|
9
|
+
class AsyncFunctionBuilder(@PublishedApi internal val name: String) {
|
|
10
10
|
@PublishedApi
|
|
11
|
-
internal var
|
|
11
|
+
internal var functionBuilder: SuspendFunctionComponentBuilder? = null
|
|
12
12
|
|
|
13
13
|
@Deprecated(
|
|
14
14
|
message = "The 'suspendBody' component was renamed to 'SuspendBody'.",
|
|
@@ -17,7 +17,7 @@ class AsyncFunctionBuilder(val name: String) {
|
|
|
17
17
|
inline fun <reified R> suspendBody(crossinline block: suspend () -> R) = SuspendBody(block)
|
|
18
18
|
|
|
19
19
|
inline fun <reified R> SuspendBody(crossinline block: suspend () -> R) {
|
|
20
|
-
|
|
20
|
+
functionBuilder = SuspendFunctionComponentBuilder(name, arrayOf()) { block() }
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
@Deprecated(
|
|
@@ -27,7 +27,7 @@ class AsyncFunctionBuilder(val name: String) {
|
|
|
27
27
|
inline fun <reified R, reified P0> suspendBody(crossinline block: suspend (p0: P0) -> R) = SuspendBody(block)
|
|
28
28
|
|
|
29
29
|
inline fun <reified R, reified P0> SuspendBody(crossinline block: suspend (p0: P0) -> R) {
|
|
30
|
-
|
|
30
|
+
functionBuilder = SuspendFunctionComponentBuilder(name, arrayOf(typeOf<P0>().toAnyType())) { block(it[0] as P0) }
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
@Deprecated(
|
|
@@ -37,7 +37,7 @@ class AsyncFunctionBuilder(val name: String) {
|
|
|
37
37
|
inline fun <reified R, reified P0, reified P1> suspendBody(crossinline block: suspend (p0: P0, p1: P1) -> R) = SuspendBody(block)
|
|
38
38
|
|
|
39
39
|
inline fun <reified R, reified P0, reified P1> SuspendBody(crossinline block: suspend (p0: P0, p1: P1) -> R) {
|
|
40
|
-
|
|
40
|
+
functionBuilder = SuspendFunctionComponentBuilder(name, arrayOf(typeOf<P0>().toAnyType())) { block(it[0] as P0, it[0] as P1) }
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
@Deprecated(
|
|
@@ -47,7 +47,7 @@ class AsyncFunctionBuilder(val name: String) {
|
|
|
47
47
|
inline fun <reified R, reified P0, reified P1, reified P2> suspendBody(crossinline block: suspend (p0: P0, p1: P1, p2: P2) -> R) = SuspendBody(block)
|
|
48
48
|
|
|
49
49
|
inline fun <reified R, reified P0, reified P1, reified P2> SuspendBody(crossinline block: suspend (p0: P0, p1: P1, p2: P2) -> R) {
|
|
50
|
-
|
|
50
|
+
functionBuilder = SuspendFunctionComponentBuilder(name, arrayOf(typeOf<P0>().toAnyType())) { block(it[0] as P0, it[1] as P1, it[2] as P2) }
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
@Deprecated(
|
|
@@ -57,7 +57,7 @@ class AsyncFunctionBuilder(val name: String) {
|
|
|
57
57
|
inline fun <reified R, reified P0, reified P1, reified P2, reified P3> suspendBody(crossinline block: suspend (p0: P0, p1: P1, p2: P2, p3: P3) -> R) = SuspendBody(block)
|
|
58
58
|
|
|
59
59
|
inline fun <reified R, reified P0, reified P1, reified P2, reified P3> SuspendBody(crossinline block: suspend (p0: P0, p1: P1, p2: P2, p3: P3) -> R) {
|
|
60
|
-
|
|
60
|
+
functionBuilder = SuspendFunctionComponentBuilder(name, arrayOf(typeOf<P0>().toAnyType())) { block(it[0] as P0, it[1] as P1, it[2] as P2, it[3] as P3) }
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
@Deprecated(
|
|
@@ -67,7 +67,7 @@ class AsyncFunctionBuilder(val name: String) {
|
|
|
67
67
|
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4> suspendBody(crossinline block: suspend (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) -> R) = SuspendBody(block)
|
|
68
68
|
|
|
69
69
|
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4> SuspendBody(crossinline block: suspend (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) -> R) {
|
|
70
|
-
|
|
70
|
+
functionBuilder = SuspendFunctionComponentBuilder(name, arrayOf(typeOf<P0>().toAnyType())) { block(it[0] as P0, it[1] as P1, it[2] as P2, it[3] as P3, it[4] as P4) }
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
@Deprecated(
|
|
@@ -77,7 +77,7 @@ class AsyncFunctionBuilder(val name: String) {
|
|
|
77
77
|
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5> suspendBody(crossinline block: suspend (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) -> R) = SuspendBody(block)
|
|
78
78
|
|
|
79
79
|
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5> SuspendBody(crossinline block: suspend (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) -> R) {
|
|
80
|
-
|
|
80
|
+
functionBuilder = SuspendFunctionComponentBuilder(name, arrayOf(typeOf<P0>().toAnyType())) { block(it[0] as P0, it[1] as P1, it[2] as P2, it[3] as P3, it[4] as P4, it[5] as P5) }
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
@Deprecated(
|
|
@@ -87,7 +87,7 @@ class AsyncFunctionBuilder(val name: String) {
|
|
|
87
87
|
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5, reified P6> suspendBody(crossinline block: suspend (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6) -> R) = SuspendBody(block)
|
|
88
88
|
|
|
89
89
|
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5, reified P6> SuspendBody(crossinline block: suspend (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6) -> R) {
|
|
90
|
-
|
|
90
|
+
functionBuilder = SuspendFunctionComponentBuilder(name, arrayOf(typeOf<P0>().toAnyType())) { block(it[0] as P0, it[1] as P1, it[2] as P2, it[3] as P3, it[4] as P4, it[5] as P5, it[6] as P6) }
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
@Deprecated(
|
|
@@ -97,11 +97,11 @@ class AsyncFunctionBuilder(val name: String) {
|
|
|
97
97
|
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5, reified P6, reified P7> suspendBody(crossinline block: suspend (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7) -> R) = SuspendBody(block)
|
|
98
98
|
|
|
99
99
|
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5, reified P6, reified P7> SuspendBody(crossinline block: suspend (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7) -> R) {
|
|
100
|
-
|
|
100
|
+
functionBuilder = SuspendFunctionComponentBuilder(name, arrayOf(typeOf<P0>().toAnyType())) { block(it[0] as P0, it[1] as P1, it[2] as P2, it[3] as P3, it[4] as P4, it[5] as P5, it[6] as P6, it[7] as P7) }
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
internal fun build():
|
|
104
|
-
return
|
|
103
|
+
internal fun build(): SuspendFunctionComponentBuilder {
|
|
104
|
+
return requireNotNull(functionBuilder)
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
package expo.modules.kotlin.functions
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.ReadableArray
|
|
4
|
+
import expo.modules.kotlin.Promise
|
|
5
|
+
import expo.modules.kotlin.exception.CodedException
|
|
6
|
+
import expo.modules.kotlin.types.AnyType
|
|
7
|
+
|
|
8
|
+
class AsyncFunctionComponent(
|
|
9
|
+
name: String,
|
|
10
|
+
desiredArgsTypes: Array<AnyType>,
|
|
11
|
+
private val body: (args: Array<out Any?>) -> Any?
|
|
12
|
+
) : AsyncFunction(name, desiredArgsTypes) {
|
|
13
|
+
@Throws(CodedException::class)
|
|
14
|
+
override fun call(args: ReadableArray, promise: Promise) {
|
|
15
|
+
val convertedArgs = convertArgs(args)
|
|
16
|
+
promise.resolve(body(convertedArgs))
|
|
17
|
+
}
|
|
18
|
+
}
|
package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromiseComponent.kt
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
package expo.modules.kotlin.functions
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.ReadableArray
|
|
4
|
+
import expo.modules.kotlin.Promise
|
|
5
|
+
import expo.modules.kotlin.exception.CodedException
|
|
6
|
+
import expo.modules.kotlin.types.AnyType
|
|
7
|
+
|
|
8
|
+
class AsyncFunctionWithPromiseComponent(
|
|
9
|
+
name: String,
|
|
10
|
+
desiredArgsTypes: Array<AnyType>,
|
|
11
|
+
private val body: (args: Array<out Any?>, promise: Promise) -> Unit
|
|
12
|
+
) : AsyncFunction(name, desiredArgsTypes) {
|
|
13
|
+
@Throws(CodedException::class)
|
|
14
|
+
override fun call(args: ReadableArray, promise: Promise) {
|
|
15
|
+
val convertedArgs = convertArgs(args)
|
|
16
|
+
body(convertedArgs, promise)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
package expo.modules.kotlin.functions
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.ReadableArray
|
|
4
|
+
import expo.modules.kotlin.ModuleHolder
|
|
5
|
+
import expo.modules.kotlin.Promise
|
|
6
|
+
import expo.modules.kotlin.exception.CodedException
|
|
7
|
+
import expo.modules.kotlin.exception.FunctionCallException
|
|
8
|
+
import expo.modules.kotlin.exception.UnexpectedException
|
|
9
|
+
import expo.modules.kotlin.exception.exceptionDecorator
|
|
10
|
+
import expo.modules.kotlin.types.AnyType
|
|
11
|
+
import kotlinx.coroutines.CoroutineScope
|
|
12
|
+
import kotlinx.coroutines.isActive
|
|
13
|
+
import kotlinx.coroutines.launch
|
|
14
|
+
import java.lang.ref.WeakReference
|
|
15
|
+
import kotlin.jvm.Throws
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* We can't construct a `SuspendFunctionComponent` in the build phase, because it has to have access to module coroutine scope.
|
|
19
|
+
* So we create another builder to store needed information and build it later - during the holder initialization.
|
|
20
|
+
*/
|
|
21
|
+
class SuspendFunctionComponentBuilder(
|
|
22
|
+
internal val name: String,
|
|
23
|
+
private val desiredArgsTypes: Array<AnyType>,
|
|
24
|
+
private val body: suspend CoroutineScope.(args: Array<out Any?>) -> Any?,
|
|
25
|
+
) {
|
|
26
|
+
fun build(moduleHolder: ModuleHolder) =
|
|
27
|
+
SuspendFunctionComponent(name, desiredArgsTypes, WeakReference(moduleHolder), body)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
class SuspendFunctionComponent(
|
|
31
|
+
name: String,
|
|
32
|
+
desiredArgsTypes: Array<AnyType>,
|
|
33
|
+
private val moduleHolderRef: WeakReference<ModuleHolder>,
|
|
34
|
+
private val body: suspend CoroutineScope.(args: Array<out Any?>) -> Any?
|
|
35
|
+
) : AsyncFunction(name, desiredArgsTypes) {
|
|
36
|
+
@Throws(CodedException::class)
|
|
37
|
+
override fun call(args: ReadableArray, promise: Promise) {
|
|
38
|
+
val holder = moduleHolderRef.get() ?: return
|
|
39
|
+
val scope = holder.module.coroutineScopeDelegate.value
|
|
40
|
+
val convertedArgs = convertArgs(args)
|
|
41
|
+
scope.launch {
|
|
42
|
+
try {
|
|
43
|
+
val result = exceptionDecorator({ cause -> FunctionCallException(name, holder.name, cause) }) {
|
|
44
|
+
body.invoke(scope, convertedArgs)
|
|
45
|
+
}
|
|
46
|
+
if (isActive) {
|
|
47
|
+
promise.resolve(result)
|
|
48
|
+
}
|
|
49
|
+
} catch (e: CodedException) {
|
|
50
|
+
promise.reject(e)
|
|
51
|
+
} catch (e: Throwable) {
|
|
52
|
+
promise.reject(UnexpectedException(e))
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
package expo.modules.kotlin.functions
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.Arguments
|
|
4
|
+
import com.facebook.react.bridge.ReadableArray
|
|
5
|
+
import expo.modules.kotlin.AppContext
|
|
6
|
+
import expo.modules.kotlin.exception.CodedException
|
|
7
|
+
import expo.modules.kotlin.jni.JavaScriptModuleObject
|
|
8
|
+
import expo.modules.kotlin.types.AnyType
|
|
9
|
+
import expo.modules.kotlin.types.JSTypeConverter
|
|
10
|
+
|
|
11
|
+
class SyncFunctionComponent(
|
|
12
|
+
name: String,
|
|
13
|
+
desiredArgsTypes: Array<AnyType>,
|
|
14
|
+
private val body: (args: Array<out Any?>) -> Any?
|
|
15
|
+
) : AnyFunction(name, desiredArgsTypes) {
|
|
16
|
+
@Throws(CodedException::class)
|
|
17
|
+
fun call(args: ReadableArray): Any? {
|
|
18
|
+
return body(convertArgs(args))
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
override fun attachToJSObject(appContext: AppContext, jsObject: JavaScriptModuleObject) {
|
|
22
|
+
jsObject.registerSyncFunction(name, argsCount) { args ->
|
|
23
|
+
val result = call(args)
|
|
24
|
+
val convertedResult = JSTypeConverter.convertToJSValue(result)
|
|
25
|
+
return@registerSyncFunction Arguments.fromJavaArgs(arrayOf(convertedResult))
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
package expo.modules.kotlin.jni
|
|
2
|
+
|
|
3
|
+
private var nextValue = 0
|
|
4
|
+
|
|
5
|
+
private fun nextValue(): Int = (1 shl nextValue).also { nextValue++ }
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Enum that represents Cpp types. Objects of those types can be obtained via JNI.
|
|
9
|
+
*/
|
|
10
|
+
enum class CppType(val value: Int) {
|
|
11
|
+
DOUBLE(nextValue()),
|
|
12
|
+
BOOLEAN(nextValue()),
|
|
13
|
+
STRING(nextValue()),
|
|
14
|
+
JS_OBJECT(nextValue()),
|
|
15
|
+
JS_VALUE(nextValue()),
|
|
16
|
+
READABLE_ARRAY(nextValue()),
|
|
17
|
+
READABLE_MAP(nextValue());
|
|
18
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
package expo.modules.kotlin.jni
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.ReadableNativeArray
|
|
4
|
+
import expo.modules.core.interfaces.DoNotStrip
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* It's a wrapper for a promise-less function that will be invoked from JS.
|
|
8
|
+
* This interface is intended to be passed to cpp code.
|
|
9
|
+
* If you want to modify it, please don't forget to change the corresponding jni::JavaClass.
|
|
10
|
+
*/
|
|
11
|
+
@DoNotStrip
|
|
12
|
+
fun interface JNIFunctionBody {
|
|
13
|
+
/**
|
|
14
|
+
* Invokes the Kotlin part of the JNI function.
|
|
15
|
+
*
|
|
16
|
+
* We used a [com.facebook.react.bridge.ReadableNativeArray] to communicate with CPP, because
|
|
17
|
+
* right now it's the only object which is recognizable by those two worlds.
|
|
18
|
+
* In the future, we may want to swap it for something else.
|
|
19
|
+
*/
|
|
20
|
+
@DoNotStrip
|
|
21
|
+
fun invoke(args: ReadableNativeArray): ReadableNativeArray?
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* It's a wrapper for a promise function that will be invoked from JS.
|
|
26
|
+
* This interface is intended to be passed to cpp code.
|
|
27
|
+
* If you want to modify it, please don't forget to change the corresponding jni::JavaClass.
|
|
28
|
+
*/
|
|
29
|
+
@DoNotStrip
|
|
30
|
+
fun interface JNIAsyncFunctionBody {
|
|
31
|
+
/**
|
|
32
|
+
* Invokes the Kotlin part of the JNI function.
|
|
33
|
+
*
|
|
34
|
+
* Note: that the `bridgePromise` has type of [Any], but it should be an instance of [com.facebook.react.bridge.Promise].
|
|
35
|
+
* This is dictated by the fact that [com.facebook.react.bridge.Promise] isn't a hybrid object of jni::HybridClass.
|
|
36
|
+
*/
|
|
37
|
+
@DoNotStrip
|
|
38
|
+
fun invoke(args: ReadableNativeArray, bridgePromise: Any)
|
|
39
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
package expo.modules.kotlin.jni
|
|
2
|
+
|
|
3
|
+
import com.facebook.jni.HybridData
|
|
4
|
+
import com.facebook.react.turbomodule.core.CallInvokerHolderImpl
|
|
5
|
+
import expo.modules.core.interfaces.DoNotStrip
|
|
6
|
+
import expo.modules.kotlin.AppContext
|
|
7
|
+
import expo.modules.kotlin.exception.JavaScriptEvaluateException
|
|
8
|
+
import java.lang.ref.WeakReference
|
|
9
|
+
|
|
10
|
+
@Suppress("KotlinJniMissingFunction")
|
|
11
|
+
@DoNotStrip
|
|
12
|
+
class JSIInteropModuleRegistry(appContext: AppContext) {
|
|
13
|
+
private val appContextHolder = WeakReference(appContext)
|
|
14
|
+
|
|
15
|
+
// Has to be called "mHybridData" - fbjni uses it via reflection
|
|
16
|
+
@DoNotStrip
|
|
17
|
+
private val mHybridData = initHybrid()
|
|
18
|
+
|
|
19
|
+
private external fun initHybrid(): HybridData
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Initializes the `ExpoModulesHostObject` and adds it to the global object.
|
|
23
|
+
*/
|
|
24
|
+
external fun installJSI(
|
|
25
|
+
jsRuntimePointer: Long,
|
|
26
|
+
jsInvokerHolder: CallInvokerHolderImpl,
|
|
27
|
+
nativeInvokerHolder: CallInvokerHolderImpl
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Initializes the test runtime. Shouldn't be used in the production.
|
|
32
|
+
*/
|
|
33
|
+
external fun installJSIForTests()
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Evaluates given JavaScript source code.
|
|
37
|
+
* @throws JavaScriptEvaluateException if the input format is unknown or evaluation causes an error
|
|
38
|
+
*/
|
|
39
|
+
@Throws(JavaScriptEvaluateException::class)
|
|
40
|
+
external fun evaluateScript(script: String): JavaScriptValue
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Returns the runtime global object
|
|
44
|
+
*/
|
|
45
|
+
external fun global(): JavaScriptObject
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Returns a new instance of [JavaScriptObject]
|
|
49
|
+
*/
|
|
50
|
+
external fun createObject(): JavaScriptObject
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Drains the JavaScript VM internal Microtask (a.k.a. event loop) queue.
|
|
54
|
+
*/
|
|
55
|
+
external fun drainJSEventLoop()
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Returns a `JavaScriptModuleObject` that is a bridge between [expo.modules.kotlin.modules.Module]
|
|
59
|
+
* and HostObject exported via JSI.
|
|
60
|
+
*
|
|
61
|
+
* This function will be called from the CPP implementation.
|
|
62
|
+
* It doesn't make sense to call it from Kotlin.
|
|
63
|
+
*/
|
|
64
|
+
@Suppress("unused")
|
|
65
|
+
@DoNotStrip
|
|
66
|
+
fun getJavaScriptModuleObject(name: String): JavaScriptModuleObject? {
|
|
67
|
+
return appContextHolder.get()?.registry?.getModuleHolder(name)?.jsObject
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Returns an array that contains names of available modules.
|
|
72
|
+
*/
|
|
73
|
+
@Suppress("unused")
|
|
74
|
+
@DoNotStrip
|
|
75
|
+
fun getJavaScriptModulesName(): Array<String> {
|
|
76
|
+
return appContextHolder.get()?.registry?.registry?.keys?.toTypedArray() ?: emptyArray()
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
@Throws(Throwable::class)
|
|
80
|
+
protected fun finalize() {
|
|
81
|
+
mHybridData.resetNative()
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
companion object {
|
|
85
|
+
init {
|
|
86
|
+
System.loadLibrary("expo-modules-core")
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
package expo.modules.kotlin.jni
|
|
2
|
+
|
|
3
|
+
import com.facebook.jni.HybridData
|
|
4
|
+
import com.facebook.react.bridge.NativeMap
|
|
5
|
+
import expo.modules.core.interfaces.DoNotStrip
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A class to communicate with CPP part of the [expo.modules.kotlin.modules.Module] class.
|
|
9
|
+
* Used to register exported JSI functions.
|
|
10
|
+
* The lifetime of instances of this class should be in sync with the lifetime of the bridge.
|
|
11
|
+
* All exported functions/objects will have a reference to the `JavaScriptModuleObject`,
|
|
12
|
+
* so it must outlive the current RN context.
|
|
13
|
+
*/
|
|
14
|
+
@Suppress("KotlinJniMissingFunction")
|
|
15
|
+
@DoNotStrip
|
|
16
|
+
class JavaScriptModuleObject {
|
|
17
|
+
// Has to be called "mHybridData" - fbjni uses it via reflection
|
|
18
|
+
@DoNotStrip
|
|
19
|
+
private val mHybridData = initHybrid()
|
|
20
|
+
|
|
21
|
+
private external fun initHybrid(): HybridData
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Exports constants
|
|
25
|
+
*/
|
|
26
|
+
external fun exportConstants(constants: NativeMap)
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Register a promise-less function on the CPP module representation.
|
|
30
|
+
* After calling this function, user can access the exported function in the JS code.
|
|
31
|
+
*/
|
|
32
|
+
external fun registerSyncFunction(name: String, args: Int, body: JNIFunctionBody)
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Register a promise function on the CPP module representation.
|
|
36
|
+
* After calling this function, user can access the exported function in the JS code.
|
|
37
|
+
*/
|
|
38
|
+
external fun registerAsyncFunction(name: String, args: Int, body: JNIAsyncFunctionBody)
|
|
39
|
+
|
|
40
|
+
@Throws(Throwable::class)
|
|
41
|
+
protected fun finalize() {
|
|
42
|
+
mHybridData.resetNative()
|
|
43
|
+
}
|
|
44
|
+
}
|