expo-modules-core 1.2.7 → 1.3.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.
Files changed (180) hide show
  1. package/CHANGELOG.md +28 -5
  2. package/ExpoModulesCore.podspec +1 -0
  3. package/README.md +1 -1
  4. package/android/ExpoModulesCorePlugin.gradle +16 -0
  5. package/android/build.gradle +3 -2
  6. package/android/src/main/cpp/Exceptions.cpp +8 -0
  7. package/android/src/main/cpp/Exceptions.h +11 -0
  8. package/android/src/main/cpp/ExpoModulesHostObject.cpp +22 -5
  9. package/android/src/main/cpp/ExpoModulesHostObject.h +5 -0
  10. package/android/src/main/cpp/JNIInjector.cpp +2 -0
  11. package/android/src/main/cpp/JSIInteropModuleRegistry.cpp +25 -1
  12. package/android/src/main/cpp/JSIInteropModuleRegistry.h +14 -0
  13. package/android/src/main/cpp/JSIObjectWrapper.h +15 -4
  14. package/android/src/main/cpp/JSITypeConverter.h +3 -2
  15. package/android/src/main/cpp/JavaReferencesCache.cpp +2 -0
  16. package/android/src/main/cpp/JavaScriptFunction.cpp +56 -0
  17. package/android/src/main/cpp/JavaScriptFunction.h +54 -0
  18. package/android/src/main/cpp/JavaScriptModuleObject.cpp +225 -105
  19. package/android/src/main/cpp/JavaScriptModuleObject.h +67 -34
  20. package/android/src/main/cpp/JavaScriptObject.cpp +55 -1
  21. package/android/src/main/cpp/JavaScriptObject.h +17 -13
  22. package/android/src/main/cpp/JavaScriptRuntime.cpp +12 -3
  23. package/android/src/main/cpp/JavaScriptRuntime.h +9 -1
  24. package/android/src/main/cpp/JavaScriptValue.cpp +9 -0
  25. package/android/src/main/cpp/JavaScriptValue.h +4 -0
  26. package/android/src/main/cpp/MethodMetadata.cpp +66 -87
  27. package/android/src/main/cpp/MethodMetadata.h +18 -16
  28. package/android/src/main/cpp/ObjectDeallocator.h +25 -0
  29. package/android/src/main/cpp/WeakRuntimeHolder.cpp +7 -0
  30. package/android/src/main/cpp/WeakRuntimeHolder.h +4 -0
  31. package/android/src/main/cpp/types/CppType.h +4 -1
  32. package/android/src/main/cpp/types/FrontendConverter.cpp +58 -0
  33. package/android/src/main/cpp/types/FrontendConverter.h +45 -0
  34. package/android/src/main/cpp/types/FrontendConverterProvider.cpp +3 -0
  35. package/android/src/main/cpp/types/JNIToJSIConverter.cpp +88 -0
  36. package/android/src/main/cpp/types/JNIToJSIConverter.h +22 -0
  37. package/android/src/main/java/com/facebook/react/uimanager/ReactStylesDiffMapHelper.kt +10 -0
  38. package/android/src/main/java/expo/modules/kotlin/AppContext.kt +8 -25
  39. package/android/src/main/java/expo/modules/kotlin/FilteredIterator.kt +37 -0
  40. package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +1 -1
  41. package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +30 -23
  42. package/android/src/main/java/expo/modules/kotlin/ModuleRegistry.kt +0 -3
  43. package/android/src/main/java/expo/modules/kotlin/Utils.kt +21 -0
  44. package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultCaller.kt +21 -1
  45. package/android/src/main/java/expo/modules/kotlin/classcomponent/ClassComponentBuilder.kt +112 -0
  46. package/android/src/main/java/expo/modules/kotlin/classcomponent/ClassDefinitionData.kt +10 -0
  47. package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +21 -0
  48. package/android/src/main/java/expo/modules/kotlin/exception/CommonExceptions.kt +15 -0
  49. package/android/src/main/java/expo/modules/kotlin/functions/AnyFunction.kt +17 -3
  50. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunction.kt +38 -8
  51. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionComponent.kt +3 -2
  52. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromiseComponent.kt +3 -2
  53. package/android/src/main/java/expo/modules/kotlin/functions/SuspendFunctionComponent.kt +1 -0
  54. package/android/src/main/java/expo/modules/kotlin/functions/SyncFunctionComponent.kt +18 -11
  55. package/android/src/main/java/expo/modules/kotlin/jni/CppType.kt +4 -1
  56. package/android/src/main/java/expo/modules/kotlin/jni/JNIDeallocator.kt +73 -0
  57. package/android/src/main/java/expo/modules/kotlin/jni/JSIInteropModuleRegistry.kt +28 -2
  58. package/android/src/main/java/expo/modules/kotlin/jni/JavaCallback.kt +8 -1
  59. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptFunction.kt +48 -0
  60. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptModuleObject.kt +40 -3
  61. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptObject.kt +23 -3
  62. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptValue.kt +26 -1
  63. package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +0 -11
  64. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +26 -16
  65. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +3 -1
  66. package/android/src/main/java/expo/modules/kotlin/sharedobjects/SharedObject.kt +12 -0
  67. package/android/src/main/java/expo/modules/kotlin/sharedobjects/SharedObjectRegistry.kt +62 -0
  68. package/android/src/main/java/expo/modules/kotlin/sharedobjects/SharedObjectTypeConverter.kt +27 -0
  69. package/android/src/main/java/expo/modules/kotlin/types/AnyType.kt +2 -1
  70. package/android/src/main/java/expo/modules/kotlin/types/EitherTypeConverter.kt +7 -6
  71. package/android/src/main/java/expo/modules/kotlin/types/JavaScriptFunctionTypeConverter.kt +22 -0
  72. package/android/src/main/java/expo/modules/kotlin/types/TypeConverter.kt +30 -24
  73. package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +45 -1
  74. package/android/src/main/java/expo/modules/kotlin/types/TypedArrayTypeConverter.kt +3 -2
  75. package/android/src/main/java/expo/modules/kotlin/views/AnyViewProp.kt +3 -1
  76. package/android/src/main/java/expo/modules/kotlin/views/ConcreteViewProp.kt +3 -3
  77. package/android/src/main/java/expo/modules/kotlin/views/FilteredReadableMap.kt +53 -0
  78. package/android/src/main/java/expo/modules/kotlin/views/GroupViewManagerWrapper.kt +25 -5
  79. package/android/src/main/java/expo/modules/kotlin/views/SimpleViewManagerWrapper.kt +25 -5
  80. package/android/src/main/java/expo/modules/kotlin/views/ViewDefinitionBuilder.kt +161 -10
  81. package/android/src/main/java/expo/modules/kotlin/views/ViewGroupDefinitionBuilder.kt +0 -67
  82. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinition.kt +6 -7
  83. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerWrapperDelegate.kt +40 -3
  84. package/android/src/main/java/expo/modules/kotlin/views/ViewTypeConverter.kt +44 -0
  85. package/android-annotation/build.gradle +45 -0
  86. package/android-annotation/src/main/java/expo/modules/annotation/Config.kt +7 -0
  87. package/android-annotation/src/main/java/expo/modules/annotation/ConverterBinder.kt +7 -0
  88. package/android-annotation-processor/build.gradle +51 -0
  89. package/android-annotation-processor/src/main/java/expo/modules/annotationprocessor/ExpoSymbolProcessor.kt +175 -0
  90. package/android-annotation-processor/src/main/java/expo/modules/annotationprocessor/ExpoSymbolProcessorProvider.kt +10 -0
  91. package/android-annotation-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider +1 -0
  92. package/build/NativeViewManagerAdapter.native.d.ts.map +1 -1
  93. package/build/NativeViewManagerAdapter.native.js +36 -23
  94. package/build/NativeViewManagerAdapter.native.js.map +1 -1
  95. package/build/requireNativeModule.js +2 -2
  96. package/build/requireNativeModule.js.map +1 -1
  97. package/common/cpp/fabric/ExpoViewProps.cpp +18 -3
  98. package/common/cpp/fabric/ExpoViewProps.h +4 -1
  99. package/ios/Fabric/ExpoFabricView.swift +10 -10
  100. package/ios/Fabric/ExpoFabricViewObjC.h +2 -0
  101. package/ios/Fabric/ExpoFabricViewObjC.mm +17 -2
  102. package/ios/JSI/EXJSIInstaller.mm +1 -1
  103. package/ios/JSI/EXJSIUtils.h +5 -0
  104. package/ios/JSI/EXJSIUtils.mm +17 -0
  105. package/ios/JSI/EXJavaScriptRuntime.h +5 -0
  106. package/ios/JSI/EXJavaScriptRuntime.mm +6 -0
  107. package/ios/JSI/EXJavaScriptValue.h +2 -0
  108. package/ios/JSI/EXJavaScriptValue.mm +8 -0
  109. package/ios/JSI/EXJavaScriptWeakObject.mm +29 -8
  110. package/ios/JSI/EXRawJavaScriptFunction.h +24 -0
  111. package/ios/JSI/EXRawJavaScriptFunction.mm +52 -0
  112. package/ios/JSI/ExpoModulesHostObject.mm +1 -1
  113. package/ios/JSI/JavaScriptValue.swift +28 -1
  114. package/ios/ModuleRegistry/EXModuleRegistry.h +0 -4
  115. package/ios/ModuleRegistry/EXModuleRegistry.m +0 -23
  116. package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +0 -16
  117. package/ios/ModuleRegistryProvider/EXModuleRegistryProvider.m +0 -6
  118. package/ios/NativeModulesProxy/EXNativeModulesProxy.mm +1 -31
  119. package/ios/Swift/AppContext.swift +46 -6
  120. package/ios/Swift/Arguments/Convertible.swift +3 -3
  121. package/ios/Swift/Arguments/Convertibles.swift +5 -5
  122. package/ios/Swift/Classes/ClassComponent.swift +18 -12
  123. package/ios/Swift/Classes/ClassRegistry.swift +31 -0
  124. package/ios/Swift/Conversions.swift +19 -3
  125. package/ios/Swift/Convertibles/Convertibles+Color.swift +3 -3
  126. package/ios/Swift/Convertibles/Either.swift +6 -4
  127. package/ios/Swift/DynamicTypes/AnyDynamicType.swift +18 -2
  128. package/ios/Swift/DynamicTypes/DynamicArrayType.swift +3 -3
  129. package/ios/Swift/DynamicTypes/DynamicConvertibleType.swift +2 -2
  130. package/ios/Swift/DynamicTypes/DynamicEnumType.swift +1 -1
  131. package/ios/Swift/DynamicTypes/DynamicJavaScriptType.swift +27 -0
  132. package/ios/Swift/DynamicTypes/DynamicOptionalType.swift +9 -2
  133. package/ios/Swift/DynamicTypes/DynamicRawType.swift +1 -1
  134. package/ios/Swift/DynamicTypes/DynamicSharedObjectType.swift +16 -2
  135. package/ios/Swift/DynamicTypes/DynamicType.swift +6 -0
  136. package/ios/Swift/DynamicTypes/DynamicTypedArrayType.swift +15 -4
  137. package/ios/Swift/DynamicTypes/DynamicViewType.swift +68 -0
  138. package/ios/Swift/ExpoBridgeModule.swift +1 -1
  139. package/ios/Swift/Functions/AnyFunction.swift +5 -4
  140. package/ios/Swift/Functions/AsyncFunctionComponent.swift +22 -19
  141. package/ios/Swift/Functions/ConcurrentFunctionDefinition.swift +29 -13
  142. package/ios/Swift/Functions/SyncFunctionComponent.swift +26 -15
  143. package/ios/Swift/JavaScriptFunction.swift +68 -0
  144. package/ios/Swift/JavaScriptUtils.swift +57 -18
  145. package/ios/Swift/ModuleHolder.swift +22 -10
  146. package/ios/Swift/Modules/ModuleDefinition.swift +8 -2
  147. package/ios/Swift/Objects/JavaScriptObjectBuilder.swift +8 -8
  148. package/ios/Swift/Objects/ObjectDefinition.swift +17 -15
  149. package/ios/Swift/Objects/PropertyComponent.swift +23 -17
  150. package/ios/Swift/Records/AnyField.swift +1 -1
  151. package/ios/Swift/Records/Field.swift +2 -2
  152. package/ios/Swift/Records/Record.swift +5 -5
  153. package/ios/Swift/SharedObjects/SharedObjectRegistry.swift +4 -0
  154. package/ios/Swift/Views/AnyViewProp.swift +1 -1
  155. package/ios/Swift/Views/ComponentData.swift +37 -2
  156. package/ios/Swift/Views/ConcreteViewProp.swift +2 -2
  157. package/ios/Swift/Views/ViewDefinition.swift +39 -0
  158. package/ios/Swift/Views/ViewModuleWrapper.swift +0 -29
  159. package/ios/Tests/ClassComponentSpec.swift +39 -27
  160. package/ios/Tests/ConvertiblesSpec.swift +75 -49
  161. package/ios/Tests/DynamicTypeSpec.swift +29 -27
  162. package/ios/Tests/EitherSpec.swift +9 -7
  163. package/ios/Tests/ExpoModulesSpec.swift +13 -13
  164. package/ios/Tests/FunctionSpec.swift +38 -22
  165. package/ios/Tests/JavaScriptRuntimeSpec.swift +4 -0
  166. package/ios/Tests/PropertyComponentSpec.swift +33 -30
  167. package/ios/Tests/RecordSpec.swift +7 -5
  168. package/ios/Tests/SharedObjectRegistrySpec.swift +12 -12
  169. package/ios/Tests/TypedArraysSpec.swift +1 -1
  170. package/ios/Tests/ViewDefinitionSpec.swift +4 -2
  171. package/package.json +2 -2
  172. package/src/NativeViewManagerAdapter.native.tsx +33 -29
  173. package/src/requireNativeModule.ts +2 -2
  174. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +0 -132
  175. package/ios/EXViewManager.h +0 -21
  176. package/ios/EXViewManager.m +0 -128
  177. package/ios/ModuleRegistryAdapter/EXViewManagerAdapterClassesRegistry.h +0 -17
  178. package/ios/ModuleRegistryAdapter/EXViewManagerAdapterClassesRegistry.m +0 -67
  179. package/ios/ViewManagerAdapter/EXViewManagerAdapter.h +0 -17
  180. package/ios/ViewManagerAdapter/EXViewManagerAdapter.m +0 -45
