expo-modules-core 2.3.8 → 2.3.10
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 +14 -1
- package/android/build.gradle +22 -9
- package/android/src/compose/expo/modules/kotlin/views/ModuleDefinitionBuilderComposeExtension.kt +35 -0
- package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +2 -2
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionBuilder.kt +17 -17
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionComponent.kt +75 -68
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromiseComponent.kt +1 -1
- package/android/src/main/java/expo/modules/kotlin/functions/UntypedAsyncFunctionComponent.kt +84 -0
- package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +8 -25
- package/android/src/main/java/expo/modules/kotlin/objects/ObjectDefinitionBuilder.kt +19 -19
- package/android/src/main/java/expo/modules/kotlin/views/ViewDefinitionBuilder.kt +19 -19
- package/android/src/withoutCompose/expo/modules/kotlin/views/ModuleDefinitionBuilderComposeExtension.kt +10 -0
- package/common/cpp/TestingSyncJSCallInvoker.h +0 -10
- package/ios/Api/Builders/ViewDefinitionBuilder.swift +5 -0
- package/ios/Core/Functions/AsyncFunctionDefinition.swift +1 -0
- package/ios/Core/Functions/ConcurrentFunctionDefinition.swift +20 -2
- package/ios/Core/Promise.swift +8 -6
- package/ios/Core/Views/SwiftUI/SwiftUIViewDefinition.swift +2 -1
- package/ios/Core/Views/SwiftUI/SwiftUIViewDefinitionBuilder.swift +5 -0
- package/ios/JSI/EXJSIConversions.mm +4 -0
- package/ios/JSI/EXJavaScriptRuntime.mm +2 -2
- package/ios/JSI/EXJavaScriptSharedObjectBinding.h +25 -0
- package/ios/JSI/EXJavaScriptSharedObjectBinding.mm +24 -0
- package/ios/TestUtils/MainThreadInvoker.h +14 -0
- package/ios/TestUtils/MainThreadInvoker.mm +19 -0
- package/ios/TestUtils/TestingJSCallInvoker.h +46 -0
- package/ios/Tests/FunctionSpec.swift +18 -6
- package/package.json +3 -3
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunction.kt +0 -91
- /package/android/src/{main/java → compose}/expo/modules/kotlin/views/AutoSizingComposable.kt +0 -0
- /package/android/src/{main/java → compose}/expo/modules/kotlin/views/ComposeProps.kt +0 -0
- /package/android/src/{main/java → compose}/expo/modules/kotlin/views/ComposeViewProp.kt +0 -0
- /package/android/src/{main/java → compose}/expo/modules/kotlin/views/ExpoComposeView.kt +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -10,11 +10,24 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 2.3.10 — 2025-04-28
|
|
14
|
+
|
|
15
|
+
### 🐛 Bug fixes
|
|
16
|
+
|
|
17
|
+
- [iOS] Fix concurrent functions on views. ([#36431](https://github.com/expo/expo/pull/36431) by [@alanjhughes](https://github.com/alanjhughes))
|
|
18
|
+
|
|
19
|
+
## 2.3.9 — 2025-04-25
|
|
20
|
+
|
|
21
|
+
### 💡 Others
|
|
22
|
+
|
|
23
|
+
- Removes `Jetpack Compose` integration if not needed. ([#36353](https://github.com/expo/expo/pull/36353) by [@lukmccall](https://github.com/lukmccall))
|
|
24
|
+
- Refined `Children` return type for SwiftUI integration. ([#36377](https://github.com/expo/expo/pull/36377) by [@kudo](https://github.com/kudo))
|
|
25
|
+
|
|
13
26
|
## 2.3.8 — 2025-04-23
|
|
14
27
|
|
|
15
28
|
### 💡 Others
|
|
16
29
|
|
|
17
|
-
- Droped support for Kotlin < `2.0.0`.
|
|
30
|
+
- Droped support for Kotlin < `2.0.0`. ([#36323](https://github.com/expo/expo/pull/36323) by [@lukmccall](https://github.com/lukmccall))
|
|
18
31
|
|
|
19
32
|
## 2.3.7 — 2025-04-22
|
|
20
33
|
|
package/android/build.gradle
CHANGED
|
@@ -2,25 +2,30 @@ import expo.modules.plugin.gradle.ExpoModuleExtension
|
|
|
2
2
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
|
3
3
|
|
|
4
4
|
buildscript {
|
|
5
|
+
// List of features that are required by linked modules
|
|
6
|
+
def coreFeatures = project.findProperty("coreFeatures") ?: []
|
|
7
|
+
ext.shouldIncludeCompose = coreFeatures.contains("compose")
|
|
8
|
+
|
|
5
9
|
repositories {
|
|
6
10
|
mavenCentral()
|
|
7
11
|
}
|
|
8
12
|
|
|
9
13
|
dependencies {
|
|
10
|
-
|
|
14
|
+
if (shouldIncludeCompose) {
|
|
15
|
+
classpath("org.jetbrains.kotlin.plugin.compose:org.jetbrains.kotlin.plugin.compose.gradle.plugin:${kotlinVersion}")
|
|
16
|
+
}
|
|
11
17
|
}
|
|
12
18
|
}
|
|
13
19
|
|
|
14
20
|
apply plugin: 'com.android.library'
|
|
15
21
|
apply plugin: 'expo-module-gradle-plugin'
|
|
16
|
-
apply plugin: 'org.jetbrains.kotlin.plugin.compose'
|
|
17
22
|
|
|
23
|
+
if (shouldIncludeCompose) {
|
|
24
|
+
apply plugin: 'org.jetbrains.kotlin.plugin.compose'
|
|
25
|
+
}
|
|
18
26
|
|
|
19
27
|
group = 'host.exp.exponent'
|
|
20
|
-
version = '2.3.
|
|
21
|
-
|
|
22
|
-
// List of features that are required by linked modules
|
|
23
|
-
def coreFeatures = project.findProperty("coreFeatures") ?: []
|
|
28
|
+
version = '2.3.10'
|
|
24
29
|
|
|
25
30
|
def isExpoModulesCoreTests = {
|
|
26
31
|
Gradle gradle = getGradle()
|
|
@@ -70,7 +75,7 @@ android {
|
|
|
70
75
|
defaultConfig {
|
|
71
76
|
consumerProguardFiles 'proguard-rules.pro'
|
|
72
77
|
versionCode 1
|
|
73
|
-
versionName "2.3.
|
|
78
|
+
versionName "2.3.10"
|
|
74
79
|
buildConfigField "String", "EXPO_MODULES_CORE_VERSION", "\"${versionName}\""
|
|
75
80
|
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled.toString()
|
|
76
81
|
|
|
@@ -98,7 +103,7 @@ android {
|
|
|
98
103
|
buildFeatures {
|
|
99
104
|
buildConfig true
|
|
100
105
|
prefab true
|
|
101
|
-
compose
|
|
106
|
+
compose shouldIncludeCompose
|
|
102
107
|
}
|
|
103
108
|
|
|
104
109
|
packagingOptions {
|
|
@@ -155,6 +160,12 @@ android {
|
|
|
155
160
|
// TODO(kudo,20241112): Remove this when we drop react-native 0.76 support
|
|
156
161
|
srcDirs += 'src/rn74'
|
|
157
162
|
}
|
|
163
|
+
|
|
164
|
+
if (shouldIncludeCompose) {
|
|
165
|
+
srcDirs += 'src/compose'
|
|
166
|
+
} else {
|
|
167
|
+
srcDirs += 'src/withoutCompose'
|
|
168
|
+
}
|
|
158
169
|
}
|
|
159
170
|
}
|
|
160
171
|
}
|
|
@@ -183,7 +194,9 @@ dependencies {
|
|
|
183
194
|
api "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3"
|
|
184
195
|
api "androidx.core:core-ktx:1.13.1"
|
|
185
196
|
|
|
186
|
-
|
|
197
|
+
if (shouldIncludeCompose) {
|
|
198
|
+
implementation 'androidx.compose.foundation:foundation-android:1.7.6'
|
|
199
|
+
}
|
|
187
200
|
|
|
188
201
|
implementation("androidx.tracing:tracing-ktx:1.2.0")
|
|
189
202
|
|
package/android/src/compose/expo/modules/kotlin/views/ModuleDefinitionBuilderComposeExtension.kt
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
@file:Suppress("FunctionName")
|
|
2
|
+
|
|
3
|
+
package expo.modules.kotlin.views
|
|
4
|
+
|
|
5
|
+
import expo.modules.kotlin.modules.InternalModuleDefinitionBuilder
|
|
6
|
+
import expo.modules.kotlin.modules.Module
|
|
7
|
+
import expo.modules.kotlin.types.AnyType
|
|
8
|
+
import expo.modules.kotlin.types.LazyKType
|
|
9
|
+
import expo.modules.kotlin.views.decorators.UseCSSProps
|
|
10
|
+
import kotlin.reflect.KClass
|
|
11
|
+
import kotlin.reflect.full.memberProperties
|
|
12
|
+
import kotlin.reflect.typeOf
|
|
13
|
+
|
|
14
|
+
open class ModuleDefinitionBuilderWithCompose(
|
|
15
|
+
module: Module? = null
|
|
16
|
+
) : InternalModuleDefinitionBuilder(module) {
|
|
17
|
+
/**
|
|
18
|
+
* Creates the view manager definition that scopes other view-related definitions.
|
|
19
|
+
* Also collects all compose view props and generates setters.
|
|
20
|
+
*/
|
|
21
|
+
@JvmName("ComposeView")
|
|
22
|
+
inline fun <reified T : ExpoComposeView<P>, reified P : Any> View(viewClass: KClass<T>, body: ViewDefinitionBuilder<T>.() -> Unit = {}) {
|
|
23
|
+
val viewDefinitionBuilder = ViewDefinitionBuilder(viewClass, LazyKType(classifier = T::class, kTypeProvider = { typeOf<T>() }))
|
|
24
|
+
P::class.memberProperties.forEach { prop ->
|
|
25
|
+
val kType = prop.returnType.arguments.first().type
|
|
26
|
+
if (kType != null) {
|
|
27
|
+
viewDefinitionBuilder.props[prop.name] = ComposeViewProp(prop.name, AnyType(kType), prop)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
viewDefinitionBuilder.UseCSSProps()
|
|
32
|
+
body.invoke(viewDefinitionBuilder)
|
|
33
|
+
registerViewDefinition(viewDefinitionBuilder.build())
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -8,7 +8,7 @@ import expo.modules.kotlin.events.EventName
|
|
|
8
8
|
import expo.modules.kotlin.exception.FunctionCallException
|
|
9
9
|
import expo.modules.kotlin.exception.MethodNotFoundException
|
|
10
10
|
import expo.modules.kotlin.exception.exceptionDecorator
|
|
11
|
-
import expo.modules.kotlin.functions.
|
|
11
|
+
import expo.modules.kotlin.functions.AsyncFunctionComponent
|
|
12
12
|
import expo.modules.kotlin.jni.JavaScriptModuleObject
|
|
13
13
|
import expo.modules.kotlin.jni.decorators.JSDecoratorsBridgingObject
|
|
14
14
|
import expo.modules.kotlin.modules.DEFAULT_MODULE_VIEW
|
|
@@ -131,7 +131,7 @@ class ModuleHolder<T : Module>(val module: T) {
|
|
|
131
131
|
val method = definition.asyncFunctions[methodName]
|
|
132
132
|
?: throw MethodNotFoundException()
|
|
133
133
|
|
|
134
|
-
if (method is
|
|
134
|
+
if (method is AsyncFunctionComponent) {
|
|
135
135
|
method.callUserImplementation(args, promise, module.appContext)
|
|
136
136
|
return@exceptionDecorator
|
|
137
137
|
}
|
|
@@ -92,19 +92,19 @@ class AsyncFunctionBuilder(@PublishedApi internal val name: String) {
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
@JvmName("AsyncBodyWithoutArgs")
|
|
95
|
-
inline fun AsyncBody(crossinline body: () -> Any?):
|
|
95
|
+
inline fun AsyncBody(crossinline body: () -> Any?): AsyncFunctionComponent {
|
|
96
96
|
return createAsyncFunctionComponent(name, emptyArray()) { body() }.also {
|
|
97
97
|
asyncFunctionComponent = it
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
inline fun <reified R> AsyncBody(crossinline body: () -> R):
|
|
101
|
+
inline fun <reified R> AsyncBody(crossinline body: () -> R): AsyncFunctionComponent {
|
|
102
102
|
return createAsyncFunctionComponent(name, emptyArray()) { body() }.also {
|
|
103
103
|
asyncFunctionComponent = it
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
inline fun <reified R, reified P0> AsyncBody(crossinline body: (p0: P0) -> R):
|
|
107
|
+
inline fun <reified R, reified P0> AsyncBody(crossinline body: (p0: P0) -> R): AsyncFunctionComponent {
|
|
108
108
|
return if (P0::class == Promise::class) {
|
|
109
109
|
AsyncFunctionWithPromiseComponent(name, emptyArray()) { _, promise -> body(promise as P0) }
|
|
110
110
|
} else {
|
|
@@ -117,7 +117,7 @@ class AsyncFunctionBuilder(@PublishedApi internal val name: String) {
|
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
inline fun <reified R, reified P0, reified P1> AsyncBody(crossinline body: (p0: P0, p1: P1) -> R):
|
|
120
|
+
inline fun <reified R, reified P0, reified P1> AsyncBody(crossinline body: (p0: P0, p1: P1) -> R): AsyncFunctionComponent {
|
|
121
121
|
return createAsyncFunctionComponent(name, toArgsArray<P0, P1>()) { (p0, p1) ->
|
|
122
122
|
enforceType<P0, P1>(p0, p1)
|
|
123
123
|
body(p0, p1)
|
|
@@ -127,7 +127,7 @@ class AsyncFunctionBuilder(@PublishedApi internal val name: String) {
|
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
@JvmName("AsyncFunctionWithPromise")
|
|
130
|
-
inline fun <reified R, reified P0> AsyncBody(crossinline body: (p0: P0, p1: Promise) -> R):
|
|
130
|
+
inline fun <reified R, reified P0> AsyncBody(crossinline body: (p0: P0, p1: Promise) -> R): AsyncFunctionComponent {
|
|
131
131
|
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0>()) { (p0), promise ->
|
|
132
132
|
enforceType<P0>(p0)
|
|
133
133
|
body(p0, promise)
|
|
@@ -136,7 +136,7 @@ class AsyncFunctionBuilder(@PublishedApi internal val name: String) {
|
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
-
inline fun <reified R, reified P0, reified P1, reified P2> AsyncBody(crossinline body: (p0: P0, p1: P1, p2: P2) -> R):
|
|
139
|
+
inline fun <reified R, reified P0, reified P1, reified P2> AsyncBody(crossinline body: (p0: P0, p1: P1, p2: P2) -> R): AsyncFunctionComponent {
|
|
140
140
|
return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2>()) { (p0, p1, p2) ->
|
|
141
141
|
enforceType<P0, P1, P2>(p0, p1, p2)
|
|
142
142
|
body(p0, p1, p2)
|
|
@@ -146,7 +146,7 @@ class AsyncFunctionBuilder(@PublishedApi internal val name: String) {
|
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
@JvmName("AsyncFunctionWithPromise")
|
|
149
|
-
inline fun <reified R, reified P0, reified P1> AsyncBody(crossinline body: (p0: P0, p1: P1, p2: Promise) -> R):
|
|
149
|
+
inline fun <reified R, reified P0, reified P1> AsyncBody(crossinline body: (p0: P0, p1: P1, p2: Promise) -> R): AsyncFunctionComponent {
|
|
150
150
|
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1>()) { (p0, p1), promise ->
|
|
151
151
|
enforceType<P0, P1>(p0, p1)
|
|
152
152
|
body(p0, p1, promise)
|
|
@@ -155,7 +155,7 @@ class AsyncFunctionBuilder(@PublishedApi internal val name: String) {
|
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
inline fun <reified R, reified P0, reified P1, reified P2, reified P3> AsyncBody(crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3) -> R):
|
|
158
|
+
inline fun <reified R, reified P0, reified P1, reified P2, reified P3> AsyncBody(crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3) -> R): AsyncFunctionComponent {
|
|
159
159
|
return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3>()) { (p0, p1, p2, p3) ->
|
|
160
160
|
enforceType<P0, P1, P2, P3>(p0, p1, p2, p3)
|
|
161
161
|
body(p0, p1, p2, p3)
|
|
@@ -165,7 +165,7 @@ class AsyncFunctionBuilder(@PublishedApi internal val name: String) {
|
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
@JvmName("AsyncFunctionWithPromise")
|
|
168
|
-
inline fun <reified R, reified P0, reified P1, reified P2> AsyncBody(crossinline body: (p0: P0, p1: P1, p2: P2, p3: Promise) -> R):
|
|
168
|
+
inline fun <reified R, reified P0, reified P1, reified P2> AsyncBody(crossinline body: (p0: P0, p1: P1, p2: P2, p3: Promise) -> R): AsyncFunctionComponent {
|
|
169
169
|
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2>()) { (p0, p1, p2), promise ->
|
|
170
170
|
enforceType<P0, P1, P2>(p0, p1, p2)
|
|
171
171
|
body(p0, p1, p2, promise)
|
|
@@ -174,7 +174,7 @@ class AsyncFunctionBuilder(@PublishedApi internal val name: String) {
|
|
|
174
174
|
}
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
-
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4> AsyncBody(crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) -> R):
|
|
177
|
+
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4> AsyncBody(crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) -> R): AsyncFunctionComponent {
|
|
178
178
|
return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4>()) { (p0, p1, p2, p3, p4) ->
|
|
179
179
|
enforceType<P0, P1, P2, P3, P4>(p0, p1, p2, p3, p4)
|
|
180
180
|
body(p0, p1, p2, p3, p4)
|
|
@@ -184,7 +184,7 @@ class AsyncFunctionBuilder(@PublishedApi internal val name: String) {
|
|
|
184
184
|
}
|
|
185
185
|
|
|
186
186
|
@JvmName("AsyncFunctionWithPromise")
|
|
187
|
-
inline fun <reified R, reified P0, reified P1, reified P2, reified P3> AsyncBody(crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: Promise) -> R):
|
|
187
|
+
inline fun <reified R, reified P0, reified P1, reified P2, reified P3> AsyncBody(crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: Promise) -> R): AsyncFunctionComponent {
|
|
188
188
|
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2, P3>()) { (p0, p1, p2, p3), promise ->
|
|
189
189
|
enforceType<P0, P1, P2, P3>(p0, p1, p2, p3)
|
|
190
190
|
body(p0, p1, p2, p3, promise)
|
|
@@ -193,7 +193,7 @@ class AsyncFunctionBuilder(@PublishedApi internal val name: String) {
|
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
-
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5> AsyncBody(crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) -> R):
|
|
196
|
+
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5> AsyncBody(crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) -> R): AsyncFunctionComponent {
|
|
197
197
|
return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5>()) { (p0, p1, p2, p3, p4, p5) ->
|
|
198
198
|
enforceType<P0, P1, P2, P3, P4, P5>(p0, p1, p2, p3, p4, p5)
|
|
199
199
|
body(p0, p1, p2, p3, p4, p5)
|
|
@@ -203,7 +203,7 @@ class AsyncFunctionBuilder(@PublishedApi internal val name: String) {
|
|
|
203
203
|
}
|
|
204
204
|
|
|
205
205
|
@JvmName("AsyncFunctionWithPromise")
|
|
206
|
-
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4> AsyncBody(crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: Promise) -> R):
|
|
206
|
+
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4> AsyncBody(crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: Promise) -> R): AsyncFunctionComponent {
|
|
207
207
|
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2, P3, P4>()) { (p0, p1, p2, p3, p4), promise ->
|
|
208
208
|
enforceType<P0, P1, P2, P3, P4>(p0, p1, p2, p3, p4)
|
|
209
209
|
body(p0, p1, p2, p3, p4, promise)
|
|
@@ -212,7 +212,7 @@ class AsyncFunctionBuilder(@PublishedApi internal val name: String) {
|
|
|
212
212
|
}
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
-
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5, reified P6> AsyncBody(crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6) -> R):
|
|
215
|
+
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5, reified P6> AsyncBody(crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6) -> R): AsyncFunctionComponent {
|
|
216
216
|
return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5, P6>()) { (p0, p1, p2, p3, p4, p5, p6) ->
|
|
217
217
|
enforceType<P0, P1, P2, P3, P4, P5, P6>(p0, p1, p2, p3, p4, p5, p6)
|
|
218
218
|
body(p0, p1, p2, p3, p4, p5, p6)
|
|
@@ -222,7 +222,7 @@ class AsyncFunctionBuilder(@PublishedApi internal val name: String) {
|
|
|
222
222
|
}
|
|
223
223
|
|
|
224
224
|
@JvmName("AsyncFunctionWithPromise")
|
|
225
|
-
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5> AsyncBody(crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: Promise) -> R):
|
|
225
|
+
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5> AsyncBody(crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: Promise) -> R): AsyncFunctionComponent {
|
|
226
226
|
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5>()) { (p0, p1, p2, p3, p4, p5), promise ->
|
|
227
227
|
enforceType<P0, P1, P2, P3, P4, P5>(p0, p1, p2, p3, p4, p5)
|
|
228
228
|
body(p0, p1, p2, p3, p4, p5, promise)
|
|
@@ -231,7 +231,7 @@ class AsyncFunctionBuilder(@PublishedApi internal val name: String) {
|
|
|
231
231
|
}
|
|
232
232
|
}
|
|
233
233
|
|
|
234
|
-
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5, reified P6, reified P7> AsyncBody(crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7) -> R):
|
|
234
|
+
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5, reified P6, reified P7> AsyncBody(crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7) -> R): AsyncFunctionComponent {
|
|
235
235
|
return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5, P6, P7>()) { (p0, p1, p2, p3, p4, p5, p6, p7) ->
|
|
236
236
|
enforceType<P0, P1, P2, P3, P4, P5, P6, P7>(p0, p1, p2, p3, p4, p5, p6, p7)
|
|
237
237
|
body(p0, p1, p2, p3, p4, p5, p6, p7)
|
|
@@ -241,7 +241,7 @@ class AsyncFunctionBuilder(@PublishedApi internal val name: String) {
|
|
|
241
241
|
}
|
|
242
242
|
|
|
243
243
|
@JvmName("AsyncFunctionWithPromise")
|
|
244
|
-
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5, reified P6> AsyncBody(crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: Promise) -> R):
|
|
244
|
+
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5, reified P6> AsyncBody(crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: Promise) -> R): AsyncFunctionComponent {
|
|
245
245
|
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5, P6>()) { (p0, p1, p2, p3, p4, p5, p6), promise ->
|
|
246
246
|
enforceType<P0, P1, P2, P3, P4, P5, P6>(p0, p1, p2, p3, p4, p5, p6)
|
|
247
247
|
body(p0, p1, p2, p3, p4, p5, p6, promise)
|
|
@@ -1,84 +1,91 @@
|
|
|
1
1
|
package expo.modules.kotlin.functions
|
|
2
2
|
|
|
3
|
+
import android.view.View
|
|
4
|
+
import expo.modules.BuildConfig
|
|
3
5
|
import expo.modules.kotlin.AppContext
|
|
4
6
|
import expo.modules.kotlin.Promise
|
|
7
|
+
import expo.modules.kotlin.exception.FunctionCallException
|
|
8
|
+
import expo.modules.kotlin.exception.exceptionDecorator
|
|
9
|
+
import expo.modules.kotlin.exception.toCodedException
|
|
10
|
+
import expo.modules.kotlin.jni.decorators.JSDecoratorsBridgingObject
|
|
5
11
|
import expo.modules.kotlin.types.AnyType
|
|
6
|
-
import expo.modules.kotlin.
|
|
12
|
+
import expo.modules.kotlin.weak
|
|
13
|
+
import kotlinx.coroutines.launch
|
|
7
14
|
|
|
8
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Base class of async function components that require a promise to be called.
|
|
17
|
+
*/
|
|
18
|
+
abstract class AsyncFunctionComponent(
|
|
9
19
|
name: String,
|
|
10
|
-
desiredArgsTypes: Array<AnyType
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
if (null is ReturnType) {
|
|
14
|
-
return AsyncFunctionComponent<Any?>(name, desiredArgsTypes, body)
|
|
15
|
-
}
|
|
16
|
-
return when (ReturnType::class.java) {
|
|
17
|
-
Int::class.java -> {
|
|
18
|
-
enforceType<(Array<out Any?>) -> Int>(body)
|
|
19
|
-
IntAsyncFunctionComponent(name, desiredArgsTypes, body)
|
|
20
|
-
}
|
|
21
|
-
Boolean::class.java -> {
|
|
22
|
-
enforceType<(Array<out Any?>) -> Boolean>(body)
|
|
23
|
-
BoolAsyncFunctionComponent(name, desiredArgsTypes, body)
|
|
24
|
-
}
|
|
25
|
-
Double::class.java -> {
|
|
26
|
-
enforceType<(Array<out Any?>) -> Double>(body)
|
|
27
|
-
DoubleAsyncFunctionComponent(name, desiredArgsTypes, body)
|
|
28
|
-
}
|
|
29
|
-
Float::class.java -> {
|
|
30
|
-
enforceType<(Array<out Any?>) -> Float>(body)
|
|
31
|
-
FloatAsyncFunctionComponent(name, desiredArgsTypes, body)
|
|
32
|
-
}
|
|
33
|
-
String::class.java -> {
|
|
34
|
-
enforceType<(Array<out Any?>) -> String>(body)
|
|
35
|
-
StringAsyncFunctionComponent(name, desiredArgsTypes, body)
|
|
36
|
-
}
|
|
37
|
-
else -> AsyncFunctionComponent<Any?>(name, desiredArgsTypes, body)
|
|
38
|
-
}
|
|
39
|
-
}
|
|
20
|
+
desiredArgsTypes: Array<AnyType>
|
|
21
|
+
) : BaseAsyncFunctionComponent(name, desiredArgsTypes) {
|
|
22
|
+
internal abstract fun callUserImplementation(args: Array<Any?>, promise: Promise, appContext: AppContext)
|
|
40
23
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
24
|
+
override fun attachToJSObject(appContext: AppContext, jsObject: JSDecoratorsBridgingObject, moduleName: String) {
|
|
25
|
+
val appContextHolder = appContext.weak()
|
|
26
|
+
jsObject.registerAsyncFunction(
|
|
27
|
+
name,
|
|
28
|
+
takesOwner,
|
|
29
|
+
isEnumerable,
|
|
30
|
+
desiredArgsTypes.map { it.getCppRequiredTypes() }.toTypedArray()
|
|
31
|
+
) { args, promiseImpl ->
|
|
32
|
+
if (BuildConfig.DEBUG) {
|
|
33
|
+
promiseImpl.decorateWithDebugInformation(
|
|
34
|
+
appContextHolder,
|
|
35
|
+
moduleName,
|
|
36
|
+
name
|
|
37
|
+
)
|
|
38
|
+
}
|
|
47
39
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
40
|
+
val functionBody = {
|
|
41
|
+
try {
|
|
42
|
+
exceptionDecorator({
|
|
43
|
+
FunctionCallException(name, moduleName, it)
|
|
44
|
+
}) {
|
|
45
|
+
callUserImplementation(args, promiseImpl, appContext)
|
|
46
|
+
}
|
|
47
|
+
} catch (e: Throwable) {
|
|
48
|
+
// The promise was resolved, so we should rethrow the error.
|
|
49
|
+
if (promiseImpl.wasSettled) {
|
|
50
|
+
throw e
|
|
51
|
+
}
|
|
52
|
+
promiseImpl.reject(e.toCodedException())
|
|
53
|
+
}
|
|
54
|
+
}
|
|
54
55
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
override fun callUserImplementation(args: Array<Any?>, promise: Promise, appContext: AppContext) {
|
|
58
|
-
promise.resolve(body(convertArgs(args, appContext)))
|
|
56
|
+
dispatchOnQueue(appContext, functionBody)
|
|
57
|
+
}
|
|
59
58
|
}
|
|
60
|
-
}
|
|
61
59
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
60
|
+
private fun dispatchOnQueue(appContext: AppContext, block: () -> Unit) {
|
|
61
|
+
when (val queue = queue) {
|
|
62
|
+
Queues.DEFAULT -> {
|
|
63
|
+
appContext.modulesQueue.launch {
|
|
64
|
+
block()
|
|
65
|
+
}
|
|
66
|
+
}
|
|
68
67
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
68
|
+
Queues.MAIN -> {
|
|
69
|
+
if (!BuildConfig.IS_NEW_ARCHITECTURE_ENABLED && desiredArgsTypes.any { it.inheritFrom<View>() }) {
|
|
70
|
+
// On certain occasions, invoking a function on a view could lead to an error
|
|
71
|
+
// because of the asynchronous communication between the JavaScript and native components.
|
|
72
|
+
// In such cases, the native view may not have been mounted yet,
|
|
73
|
+
// but the JavaScript code has already received the future tag of the view.
|
|
74
|
+
// To avoid this issue, we have decided to temporarily utilize
|
|
75
|
+
// the UIManagerModule for dispatching functions on the main thread.
|
|
76
|
+
appContext.dispatchOnMainUsingUIManager(block)
|
|
77
|
+
return
|
|
78
|
+
}
|
|
75
79
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
appContext.mainQueue.launch {
|
|
81
|
+
block()
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
is CustomQueue ->
|
|
86
|
+
queue.scope.launch {
|
|
87
|
+
block()
|
|
88
|
+
}
|
|
89
|
+
}
|
|
83
90
|
}
|
|
84
91
|
}
|
package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromiseComponent.kt
CHANGED
|
@@ -8,7 +8,7 @@ class AsyncFunctionWithPromiseComponent(
|
|
|
8
8
|
name: String,
|
|
9
9
|
desiredArgsTypes: Array<AnyType>,
|
|
10
10
|
private val body: (args: Array<out Any?>, promise: Promise) -> Unit
|
|
11
|
-
) :
|
|
11
|
+
) : AsyncFunctionComponent(name, desiredArgsTypes) {
|
|
12
12
|
override fun callUserImplementation(args: Array<Any?>, promise: Promise, appContext: AppContext) {
|
|
13
13
|
body(convertArgs(args, appContext), promise)
|
|
14
14
|
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
package expo.modules.kotlin.functions
|
|
2
|
+
|
|
3
|
+
import expo.modules.kotlin.AppContext
|
|
4
|
+
import expo.modules.kotlin.Promise
|
|
5
|
+
import expo.modules.kotlin.types.AnyType
|
|
6
|
+
import expo.modules.kotlin.types.enforceType
|
|
7
|
+
|
|
8
|
+
inline fun <reified ReturnType> createAsyncFunctionComponent(
|
|
9
|
+
name: String,
|
|
10
|
+
desiredArgsTypes: Array<AnyType>,
|
|
11
|
+
noinline body: (args: Array<out Any?>) -> ReturnType
|
|
12
|
+
): AsyncFunctionComponent {
|
|
13
|
+
if (null is ReturnType) {
|
|
14
|
+
return UntypedAsyncFunctionComponent<Any?>(name, desiredArgsTypes, body)
|
|
15
|
+
}
|
|
16
|
+
return when (ReturnType::class.java) {
|
|
17
|
+
Int::class.java -> {
|
|
18
|
+
enforceType<(Array<out Any?>) -> Int>(body)
|
|
19
|
+
IntAsyncFunctionComponent(name, desiredArgsTypes, body)
|
|
20
|
+
}
|
|
21
|
+
Boolean::class.java -> {
|
|
22
|
+
enforceType<(Array<out Any?>) -> Boolean>(body)
|
|
23
|
+
BoolAsyncFunctionComponent(name, desiredArgsTypes, body)
|
|
24
|
+
}
|
|
25
|
+
Double::class.java -> {
|
|
26
|
+
enforceType<(Array<out Any?>) -> Double>(body)
|
|
27
|
+
DoubleAsyncFunctionComponent(name, desiredArgsTypes, body)
|
|
28
|
+
}
|
|
29
|
+
Float::class.java -> {
|
|
30
|
+
enforceType<(Array<out Any?>) -> Float>(body)
|
|
31
|
+
FloatAsyncFunctionComponent(name, desiredArgsTypes, body)
|
|
32
|
+
}
|
|
33
|
+
String::class.java -> {
|
|
34
|
+
enforceType<(Array<out Any?>) -> String>(body)
|
|
35
|
+
StringAsyncFunctionComponent(name, desiredArgsTypes, body)
|
|
36
|
+
}
|
|
37
|
+
else -> UntypedAsyncFunctionComponent<Any?>(name, desiredArgsTypes, body)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
class IntAsyncFunctionComponent(name: String, desiredArgsTypes: Array<AnyType>, body: (args: Array<out Any?>) -> Int) :
|
|
42
|
+
UntypedAsyncFunctionComponent<Int>(name, desiredArgsTypes, body) {
|
|
43
|
+
override fun callUserImplementation(args: Array<Any?>, promise: Promise, appContext: AppContext) {
|
|
44
|
+
promise.resolve(body(convertArgs(args, appContext)))
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
class BoolAsyncFunctionComponent(name: String, desiredArgsTypes: Array<AnyType>, body: (args: Array<out Any?>) -> Boolean) :
|
|
49
|
+
UntypedAsyncFunctionComponent<Boolean>(name, desiredArgsTypes, body) {
|
|
50
|
+
override fun callUserImplementation(args: Array<Any?>, promise: Promise, appContext: AppContext) {
|
|
51
|
+
promise.resolve(body(convertArgs(args, appContext)))
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
class DoubleAsyncFunctionComponent(name: String, desiredArgsTypes: Array<AnyType>, body: (args: Array<out Any?>) -> Double) :
|
|
56
|
+
UntypedAsyncFunctionComponent<Double>(name, desiredArgsTypes, body) {
|
|
57
|
+
override fun callUserImplementation(args: Array<Any?>, promise: Promise, appContext: AppContext) {
|
|
58
|
+
promise.resolve(body(convertArgs(args, appContext)))
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
class FloatAsyncFunctionComponent(name: String, desiredArgsTypes: Array<AnyType>, body: (args: Array<out Any?>) -> Float) :
|
|
63
|
+
UntypedAsyncFunctionComponent<Float>(name, desiredArgsTypes, body) {
|
|
64
|
+
override fun callUserImplementation(args: Array<Any?>, promise: Promise, appContext: AppContext) {
|
|
65
|
+
promise.resolve(body(convertArgs(args, appContext)))
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
class StringAsyncFunctionComponent(name: String, desiredArgsTypes: Array<AnyType>, body: (args: Array<out Any?>) -> String) :
|
|
70
|
+
UntypedAsyncFunctionComponent<String>(name, desiredArgsTypes, body) {
|
|
71
|
+
override fun callUserImplementation(args: Array<Any?>, promise: Promise, appContext: AppContext) {
|
|
72
|
+
promise.resolve(body(convertArgs(args, appContext)))
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
open class UntypedAsyncFunctionComponent<ReturnType>(
|
|
77
|
+
name: String,
|
|
78
|
+
desiredArgsTypes: Array<AnyType>,
|
|
79
|
+
protected val body: (args: Array<out Any?>) -> ReturnType
|
|
80
|
+
) : AsyncFunctionComponent(name, desiredArgsTypes) {
|
|
81
|
+
override fun callUserImplementation(args: Array<Any?>, promise: Promise, appContext: AppContext) {
|
|
82
|
+
promise.resolve(body(convertArgs(args, appContext)))
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -16,22 +16,23 @@ import expo.modules.kotlin.events.EventName
|
|
|
16
16
|
import expo.modules.kotlin.events.OnActivityResultPayload
|
|
17
17
|
import expo.modules.kotlin.objects.ObjectDefinitionBuilder
|
|
18
18
|
import expo.modules.kotlin.sharedobjects.SharedObject
|
|
19
|
-
import expo.modules.kotlin.types.AnyType
|
|
20
19
|
import expo.modules.kotlin.types.LazyKType
|
|
21
20
|
import expo.modules.kotlin.types.toAnyType
|
|
22
|
-
import expo.modules.kotlin.views.
|
|
23
|
-
import expo.modules.kotlin.views.ExpoComposeView
|
|
21
|
+
import expo.modules.kotlin.views.ModuleDefinitionBuilderWithCompose
|
|
24
22
|
import expo.modules.kotlin.views.ViewDefinitionBuilder
|
|
25
23
|
import expo.modules.kotlin.views.ViewManagerDefinition
|
|
26
24
|
import expo.modules.kotlin.views.decorators.UseCSSProps
|
|
27
25
|
import kotlin.reflect.KClass
|
|
28
|
-
import kotlin.reflect.full.memberProperties
|
|
29
26
|
import kotlin.reflect.typeOf
|
|
30
27
|
|
|
31
28
|
const val DEFAULT_MODULE_VIEW = "DEFAULT_MODULE_VIEW"
|
|
32
29
|
|
|
33
|
-
@DefinitionMarker
|
|
34
30
|
class ModuleDefinitionBuilder(
|
|
31
|
+
module: Module? = null
|
|
32
|
+
) : ModuleDefinitionBuilderWithCompose(module)
|
|
33
|
+
|
|
34
|
+
@DefinitionMarker
|
|
35
|
+
open class InternalModuleDefinitionBuilder(
|
|
35
36
|
@PublishedApi internal val module: Module? = null
|
|
36
37
|
) : ObjectDefinitionBuilder(
|
|
37
38
|
module
|
|
@@ -72,7 +73,8 @@ class ModuleDefinitionBuilder(
|
|
|
72
73
|
this.name = name
|
|
73
74
|
}
|
|
74
75
|
|
|
75
|
-
|
|
76
|
+
@PublishedApi
|
|
77
|
+
internal fun registerViewDefinition(definition: ViewManagerDefinition) {
|
|
76
78
|
// For backwards compatibility, the first View is also added to viewManagerDefinitions under the `DEFAULT` key
|
|
77
79
|
if (definition.name != null) {
|
|
78
80
|
require(!viewManagerDefinitions.contains(definition.name)) { "The module definition defines more than one view with name ${definition.name}." }
|
|
@@ -95,25 +97,6 @@ class ModuleDefinitionBuilder(
|
|
|
95
97
|
registerViewDefinition(viewDefinitionBuilder.build())
|
|
96
98
|
}
|
|
97
99
|
|
|
98
|
-
/**
|
|
99
|
-
* Creates the view manager definition that scopes other view-related definitions.
|
|
100
|
-
* Also collects all compose view props and generates setters.
|
|
101
|
-
*/
|
|
102
|
-
@JvmName("ComposeView")
|
|
103
|
-
inline fun <reified T : ExpoComposeView<P>, reified P : Any> View(viewClass: KClass<T>, body: ViewDefinitionBuilder<T>.() -> Unit = {}) {
|
|
104
|
-
val viewDefinitionBuilder = ViewDefinitionBuilder(viewClass, LazyKType(classifier = T::class, kTypeProvider = { typeOf<T>() }))
|
|
105
|
-
P::class.memberProperties.forEach { prop ->
|
|
106
|
-
val kType = prop.returnType.arguments.first().type
|
|
107
|
-
if (kType != null) {
|
|
108
|
-
viewDefinitionBuilder.props[prop.name] = ComposeViewProp(prop.name, AnyType(kType), prop)
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
viewDefinitionBuilder.UseCSSProps()
|
|
113
|
-
body.invoke(viewDefinitionBuilder)
|
|
114
|
-
registerViewDefinition(viewDefinitionBuilder.build())
|
|
115
|
-
}
|
|
116
|
-
|
|
117
100
|
/**
|
|
118
101
|
* Creates module's lifecycle listener that is called right after the module initialization.
|
|
119
102
|
*/
|