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.
Files changed (33) hide show
  1. package/CHANGELOG.md +14 -1
  2. package/android/build.gradle +22 -9
  3. package/android/src/compose/expo/modules/kotlin/views/ModuleDefinitionBuilderComposeExtension.kt +35 -0
  4. package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +2 -2
  5. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionBuilder.kt +17 -17
  6. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionComponent.kt +75 -68
  7. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromiseComponent.kt +1 -1
  8. package/android/src/main/java/expo/modules/kotlin/functions/UntypedAsyncFunctionComponent.kt +84 -0
  9. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +8 -25
  10. package/android/src/main/java/expo/modules/kotlin/objects/ObjectDefinitionBuilder.kt +19 -19
  11. package/android/src/main/java/expo/modules/kotlin/views/ViewDefinitionBuilder.kt +19 -19
  12. package/android/src/withoutCompose/expo/modules/kotlin/views/ModuleDefinitionBuilderComposeExtension.kt +10 -0
  13. package/common/cpp/TestingSyncJSCallInvoker.h +0 -10
  14. package/ios/Api/Builders/ViewDefinitionBuilder.swift +5 -0
  15. package/ios/Core/Functions/AsyncFunctionDefinition.swift +1 -0
  16. package/ios/Core/Functions/ConcurrentFunctionDefinition.swift +20 -2
  17. package/ios/Core/Promise.swift +8 -6
  18. package/ios/Core/Views/SwiftUI/SwiftUIViewDefinition.swift +2 -1
  19. package/ios/Core/Views/SwiftUI/SwiftUIViewDefinitionBuilder.swift +5 -0
  20. package/ios/JSI/EXJSIConversions.mm +4 -0
  21. package/ios/JSI/EXJavaScriptRuntime.mm +2 -2
  22. package/ios/JSI/EXJavaScriptSharedObjectBinding.h +25 -0
  23. package/ios/JSI/EXJavaScriptSharedObjectBinding.mm +24 -0
  24. package/ios/TestUtils/MainThreadInvoker.h +14 -0
  25. package/ios/TestUtils/MainThreadInvoker.mm +19 -0
  26. package/ios/TestUtils/TestingJSCallInvoker.h +46 -0
  27. package/ios/Tests/FunctionSpec.swift +18 -6
  28. package/package.json +3 -3
  29. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunction.kt +0 -91
  30. /package/android/src/{main/java → compose}/expo/modules/kotlin/views/AutoSizingComposable.kt +0 -0
  31. /package/android/src/{main/java → compose}/expo/modules/kotlin/views/ComposeProps.kt +0 -0
  32. /package/android/src/{main/java → compose}/expo/modules/kotlin/views/ComposeViewProp.kt +0 -0
  33. /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
 
@@ -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
- classpath("org.jetbrains.kotlin.plugin.compose:org.jetbrains.kotlin.plugin.compose.gradle.plugin:${kotlinVersion}")
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.8'
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.8"
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 true
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
- implementation 'androidx.compose.foundation:foundation-android:1.7.6'
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
 
@@ -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.AsyncFunction
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 AsyncFunction) {
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?): AsyncFunction {
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): AsyncFunction {
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): AsyncFunction {
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): AsyncFunction {
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): AsyncFunction {
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): AsyncFunction {
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): AsyncFunction {
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): AsyncFunction {
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): AsyncFunction {
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): AsyncFunction {
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): AsyncFunction {
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): AsyncFunction {
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): AsyncFunction {
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): AsyncFunction {
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): AsyncFunction {
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): AsyncFunction {
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): AsyncFunction {
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.types.enforceType
12
+ import expo.modules.kotlin.weak
13
+ import kotlinx.coroutines.launch
7
14
 
8
- inline fun <reified ReturnType> createAsyncFunctionComponent(
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
- noinline body: (args: Array<out Any?>) -> ReturnType
12
- ): AsyncFunction {
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
- class IntAsyncFunctionComponent(name: String, desiredArgsTypes: Array<AnyType>, body: (args: Array<out Any?>) -> Int) :
42
- AsyncFunctionComponent<Int>(name, desiredArgsTypes, body) {
43
- override fun callUserImplementation(args: Array<Any?>, promise: Promise, appContext: AppContext) {
44
- promise.resolve(body(convertArgs(args, appContext)))
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
- class BoolAsyncFunctionComponent(name: String, desiredArgsTypes: Array<AnyType>, body: (args: Array<out Any?>) -> Boolean) :
49
- AsyncFunctionComponent<Boolean>(name, desiredArgsTypes, body) {
50
- override fun callUserImplementation(args: Array<Any?>, promise: Promise, appContext: AppContext) {
51
- promise.resolve(body(convertArgs(args, appContext)))
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
- class DoubleAsyncFunctionComponent(name: String, desiredArgsTypes: Array<AnyType>, body: (args: Array<out Any?>) -> Double) :
56
- AsyncFunctionComponent<Double>(name, desiredArgsTypes, body) {
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
- class FloatAsyncFunctionComponent(name: String, desiredArgsTypes: Array<AnyType>, body: (args: Array<out Any?>) -> Float) :
63
- AsyncFunctionComponent<Float>(name, desiredArgsTypes, body) {
64
- override fun callUserImplementation(args: Array<Any?>, promise: Promise, appContext: AppContext) {
65
- promise.resolve(body(convertArgs(args, appContext)))
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
- class StringAsyncFunctionComponent(name: String, desiredArgsTypes: Array<AnyType>, body: (args: Array<out Any?>) -> String) :
70
- AsyncFunctionComponent<String>(name, desiredArgsTypes, body) {
71
- override fun callUserImplementation(args: Array<Any?>, promise: Promise, appContext: AppContext) {
72
- promise.resolve(body(convertArgs(args, appContext)))
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
- open class AsyncFunctionComponent<ReturnType>(
77
- name: String,
78
- desiredArgsTypes: Array<AnyType>,
79
- protected val body: (args: Array<out Any?>) -> ReturnType
80
- ) : AsyncFunction(name, desiredArgsTypes) {
81
- override fun callUserImplementation(args: Array<Any?>, promise: Promise, appContext: AppContext) {
82
- promise.resolve(body(convertArgs(args, appContext)))
80
+ appContext.mainQueue.launch {
81
+ block()
82
+ }
83
+ }
84
+
85
+ is CustomQueue ->
86
+ queue.scope.launch {
87
+ block()
88
+ }
89
+ }
83
90
  }
84
91
  }
@@ -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
- ) : AsyncFunction(name, desiredArgsTypes) {
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.ComposeViewProp
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
- fun registerViewDefinition(definition: ViewManagerDefinition) {
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
  */