@@ -2,6 +2,7 @@ package expo.modules.kotlin.jni
2
2
 
3
3
  import com.facebook.jni.HybridData
4
4
  import expo.modules.core.interfaces.DoNotStrip
5
+ import kotlin.reflect.typeOf
5
6
 
6
7
  /**
7
8
  * A Kotlin representation of jsi::Value.
@@ -9,7 +10,12 @@ import expo.modules.core.interfaces.DoNotStrip
9
10
  */
10
11
  @Suppress("KotlinJniMissingFunction")
11
12
  @DoNotStrip
12
- class JavaScriptValue @DoNotStrip private constructor(@DoNotStrip private val mHybridData: HybridData) {
13
+ class JavaScriptValue @DoNotStrip private constructor(@DoNotStrip private val mHybridData: HybridData) : Destructible {
14
+ init {
15
+ JNIDeallocator.addReference(this)
16
+ }
17
+
18
+ fun isValid() = mHybridData.isValid
13
19
  external fun kind(): String
14
20
 
15
21
  external fun isNull(): Boolean
@@ -30,12 +36,31 @@ class JavaScriptValue @DoNotStrip private constructor(@DoNotStrip private val mH
30
36
  external fun getArray(): Array<JavaScriptValue>
31
37
  external fun getTypedArray(): JavaScriptTypedArray
32
38
 
39
+ private external fun <T : Any?> jniGetFunction(): JavaScriptFunction<T>
40
+ @PublishedApi
41
+ internal fun <T : Any?> internalJniGetFunction(): JavaScriptFunction<T> = jniGetFunction()
42
+ inline fun <reified ReturnType : Any?> getFunction(): JavaScriptFunction<ReturnType> {
43
+ return internalJniGetFunction<ReturnType>().apply {
44
+ returnType = typeOf<ReturnType>()
45
+ }
46
+ }
47
+ @JvmName("getVoidFunction")
48
+ fun getFunction(): JavaScriptFunction<Unit> {
49
+ return internalJniGetFunction<Unit>().apply {
50
+ returnType = typeOf<Unit>()
51
+ }
52
+ }
53
+
33
54
  fun getInt() = getDouble().toInt()
34
55
  fun getLong() = getDouble().toLong()
35
56
  fun getFloat() = getDouble().toFloat()
36
57
 
37
58
  @Throws(Throwable::class)
38
59
  protected fun finalize() {
60
+ deallocate()
61
+ }
62
+
63
+ override fun deallocate() {
39
64
  mHybridData.resetNative()
40
65
  }
41
66
  }
@@ -1,11 +1,9 @@
1
1
  package expo.modules.kotlin.modules
2
2
 
3
3
  import android.os.Bundle
4
- import expo.modules.core.errors.ModuleDestroyedException
5
4
  import expo.modules.kotlin.AppContext
6
5
  import expo.modules.kotlin.providers.AppContextProvider
7
6
  import kotlinx.coroutines.CoroutineScope
8
- import kotlinx.coroutines.cancel
9
7
 
10
8
  abstract class Module : AppContextProvider {
11
9
 
@@ -25,9 +23,6 @@ abstract class Module : AppContextProvider {
25
23
  @PublishedApi
26
24
  internal lateinit var coroutineScopeDelegate: Lazy<CoroutineScope>
27
25
 
28
- @Deprecated(message = "Use a scope from the AppContext", replaceWith = ReplaceWith("appContext.modulesQueue"))
29
- val coroutineScope get() = coroutineScopeDelegate.value
30
-
31
26
  fun sendEvent(name: String, body: Bundle? = Bundle.EMPTY) {
32
27
  moduleEventEmitter?.emit(name, body)
33
28
  }
@@ -37,12 +32,6 @@ abstract class Module : AppContextProvider {
37
32
  }
38
33
 
39
34
  abstract fun definition(): ModuleDefinitionData
40
-
41
- internal fun cleanUp() {
42
- if (coroutineScopeDelegate.isInitialized()) {
43
- coroutineScope.cancel(ModuleDestroyedException())
44
- }
45
- }
46
35
  }
47
36
 
48
37
  @Suppress("FunctionName")
@@ -6,6 +6,8 @@ import android.app.Activity
6
6
  import android.content.Intent
7
7
  import android.view.View
8
8
  import expo.modules.kotlin.activityresult.AppContextActivityResultCaller
9
+ import expo.modules.kotlin.classcomponent.ClassComponentBuilder
10
+ import expo.modules.kotlin.classcomponent.ClassDefinitionData
9
11
  import expo.modules.kotlin.events.BasicEventListener
10
12
  import expo.modules.kotlin.events.EventListener
11
13
  import expo.modules.kotlin.events.EventListenerWithPayload
@@ -13,10 +15,11 @@ import expo.modules.kotlin.events.EventListenerWithSenderAndPayload
13
15
  import expo.modules.kotlin.events.EventName
14
16
  import expo.modules.kotlin.events.OnActivityResultPayload
15
17
  import expo.modules.kotlin.objects.ObjectDefinitionBuilder
18
+ import expo.modules.kotlin.sharedobjects.SharedObject
16
19
  import expo.modules.kotlin.views.ViewDefinitionBuilder
17
20
  import expo.modules.kotlin.views.ViewManagerDefinition
18
- import expo.modules.kotlin.views.ViewManagerDefinitionBuilder
19
21
  import kotlin.reflect.KClass
22
+ import kotlin.reflect.typeOf
20
23
 
21
24
  @DefinitionMarker
22
25
  class ModuleDefinitionBuilder(@PublishedApi internal val module: Module? = null) : ObjectDefinitionBuilder() {
@@ -31,6 +34,9 @@ class ModuleDefinitionBuilder(@PublishedApi internal val module: Module? = null)
31
34
  @PublishedApi
32
35
  internal var registerContracts: (suspend AppContextActivityResultCaller.() -> Unit)? = null
33
36
 
37
+ @PublishedApi
38
+ internal var classData = mutableListOf<ClassDefinitionData>()
39
+
34
40
  fun buildModule(): ModuleDefinitionData {
35
41
  val moduleName = name ?: module?.javaClass?.simpleName
36
42
 
@@ -39,7 +45,8 @@ class ModuleDefinitionBuilder(@PublishedApi internal val module: Module? = null)
39
45
  buildObject(),
40
46
  viewManagerDefinition,
41
47
  eventListeners,
42
- registerContracts
48
+ registerContracts,
49
+ classData
43
50
  )
44
51
  }
45
52
 
@@ -53,22 +60,10 @@ class ModuleDefinitionBuilder(@PublishedApi internal val module: Module? = null)
53
60
  /**
54
61
  * Creates the view manager definition that scopes other view-related definitions.
55
62
  */
56
- @Deprecated(message = "Use a `View` component instead.")
57
- inline fun ViewManager(body: ViewManagerDefinitionBuilder.() -> Unit) {
63
+ inline fun <reified T : View> View(viewClass: KClass<T>, body: ViewDefinitionBuilder<T>.() -> Unit) {
58
64
  require(viewManagerDefinition == null) { "The module definition may have exported only one view manager." }
59
65
 
60
- val viewManagerDefinitionBuilder = ViewManagerDefinitionBuilder()
61
- body.invoke(viewManagerDefinitionBuilder)
62
- viewManagerDefinition = viewManagerDefinitionBuilder.build()
63
- }
64
-
65
- /**
66
- * Creates the view manager definition that scopes other view-related definitions.
67
- */
68
- inline fun <T : View> View(viewType: KClass<T>, body: ViewDefinitionBuilder<T>.() -> Unit) {
69
- require(viewManagerDefinition == null) { "The module definition may have exported only one view manager." }
70
-
71
- val viewDefinitionBuilder = ViewDefinitionBuilder(viewType)
66
+ val viewDefinitionBuilder = ViewDefinitionBuilder(viewClass, typeOf<T>())
72
67
  body.invoke(viewDefinitionBuilder)
73
68
  viewManagerDefinition = viewDefinitionBuilder.build()
74
69
  }
@@ -129,4 +124,19 @@ class ModuleDefinitionBuilder(@PublishedApi internal val module: Module? = null)
129
124
  eventListeners[EventName.ON_ACTIVITY_RESULT] =
130
125
  EventListenerWithSenderAndPayload<Activity, OnActivityResultPayload>(EventName.ON_ACTIVITY_RESULT) { sender, payload -> body(sender, payload) }
131
126
  }
127
+
128
+ inline fun Class(name: String, body: ClassComponentBuilder<Unit>.() -> Unit = {}) {
129
+ val clazzBuilder = ClassComponentBuilder(name, Unit::class, typeOf<Unit>())
130
+ body.invoke(clazzBuilder)
131
+ classData.add(clazzBuilder.buildClass())
132
+ }
133
+
134
+ inline fun <reified SharedObjectType : SharedObject> Class(
135
+ sharedObjectClass: KClass<SharedObjectType>,
136
+ body: ClassComponentBuilder<SharedObjectType>.() -> Unit = {}
137
+ ) {
138
+ val clazzBuilder = ClassComponentBuilder(sharedObjectClass.java.simpleName, sharedObjectClass, typeOf<SharedObjectType>())
139
+ body.invoke(clazzBuilder)
140
+ classData.add(clazzBuilder.buildClass())
141
+ }
132
142
  }
@@ -1,6 +1,7 @@
1
1
  package expo.modules.kotlin.modules
2
2
 
3
3
  import expo.modules.kotlin.activityresult.AppContextActivityResultCaller
4
+ import expo.modules.kotlin.classcomponent.ClassDefinitionData
4
5
  import expo.modules.kotlin.events.EventListener
5
6
  import expo.modules.kotlin.events.EventName
6
7
  import expo.modules.kotlin.objects.ObjectDefinitionData
@@ -11,7 +12,8 @@ class ModuleDefinitionData(
11
12
  val objectDefinition: ObjectDefinitionData,
12
13
  val viewManagerDefinition: ViewManagerDefinition? = null,
13
14
  val eventListeners: Map<EventName, EventListener> = emptyMap(),
14
- val registerContracts: (suspend AppContextActivityResultCaller.() -> Unit)? = null
15
+ val registerContracts: (suspend AppContextActivityResultCaller.() -> Unit)? = null,
16
+ val classData: List<ClassDefinitionData> = emptyList()
15
17
  ) {
16
18
 
17
19
  val constantsProvider = objectDefinition.constantsProvider
@@ -0,0 +1,12 @@
1
+ package expo.modules.kotlin.sharedobjects
2
+
3
+ import expo.modules.core.interfaces.DoNotStrip
4
+
5
+ @DoNotStrip
6
+ open class SharedObject {
7
+ /**
8
+ * An identifier of the native shared object that maps to the JavaScript object.
9
+ * When the object is not linked with any JavaScript object, its value is 0.
10
+ */
11
+ internal var sharedObjectId: SharedObjectId = SharedObjectId(0)
12
+ }
@@ -0,0 +1,62 @@
1
+ package expo.modules.kotlin.sharedobjects
2
+
3
+ import expo.modules.kotlin.jni.JavaScriptObject
4
+
5
+ @JvmInline
6
+ value class SharedObjectId(val value: Int)
7
+
8
+ // TODO(@lukmccall): use weak ref to hold js object
9
+ typealias SharedObjectPair = Pair<SharedObject, JavaScriptObject>
10
+
11
+ const val sharedObjectIdPropertyName = "__expo_shared_object_id__"
12
+
13
+ class SharedObjectRegistry {
14
+ private var currentId: SharedObjectId = SharedObjectId(1)
15
+
16
+ internal var pairs = mutableMapOf<SharedObjectId, SharedObjectPair>()
17
+
18
+ private fun pullNextId(): SharedObjectId {
19
+ val current = currentId
20
+ currentId = SharedObjectId(current.value + 1)
21
+ return current
22
+ }
23
+
24
+ internal fun add(native: SharedObject, js: JavaScriptObject): SharedObjectId {
25
+ val id = pullNextId()
26
+ native.sharedObjectId = id
27
+ js.defineProperty(sharedObjectIdPropertyName, id.value)
28
+
29
+ js.defineDeallocator {
30
+ delete(id)
31
+ }
32
+
33
+ pairs[id] = native to js
34
+ return id
35
+ }
36
+
37
+ internal fun delete(id: SharedObjectId) {
38
+ pairs.remove(id)?.let { (native, js) ->
39
+ native.sharedObjectId = SharedObjectId(0)
40
+ if (js.isValid()) {
41
+ js.defineProperty(sharedObjectIdPropertyName, 0)
42
+ }
43
+ }
44
+ }
45
+
46
+ internal fun toNativeObject(id: SharedObjectId): SharedObject? {
47
+ return pairs[id]?.first
48
+ }
49
+
50
+ internal fun toNativeObject(js: JavaScriptObject): SharedObject? {
51
+ if (!js.hasProperty(sharedObjectIdPropertyName)) {
52
+ return null
53
+ }
54
+
55
+ val id = SharedObjectId(js.getProperty(sharedObjectIdPropertyName).getInt())
56
+ return pairs[id]?.first
57
+ }
58
+
59
+ internal fun toJavaScriptObjet(native: SharedObject): JavaScriptObject? {
60
+ return pairs[native.sharedObjectId]?.second
61
+ }
62
+ }
@@ -0,0 +1,27 @@
1
+ package expo.modules.kotlin.sharedobjects
2
+
3
+ import expo.modules.kotlin.AppContext
4
+ import expo.modules.kotlin.exception.InvalidSharedObjectException
5
+ import expo.modules.kotlin.jni.CppType
6
+ import expo.modules.kotlin.jni.ExpectedType
7
+ import expo.modules.kotlin.toStrongReference
8
+ import expo.modules.kotlin.types.NullAwareTypeConverter
9
+ import kotlin.reflect.KType
10
+
11
+ class SharedObjectTypeConverter<T : SharedObject>(
12
+ val type: KType
13
+ ) : NullAwareTypeConverter<T>(type.isMarkedNullable) {
14
+ @Suppress("UNCHECKED_CAST")
15
+ override fun convertNonOptional(value: Any, context: AppContext?): T {
16
+ val id = SharedObjectId(value as Int)
17
+ val appContext = context.toStrongReference()
18
+ val result = appContext.sharedObjectRegistry.toNativeObject(id)
19
+ ?: throw InvalidSharedObjectException(type)
20
+
21
+ return result as T
22
+ }
23
+
24
+ override fun getCppRequiredTypes() = ExpectedType(CppType.SHARED_OBJECT_ID)
25
+
26
+ override fun isTrivial(): Boolean = false
27
+ }
@@ -1,5 +1,6 @@
1
1
  package expo.modules.kotlin.types
2
2
 
3
+ import expo.modules.kotlin.AppContext
3
4
  import expo.modules.kotlin.jni.ExpectedType
4
5
  import kotlin.reflect.KType
5
6
 
@@ -10,7 +11,7 @@ class AnyType(val kType: KType) {
10
11
  TypeConverterProviderImpl.obtainTypeConverter(kType)
11
12
  }
12
13
 
13
- fun convert(value: Any?): Any? = converter.convert(value)
14
+ fun convert(value: Any?, appContext: AppContext? = null): Any? = converter.convert(value, appContext)
14
15
 
15
16
  fun getCppRequiredTypes(): ExpectedType = converter.getCppRequiredTypes()
16
17
  }
@@ -1,5 +1,6 @@
1
1
  package expo.modules.kotlin.types
2
2
 
3
+ import expo.modules.kotlin.AppContext
3
4
  import expo.modules.kotlin.apifeatures.EitherType
4
5
  import expo.modules.kotlin.jni.ExpectedType
5
6
  import expo.modules.kotlin.jni.SingleType
@@ -9,7 +10,7 @@ import kotlin.reflect.KType
9
10
  class EitherTypeConverter<FirstType : Any, SecondType : Any>(
10
11
  converterProvider: TypeConverterProvider,
11
12
  eitherType: KType,
12
- ) : TypeConverter<Either<FirstType, SecondType>>(eitherType.isMarkedNullable) {
13
+ ) : NullAwareTypeConverter<Either<FirstType, SecondType>>(eitherType.isMarkedNullable) {
13
14
  private val firstJavaType = requireNotNull(eitherType.arguments.getOrNull(0)?.type)
14
15
  private val secondJavaType = requireNotNull(eitherType.arguments.getOrNull(1)?.type)
15
16
  private val firstTypeConverter = converterProvider.obtainTypeConverter(
@@ -21,7 +22,7 @@ class EitherTypeConverter<FirstType : Any, SecondType : Any>(
21
22
  private val firstType = firstTypeConverter.getCppRequiredTypes()
22
23
  private val secondType = secondTypeConverter.getCppRequiredTypes()
23
24
 
24
- override fun convertNonOptional(value: Any): Either<FirstType, SecondType> {
25
+ override fun convertNonOptional(value: Any, context: AppContext?): Either<FirstType, SecondType> {
25
26
  val convertValueIfNeeded = Convert@{ types: Array<out SingleType>, converter: TypeConverter<*> ->
26
27
  for (singleType in types) {
27
28
  if (singleType.expectedCppType.clazz.isInstance(value)) {
@@ -54,7 +55,7 @@ class EitherTypeConverter<FirstType : Any, SecondType : Any>(
54
55
  class EitherOfThreeTypeConverter<FirstType : Any, SecondType : Any, ThirdType : Any>(
55
56
  converterProvider: TypeConverterProvider,
56
57
  eitherType: KType,
57
- ) : TypeConverter<EitherOfThree<FirstType, SecondType, ThirdType>>(eitherType.isMarkedNullable) {
58
+ ) : NullAwareTypeConverter<EitherOfThree<FirstType, SecondType, ThirdType>>(eitherType.isMarkedNullable) {
58
59
  private val firstJavaType = requireNotNull(eitherType.arguments.getOrNull(0)?.type)
59
60
  private val secondJavaType = requireNotNull(eitherType.arguments.getOrNull(1)?.type)
60
61
  private val thirdJavaType = requireNotNull(eitherType.arguments.getOrNull(2)?.type)
@@ -71,7 +72,7 @@ class EitherOfThreeTypeConverter<FirstType : Any, SecondType : Any, ThirdType :
71
72
  private val secondType = secondTypeConverter.getCppRequiredTypes()
72
73
  private val thirdType = thirdTypeConverter.getCppRequiredTypes()
73
74
 
74
- override fun convertNonOptional(value: Any): EitherOfThree<FirstType, SecondType, ThirdType> {
75
+ override fun convertNonOptional(value: Any, context: AppContext?): EitherOfThree<FirstType, SecondType, ThirdType> {
75
76
  val convertValueIfNeeded = Convert@{ types: Array<out SingleType>, converter: TypeConverter<*> ->
76
77
  for (singleType in types) {
77
78
  if (singleType.expectedCppType.clazz.isInstance(value)) {
@@ -105,7 +106,7 @@ class EitherOfThreeTypeConverter<FirstType : Any, SecondType : Any, ThirdType :
105
106
  class EitherOfFourTypeConverter<FirstType : Any, SecondType : Any, ThirdType : Any, FourthType : Any>(
106
107
  converterProvider: TypeConverterProvider,
107
108
  eitherType: KType,
108
- ) : TypeConverter<EitherOfFour<FirstType, SecondType, ThirdType, FourthType>>(eitherType.isMarkedNullable) {
109
+ ) : NullAwareTypeConverter<EitherOfFour<FirstType, SecondType, ThirdType, FourthType>>(eitherType.isMarkedNullable) {
109
110
  private val firstJavaType = requireNotNull(eitherType.arguments.getOrNull(0)?.type)
110
111
  private val secondJavaType = requireNotNull(eitherType.arguments.getOrNull(1)?.type)
111
112
  private val thirdJavaType = requireNotNull(eitherType.arguments.getOrNull(2)?.type)
@@ -127,7 +128,7 @@ class EitherOfFourTypeConverter<FirstType : Any, SecondType : Any, ThirdType : A
127
128
  private val thirdType = thirdTypeConverter.getCppRequiredTypes()
128
129
  private val fourthType = fourthTypeConverter.getCppRequiredTypes()
129
130
 
130
- override fun convertNonOptional(value: Any): EitherOfFour<FirstType, SecondType, ThirdType, FourthType> {
131
+ override fun convertNonOptional(value: Any, context: AppContext?): EitherOfFour<FirstType, SecondType, ThirdType, FourthType> {
131
132
  val convertValueIfNeeded = Convert@{ types: Array<out SingleType>, converter: TypeConverter<*> ->
132
133
  for (singleType in types) {
133
134
  if (singleType.expectedCppType.clazz.isInstance(value)) {
@@ -0,0 +1,22 @@
1
+ package expo.modules.kotlin.types
2
+
3
+ import expo.modules.kotlin.AppContext
4
+ import expo.modules.kotlin.jni.CppType
5
+ import expo.modules.kotlin.jni.ExpectedType
6
+ import expo.modules.kotlin.jni.JavaScriptFunction
7
+ import kotlin.reflect.KType
8
+
9
+ class JavaScriptFunctionTypeConverter<T : Any>(
10
+ val type: KType
11
+ ) : NullAwareTypeConverter<JavaScriptFunction<T>>(type.isMarkedNullable) {
12
+ override fun convertNonOptional(value: Any, context: AppContext?): JavaScriptFunction<T> {
13
+ @Suppress("UNCHECKED_CAST")
14
+ val jsFunction = value as JavaScriptFunction<T>
15
+ jsFunction.returnType = requireNotNull(type.arguments.first().type)
16
+ return jsFunction
17
+ }
18
+
19
+ override fun getCppRequiredTypes(): ExpectedType = ExpectedType(CppType.JS_FUNCTION)
20
+
21
+ override fun isTrivial(): Boolean = false
22
+ }
@@ -1,6 +1,7 @@
1
1
  package expo.modules.kotlin.types
2
2
 
3
3
  import com.facebook.react.bridge.Dynamic
4
+ import expo.modules.kotlin.AppContext
4
5
  import expo.modules.kotlin.exception.NullArgumentException
5
6
  import expo.modules.kotlin.exception.UnsupportedClass
6
7
  import expo.modules.kotlin.jni.ExpectedType
@@ -9,30 +10,11 @@ import expo.modules.kotlin.jni.ExpectedType
9
10
  * Basic type converter. It has to handle two different inputs - [Dynamic] and [Any].
10
11
  * The first one is used in the bridge implementation. The second one is used in the JSI.
11
12
  */
12
- abstract class TypeConverter<Type : Any>(
13
- /**
14
- * Whether `null` can be assigned to the desired type.
15
- */
16
- private val isOptional: Boolean
17
- ) {
13
+ abstract class TypeConverter<Type : Any> {
18
14
  /**
19
15
  * Tries to convert from [Any]? (can be also [Dynamic]) to the desired type.
20
16
  */
21
- open fun convert(value: Any?): Type? {
22
- if (value == null || value is Dynamic && value.isNull) {
23
- if (isOptional) {
24
- return null
25
- }
26
- throw NullArgumentException()
27
- }
28
- return convertNonOptional(value)
29
- }
30
-
31
- /**
32
- * Tries to convert from [Any] to the desired type.
33
- * We know in that place that we're not dealing with `null`.
34
- */
35
- abstract fun convertNonOptional(value: Any): Type
17
+ abstract fun convert(value: Any?, context: AppContext? = null): Type?
36
18
 
37
19
  /**
38
20
  * Returns a list of [ExpectedType] types that can be converted to the desired type.
@@ -40,7 +22,7 @@ abstract class TypeConverter<Type : Any>(
40
22
  * For instance js object can be pass as [Map] or [expo.modules.kotlin.jni.JavaScriptObject].
41
23
  * This value tells us which one we should choose.
42
24
  */
43
- abstract fun getCppRequiredTypes(): ExpectedType
25
+ open fun getCppRequiredTypes(): ExpectedType = ExpectedType.forAny()
44
26
 
45
27
  /**
46
28
  * Checks if the current converter is a trivial one.
@@ -50,13 +32,36 @@ abstract class TypeConverter<Type : Any>(
50
32
  open fun isTrivial(): Boolean = true
51
33
  }
52
34
 
35
+ abstract class NullAwareTypeConverter<Type : Any>(
36
+ /**
37
+ * Whether `null` can be assigned to the desired type.
38
+ */
39
+ private val isOptional: Boolean
40
+ ) : TypeConverter<Type>() {
41
+ override fun convert(value: Any?, context: AppContext?): Type? {
42
+ if (value == null || value is Dynamic && value.isNull) {
43
+ if (isOptional) {
44
+ return null
45
+ }
46
+ throw NullArgumentException()
47
+ }
48
+ return convertNonOptional(value, context)
49
+ }
50
+
51
+ /**
52
+ * Tries to convert from [Any] to the desired type.
53
+ * We know in that place that we're not dealing with `null`.
54
+ */
55
+ abstract fun convertNonOptional(value: Any, context: AppContext?): Type
56
+ }
57
+
53
58
  /**
54
59
  * A helper class to make a clear separation between [Any] and [Dynamic].
55
60
  * Right it is used as a default base class for all converters, but this will change when we
56
61
  * stop using the bridge to pass data between JS and Kotlin.
57
62
  */
58
- abstract class DynamicAwareTypeConverters<T : Any>(isOptional: Boolean) : TypeConverter<T>(isOptional) {
59
- override fun convertNonOptional(value: Any): T =
63
+ abstract class DynamicAwareTypeConverters<T : Any>(isOptional: Boolean) : NullAwareTypeConverter<T>(isOptional) {
64
+ override fun convertNonOptional(value: Any, context: AppContext?): T =
60
65
  if (value is Dynamic) {
61
66
  convertFromDynamic(value)
62
67
  } else {
@@ -75,6 +80,7 @@ inline fun <reified T : Any> createTrivialTypeConverter(
75
80
  return object : DynamicAwareTypeConverters<T>(isOptional) {
76
81
  override fun convertFromDynamic(value: Dynamic): T = dynamicFallback(value)
77
82
  override fun getCppRequiredTypes(): ExpectedType = cppRequireType
83
+
78
84
  @Suppress("UNCHECKED_CAST")
79
85
  override fun convertFromAny(value: Any): T = value as T
80
86
  }
@@ -4,17 +4,22 @@ package expo.modules.kotlin.types
4
4
 
5
5
  import android.graphics.Color
6
6
  import android.net.Uri
7
+ import android.view.View
7
8
  import com.facebook.react.bridge.Dynamic
8
9
  import com.facebook.react.bridge.ReadableArray
9
10
  import com.facebook.react.bridge.ReadableMap
11
+ import expo.modules.annotation.Config
10
12
  import expo.modules.kotlin.apifeatures.EitherType
11
13
  import expo.modules.kotlin.exception.MissingTypeConverter
12
14
  import expo.modules.kotlin.jni.CppType
13
15
  import expo.modules.kotlin.jni.ExpectedType
16
+ import expo.modules.kotlin.jni.JavaScriptFunction
14
17
  import expo.modules.kotlin.jni.JavaScriptObject
15
18
  import expo.modules.kotlin.jni.JavaScriptValue
16
19
  import expo.modules.kotlin.records.Record
17
20
  import expo.modules.kotlin.records.RecordTypeConverter
21
+ import expo.modules.kotlin.sharedobjects.SharedObject
22
+ import expo.modules.kotlin.sharedobjects.SharedObjectTypeConverter
18
23
  import expo.modules.kotlin.typedarray.BigInt64Array
19
24
  import expo.modules.kotlin.typedarray.BigUint64Array
20
25
  import expo.modules.kotlin.typedarray.Float32Array
@@ -32,6 +37,7 @@ import expo.modules.kotlin.types.io.PathTypeConverter
32
37
  import expo.modules.kotlin.types.net.JavaURITypeConverter
33
38
  import expo.modules.kotlin.types.net.URLTypConverter
34
39
  import expo.modules.kotlin.types.net.UriTypeConverter
40
+ import expo.modules.kotlin.views.ViewTypeConverter
35
41
  import java.io.File
36
42
  import java.net.URI
37
43
  import java.net.URL
@@ -69,6 +75,7 @@ fun convert(value: Dynamic, type: KType): Any? {
69
75
  object TypeConverterProviderImpl : TypeConverterProvider {
70
76
  private val cachedConverters = createCashedConverters(false) + createCashedConverters(true)
71
77
  private val cachedRecordConverters = mutableMapOf<KClass<*>, TypeConverter<*>>()
78
+ private val cachedCustomConverters = mutableMapOf<KType, TypeConverter<*>>()
72
79
 
73
80
  override fun obtainTypeConverter(type: KType): TypeConverter<*> {
74
81
  cachedConverters[type]?.let {
@@ -113,7 +120,21 @@ object TypeConverterProviderImpl : TypeConverterProvider {
113
120
  return converter
114
121
  }
115
122
 
116
- return handelEither(type, kClass) ?: throw MissingTypeConverter(type)
123
+ if (kClass.isSubclassOf(View::class)) {
124
+ return ViewTypeConverter<View>(type)
125
+ }
126
+
127
+ if (kClass.isSubclassOf(SharedObject::class)) {
128
+ return SharedObjectTypeConverter<SharedObject>(type)
129
+ }
130
+
131
+ if (kClass.isSubclassOf(JavaScriptFunction::class)) {
132
+ return JavaScriptFunctionTypeConverter<Any>(type)
133
+ }
134
+
135
+ return handelEither(type, kClass)
136
+ ?: handelCustomConverter(type, kClass)
137
+ ?: throw MissingTypeConverter(type)
117
138
  }
118
139
 
119
140
  @OptIn(EitherType::class)
@@ -131,6 +152,29 @@ object TypeConverterProviderImpl : TypeConverterProvider {
131
152
  return null
132
153
  }
133
154
 
155
+ private fun handelCustomConverter(type: KType, kClass: KClass<*>): TypeConverter<*>? {
156
+ val cachedConverter = cachedCustomConverters[type]
157
+ if (cachedConverter != null) {
158
+ return cachedConverter
159
+ }
160
+
161
+ val typeName = kClass.java.canonicalName ?: return null
162
+
163
+ val converterProviderName = "${Config.packageNamePrefix}$typeName${Config.classNameSuffix}"
164
+ return try {
165
+ val converterClazz = Class.forName(converterProviderName)
166
+ val converterProvider = converterClazz.newInstance()
167
+ val method = converterProvider.javaClass.getMethod(Config.converterProviderFunctionName, KType::class.java)
168
+
169
+ (method.invoke(converterProvider, type) as TypeConverter<*>)
170
+ .also {
171
+ cachedCustomConverters[type] = it
172
+ }
173
+ } catch (e: Throwable) {
174
+ null
175
+ }
176
+ }
177
+
134
178
  private fun createCashedConverters(isOptional: Boolean): Map<KType, TypeConverter<*>> {
135
179
  val intTypeConverter = createTrivialTypeConverter(
136
180
  isOptional, ExpectedType(CppType.INT)
@@ -1,5 +1,6 @@
1
1
  package expo.modules.kotlin.types
2
2
 
3
+ import expo.modules.kotlin.AppContext
3
4
  import expo.modules.kotlin.jni.CppType
4
5
  import expo.modules.kotlin.jni.ExpectedType
5
6
  import expo.modules.kotlin.jni.JavaScriptTypedArray
@@ -16,8 +17,8 @@ import expo.modules.kotlin.typedarray.Uint32Array
16
17
  import expo.modules.kotlin.typedarray.Uint8Array
17
18
  import expo.modules.kotlin.typedarray.Uint8ClampedArray
18
19
 
19
- abstract class BaseTypeArrayConverter<T : TypedArray>(isOptional: Boolean) : TypeConverter<T>(isOptional) {
20
- override fun convertNonOptional(value: Any): T = wrapJavaScriptTypedArray(value as JavaScriptTypedArray)
20
+ abstract class BaseTypeArrayConverter<T : TypedArray>(isOptional: Boolean) : NullAwareTypeConverter<T>(isOptional) {
21
+ override fun convertNonOptional(value: Any, context: AppContext?): T = wrapJavaScriptTypedArray(value as JavaScriptTypedArray)
21
22
  override fun getCppRequiredTypes(): ExpectedType = ExpectedType(CppType.TYPED_ARRAY)
22
23
  override fun isTrivial() = false
23
24
 
@@ -2,9 +2,11 @@ package expo.modules.kotlin.views
2
2
 
3
3
  import android.view.View
4
4
  import com.facebook.react.bridge.Dynamic
5
+ import expo.modules.kotlin.types.AnyType
5
6
 
6
7
  abstract class AnyViewProp(
7
- val name: String
8
+ val name: String,
9
+ internal val type: AnyType
8
10
  ) {
9
11
  abstract fun set(prop: Dynamic, onView: View)
10
12
 
@@ -8,16 +8,16 @@ import expo.modules.kotlin.types.AnyType
8
8
 
9
9
  class ConcreteViewProp<ViewType : View, PropType>(
10
10
  name: String,
11
- private val propType: AnyType,
11
+ propType: AnyType,
12
12
  private val setter: (view: ViewType, prop: PropType) -> Unit,
13
- ) : AnyViewProp(name) {
13
+ ) : AnyViewProp(name, propType) {
14
14
 
15
15
  @Suppress("UNCHECKED_CAST")
16
16
  override fun set(prop: Dynamic, onView: View) {
17
17
  exceptionDecorator({
18
18
  PropSetException(name, onView::class, it)
19
19
  }) {
20
- setter(onView as ViewType, propType.convert(prop) as PropType)
20
+ setter(onView as ViewType, type.convert(prop) as PropType)
21
21
  }
22
22
  }
23
23