expo-modules-core 0.10.0 → 0.11.2

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 (63) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +3 -3
  3. package/android/CMakeLists.txt +14 -5
  4. package/android/build.gradle +78 -28
  5. package/android/src/main/cpp/CachedReferencesRegistry.cpp +67 -0
  6. package/android/src/main/cpp/CachedReferencesRegistry.h +80 -0
  7. package/android/src/main/cpp/JNIFunctionBody.cpp +28 -12
  8. package/android/src/main/cpp/JNIFunctionBody.h +2 -2
  9. package/android/src/main/cpp/JNIInjector.cpp +4 -0
  10. package/android/src/main/cpp/JavaScriptModuleObject.cpp +86 -5
  11. package/android/src/main/cpp/JavaScriptModuleObject.h +27 -5
  12. package/android/src/main/cpp/JavaScriptRuntime.cpp +10 -12
  13. package/android/src/main/cpp/MethodMetadata.cpp +181 -40
  14. package/android/src/main/cpp/MethodMetadata.h +43 -3
  15. package/android/src/main/java/expo/modules/kotlin/AppContext.kt +63 -10
  16. package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +6 -0
  17. package/android/src/main/java/expo/modules/kotlin/activityaware/AppCompatActivityAware.kt +49 -0
  18. package/android/src/main/java/expo/modules/kotlin/activityaware/AppCompatActivityAwareHelper.kt +43 -0
  19. package/android/src/main/java/expo/modules/kotlin/activityaware/OnActivityAvailableListener.kt +18 -0
  20. package/android/src/main/java/expo/modules/kotlin/activityresult/ActivityResultsManager.kt +99 -0
  21. package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultCaller.kt +25 -0
  22. package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultContract.kt +27 -0
  23. package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultFallbackCallback.kt +17 -0
  24. package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultLauncher.kt +30 -0
  25. package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultRegistry.kt +358 -0
  26. package/android/src/main/java/expo/modules/kotlin/activityresult/DataPersistor.kt +135 -0
  27. package/android/src/main/java/expo/modules/kotlin/functions/AnyFunction.kt +34 -1
  28. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunction.kt +7 -1
  29. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionBuilder.kt +0 -108
  30. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionComponent.kt +5 -2
  31. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromiseComponent.kt +5 -2
  32. package/android/src/main/java/expo/modules/kotlin/functions/SuspendFunctionComponent.kt +9 -2
  33. package/android/src/main/java/expo/modules/kotlin/functions/SyncFunctionComponent.kt +9 -1
  34. package/android/src/main/java/expo/modules/kotlin/jni/CppType.kt +1 -0
  35. package/android/src/main/java/expo/modules/kotlin/jni/JNIFunctionBody.kt +2 -2
  36. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptModuleObject.kt +4 -2
  37. package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +1 -1
  38. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +5 -454
  39. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +7 -15
  40. package/android/src/main/java/expo/modules/kotlin/objects/ObjectDefinitionBuilder.kt +271 -0
  41. package/android/src/main/java/expo/modules/kotlin/objects/ObjectDefinitionData.kt +21 -0
  42. package/android/src/main/java/expo/modules/kotlin/objects/PropertyComponent.kt +54 -0
  43. package/android/src/main/java/expo/modules/kotlin/objects/PropertyComponentBuilder.kt +32 -0
  44. package/android/src/main/java/expo/modules/kotlin/types/AnyTypeConverter.kt +36 -0
  45. package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +7 -0
  46. package/android/src/main/java/expo/modules/kotlin/views/ViewGroupDefinitionBuilder.kt +0 -41
  47. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +0 -33
  48. package/build/PermissionsInterface.d.ts +29 -0
  49. package/build/PermissionsInterface.d.ts.map +1 -1
  50. package/build/PermissionsInterface.js +9 -0
  51. package/build/PermissionsInterface.js.map +1 -1
  52. package/ios/ExpoModulesCore.podspec +2 -1
  53. package/ios/JSI/EXJSIInstaller.mm +2 -0
  54. package/ios/JSI/EXJSIUtils.h +1 -0
  55. package/ios/NativeModulesProxy/EXNativeModulesProxy.mm +4 -3
  56. package/ios/Swift/AppContext.swift +2 -4
  57. package/ios/Swift/Classes/ClassComponentElementsBuilder.swift +2 -2
  58. package/ios/Swift/Exceptions/ChainableException.swift +3 -3
  59. package/ios/Swift/ExpoBridgeModule.swift +16 -2
  60. package/ios/Swift/Logging/Logger.swift +3 -0
  61. package/ios/Swift/Promise.swift +5 -1
  62. package/package.json +2 -2
  63. package/src/PermissionsInterface.ts +29 -0
@@ -5,6 +5,7 @@ package expo.modules.kotlin
5
5
  import android.app.Activity
6
6
  import android.content.Context
7
7
  import android.content.Intent
8
+ import androidx.annotation.MainThread
8
9
  import androidx.appcompat.app.AppCompatActivity
9
10
  import com.facebook.react.bridge.ReactApplicationContext
10
11
  import com.facebook.react.turbomodule.core.CallInvokerHolderImpl
@@ -19,6 +20,11 @@ import expo.modules.interfaces.imageloader.ImageLoaderInterface
19
20
  import expo.modules.interfaces.permissions.Permissions
20
21
  import expo.modules.interfaces.sensors.SensorServiceInterface
21
22
  import expo.modules.interfaces.taskManager.TaskManagerInterface
23
+ import expo.modules.kotlin.activityresult.ActivityResultsManager
24
+ import expo.modules.kotlin.activityresult.AppContextActivityResultFallbackCallback
25
+ import expo.modules.kotlin.activityresult.AppContextActivityResultCaller
26
+ import expo.modules.kotlin.activityresult.AppContextActivityResultContract
27
+ import expo.modules.kotlin.activityresult.AppContextActivityResultLauncher
22
28
  import expo.modules.kotlin.defaultmodules.ErrorManagerModule
23
29
  import expo.modules.kotlin.events.EventEmitter
24
30
  import expo.modules.kotlin.events.EventName
@@ -34,45 +40,64 @@ import kotlinx.coroutines.DelicateCoroutinesApi
34
40
  import kotlinx.coroutines.SupervisorJob
35
41
  import kotlinx.coroutines.cancel
36
42
  import kotlinx.coroutines.newSingleThreadContext
43
+ import java.io.Serializable
37
44
  import java.lang.ref.WeakReference
38
45
 
39
46
  class AppContext(
40
47
  modulesProvider: ModulesProvider,
41
48
  val legacyModuleRegistry: expo.modules.core.ModuleRegistry,
42
49
  private val reactContextHolder: WeakReference<ReactApplicationContext>
43
- ) : CurrentActivityProvider {
50
+ ) : CurrentActivityProvider, AppContextActivityResultCaller {
44
51
  val registry = ModuleRegistry(WeakReference(this)).apply {
45
- register(ErrorManagerModule())
46
- register(modulesProvider)
47
52
  }
48
53
  private val reactLifecycleDelegate = ReactLifecycleDelegate(this)
54
+
49
55
  // We postpone creating the `JSIInteropModuleRegistry` to not load so files in unit tests.
50
56
  private lateinit var jsiInterop: JSIInteropModuleRegistry
57
+
58
+ /**
59
+ * A queue used to dispatch all async methods that are called via JSI.
60
+ */
51
61
  internal val modulesQueue = CoroutineScope(
62
+ // TODO(@lukmccall): maybe it will be better to use a thread pool
52
63
  newSingleThreadContext("ExpoModulesCoreQueue") +
53
64
  SupervisorJob() +
54
65
  CoroutineName("ExpoModulesCoreCoroutineQueue")
55
66
  )
56
67
 
68
+ private val activityResultsManager = ActivityResultsManager(this)
69
+
57
70
  init {
58
71
  requireNotNull(reactContextHolder.get()) {
59
72
  "The app context should be created with valid react context."
60
73
  }.apply {
61
74
  addLifecycleEventListener(reactLifecycleDelegate)
62
75
  addActivityEventListener(reactLifecycleDelegate)
76
+
77
+ // Registering modules has to happen at the very end of `AppContext` creation. Some modules need to access
78
+ // `AppContext` during their initialisation (or during `OnCreate` method), so we need to ensure all `AppContext`'s
79
+ // properties are initialized first. Not having that would trigger NPE.
80
+ registry.register(ErrorManagerModule())
81
+ registry.register(modulesProvider)
63
82
  }
64
83
  }
65
84
 
85
+ /**
86
+ * Initializes a JSI part of the module registry.
87
+ * It will be a NOOP if the remote debugging was activated.
88
+ */
66
89
  fun installJSIInterop() {
67
90
  jsiInterop = JSIInteropModuleRegistry(this)
68
91
  val reactContext = reactContextHolder.get() ?: return
69
- reactContext.javaScriptContextHolder?.get()?.let {
70
- jsiInterop.installJSI(
71
- it,
72
- reactContext.catalystInstance.jsCallInvokerHolder as CallInvokerHolderImpl,
73
- reactContext.catalystInstance.nativeCallInvokerHolder as CallInvokerHolderImpl
74
- )
75
- }
92
+ reactContext.javaScriptContextHolder?.get()
93
+ ?.takeIf { it != 0L }
94
+ ?.let {
95
+ jsiInterop.installJSI(
96
+ it,
97
+ reactContext.catalystInstance.jsCallInvokerHolder as CallInvokerHolderImpl,
98
+ reactContext.catalystInstance.nativeCallInvokerHolder as CallInvokerHolderImpl
99
+ )
100
+ }
76
101
  }
77
102
 
78
103
  /**
@@ -185,6 +210,11 @@ class AppContext(
185
210
  }
186
211
 
187
212
  fun onHostResume() {
213
+ activityResultsManager.onHostResume(
214
+ requireNotNull(currentActivity) {
215
+ "Current Activity is not available at this moment. This is an invalid state and this should never happen"
216
+ }
217
+ )
188
218
  registry.post(EventName.ACTIVITY_ENTERS_FOREGROUND)
189
219
  }
190
220
 
@@ -193,10 +223,16 @@ class AppContext(
193
223
  }
194
224
 
195
225
  fun onHostDestroy() {
226
+ activityResultsManager.onHostDestroy(
227
+ requireNotNull(currentActivity) {
228
+ "Current Activity is not available at this moment. This is an invalid state and this should never happen"
229
+ }
230
+ )
196
231
  registry.post(EventName.ACTIVITY_DESTROYS)
197
232
  }
198
233
 
199
234
  fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int, data: Intent?) {
235
+ activityResultsManager.onActivityResult(activity, requestCode, resultCode, data)
200
236
  registry.post(
201
237
  EventName.ON_ACTIVITY_RESULT,
202
238
  activity,
@@ -228,5 +264,22 @@ class AppContext(
228
264
  return currentActivity
229
265
  }
230
266
 
267
+ // endregion
268
+
269
+ // region AppContextActivityResultCaller
270
+
271
+ /**
272
+ * For the time being [fallbackCallback] is not working.
273
+ * There are some problems with saving and restoring the state of [activityResultsManager]
274
+ * connected with [Activity]'s lifecycle and [AppContext] lifespan. So far, we've failed with identifying
275
+ * what parts of the application outlives the Activity destruction (especially [AppContext] and other [Bridge]-related parts).
276
+ */
277
+ @MainThread
278
+ override suspend fun <I : Serializable, O> registerForActivityResult(
279
+ contract: AppContextActivityResultContract<I, O>,
280
+ fallbackCallback: AppContextActivityResultFallbackCallback<I, O>
281
+ ): AppContextActivityResultLauncher<I, O> =
282
+ activityResultsManager.registerForActivityResult(contract, fallbackCallback)
283
+
231
284
  // endregion
232
285
  }
@@ -33,6 +33,12 @@ class ModuleHolder(val module: Module) {
33
33
  .forEach { function ->
34
34
  function.attachToJSObject(module.appContext, this)
35
35
  }
36
+
37
+ definition
38
+ .properties
39
+ .forEach { (_, prop) ->
40
+ prop.attachToJSObject(this)
41
+ }
36
42
  }
37
43
  }
38
44
 
@@ -0,0 +1,49 @@
1
+ package expo.modules.kotlin.activityaware
2
+
3
+ import android.app.Activity
4
+ import androidx.appcompat.app.AppCompatActivity
5
+ import expo.modules.kotlin.AppContext
6
+ import kotlinx.coroutines.suspendCancellableCoroutine
7
+
8
+ /**
9
+ * Similar to [androidx.activity.contextaware.ContextAware]
10
+ *
11
+ * A [AppCompatActivityAware] class is associated with a [AppCompatActivity] sometime after
12
+ * the [Activity] is passed down to the [AppContext] in [AppContext.onHostResume].
13
+ * By adding a [OnActivityAvailableListener] you can receive a callback for that event.
14
+ */
15
+ interface AppCompatActivityAware {
16
+ /**
17
+ * Adds a listener waiting for Activity to become available.
18
+ * If Activity is available when listener is being added it will be immediately called.
19
+ */
20
+ fun addOnActivityAvailableListener(listener: OnActivityAvailableListener)
21
+
22
+ fun removeOnActivityAvailableListener(listener: OnActivityAvailableListener)
23
+ }
24
+
25
+ /**
26
+ * Similar to [androidx.activity.contextaware.ContextAware] from `androidx.activity:activity-kts`
27
+ *
28
+ * Run [onActivityAvailable] when the [AppCompatActivity] becomes available and resume with the result.
29
+ *
30
+ * If the [AppCompatActivity] is already available, [onActivityAvailable] will be synchronously
31
+ * called on the current coroutine context. Otherwise, [onActivityAvailable] will be called on the
32
+ * the UI thread immediately when the [Activity] becomes available.
33
+ *
34
+ * No matter how many times [Activity] will become available callback would be called only once.
35
+ */
36
+ suspend inline fun <R> AppCompatActivityAware.withActivityAvailable(
37
+ crossinline onActivityAvailable: (AppCompatActivity) -> R
38
+ ): R = suspendCancellableCoroutine { continuation ->
39
+ val listener = object : OnActivityAvailableListener {
40
+ override fun onActivityAvailable(activity: AppCompatActivity) {
41
+ removeOnActivityAvailableListener(this)
42
+ continuation.resumeWith(runCatching { onActivityAvailable(activity) })
43
+ }
44
+ }
45
+ addOnActivityAvailableListener(listener)
46
+ continuation.invokeOnCancellation {
47
+ removeOnActivityAvailableListener(listener)
48
+ }
49
+ }
@@ -0,0 +1,43 @@
1
+ package expo.modules.kotlin.activityaware
2
+
3
+ import androidx.appcompat.app.AppCompatActivity
4
+ import java.lang.ref.WeakReference
5
+ import java.util.concurrent.CopyOnWriteArrayList
6
+
7
+ /**
8
+ * Similar to [androidx.activity.contextaware.ContextAwareHelper]
9
+ *
10
+ * Helper class for implementing [AppCompatActivityAware].
11
+ */
12
+ class AppCompatActivityAwareHelper : AppCompatActivityAware {
13
+ val listeners = CopyOnWriteArrayList<OnActivityAvailableListener>()
14
+
15
+ var activityReference = WeakReference<AppCompatActivity>(null)
16
+
17
+ fun dispatchOnActivityAvailable(activity: AppCompatActivity) {
18
+ this.activityReference = WeakReference(activity)
19
+
20
+ activity.runOnUiThread {
21
+ for (listener in listeners) {
22
+ listener.onActivityAvailable(activity)
23
+ }
24
+ }
25
+ }
26
+
27
+ // region AppCompatActivityAware
28
+
29
+ override fun addOnActivityAvailableListener(listener: OnActivityAvailableListener) {
30
+ listeners.add(listener)
31
+ activityReference.get()?.let { activity ->
32
+ activity.runOnUiThread {
33
+ listener.onActivityAvailable(activity)
34
+ }
35
+ }
36
+ }
37
+
38
+ override fun removeOnActivityAvailableListener(listener: OnActivityAvailableListener) {
39
+ listeners.remove(listener)
40
+ }
41
+
42
+ // endregion
43
+ }
@@ -0,0 +1,18 @@
1
+ package expo.modules.kotlin.activityaware
2
+
3
+ import androidx.annotation.UiThread
4
+ import androidx.appcompat.app.AppCompatActivity
5
+
6
+ /**
7
+ * Similar to [androidx.activity.contextaware.OnContextAvailableListener]
8
+ *
9
+ * Listener for receiving a callback at the first moment a [AppCompatActivity] is made
10
+ * available to the [AppCompatActivityAware] class.
11
+ */
12
+ fun interface OnActivityAvailableListener {
13
+ /**
14
+ * This callback will be called on UI thread.
15
+ */
16
+ @UiThread
17
+ fun onActivityAvailable(activity: AppCompatActivity)
18
+ }
@@ -0,0 +1,99 @@
1
+ @file:OptIn(DelicateCoroutinesApi::class)
2
+
3
+ package expo.modules.kotlin.activityresult
4
+
5
+ import android.app.Activity
6
+ import android.content.Intent
7
+ import androidx.appcompat.app.AppCompatActivity
8
+ import androidx.lifecycle.Lifecycle
9
+ import expo.modules.kotlin.AppContext
10
+ import expo.modules.kotlin.activityaware.AppCompatActivityAware
11
+ import expo.modules.kotlin.activityaware.AppCompatActivityAwareHelper
12
+ import expo.modules.kotlin.activityaware.OnActivityAvailableListener
13
+ import expo.modules.kotlin.activityaware.withActivityAvailable
14
+ import expo.modules.kotlin.providers.CurrentActivityProvider
15
+ import kotlinx.coroutines.DelicateCoroutinesApi
16
+ import kotlinx.coroutines.GlobalScope
17
+ import kotlinx.coroutines.launch
18
+ import java.io.Serializable
19
+ import java.util.concurrent.atomic.AtomicInteger
20
+
21
+ /**
22
+ * Manager class that takes care of proper communication with [AppContextActivityResultRegistry]
23
+ * It also monitors the needed lifecycle state using [AppCompatActivityAwareHelper]
24
+ */
25
+ class ActivityResultsManager(
26
+ currentActivityProvider: CurrentActivityProvider
27
+ ) : AppContextActivityResultCaller, AppCompatActivityAware {
28
+ /**
29
+ * Due to the fact that [AppContext] is not coupled directly with the [Activity]'s lifecycle
30
+ * it's impossible to subscribe all [Lifecycle]'s events properly.
31
+ * That forces us to create our own [AppContextActivityResultRegistry].
32
+ */
33
+ private val registry = AppContextActivityResultRegistry(currentActivityProvider)
34
+ private val nextLocalRequestCode = AtomicInteger()
35
+
36
+ /**
37
+ * Helper property that allows for waiting for [Activity] creation.
38
+ * It is useful when some Module wants to register itself before the current [Activity] is made available.
39
+ */
40
+ private val activityAwareHelper = AppCompatActivityAwareHelper()
41
+
42
+ init {
43
+ GlobalScope.launch {
44
+ withActivityAvailable { activity ->
45
+ registry.restoreInstanceState(activity)
46
+ }
47
+ }
48
+ }
49
+
50
+ // region Lifecycle
51
+
52
+ fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int, data: Intent?) {
53
+ registry.dispatchResult(requestCode, resultCode, data)
54
+ }
55
+
56
+ /**
57
+ * This function is called every time the [Activity] is resumed.
58
+ * If you want to add some mechanism that fires only once (similar to how [Activity.onCreate] works),
59
+ * then use `init` block with [withActivityAvailable].
60
+ */
61
+ fun onHostResume(activity: AppCompatActivity) {
62
+ activityAwareHelper.dispatchOnActivityAvailable(activity)
63
+ }
64
+
65
+ fun onHostDestroy(activity: AppCompatActivity) {
66
+ registry.persistInstanceState(activity)
67
+ }
68
+
69
+ // endregion
70
+
71
+ // region AppContextActivityResultCaller
72
+
73
+ override suspend fun <I : Serializable, O> registerForActivityResult(
74
+ contract: AppContextActivityResultContract<I, O>,
75
+ fallbackCallback: AppContextActivityResultFallbackCallback<I, O>
76
+ ): AppContextActivityResultLauncher<I, O> =
77
+ withActivityAvailable { activity ->
78
+ registry.register(
79
+ "AppContext_rq#${nextLocalRequestCode.getAndIncrement()}",
80
+ activity,
81
+ contract,
82
+ fallbackCallback
83
+ )
84
+ }
85
+
86
+ // endregion
87
+
88
+ // region ActivityAware
89
+
90
+ override fun addOnActivityAvailableListener(listener: OnActivityAvailableListener) {
91
+ activityAwareHelper.addOnActivityAvailableListener(listener)
92
+ }
93
+
94
+ override fun removeOnActivityAvailableListener(listener: OnActivityAvailableListener) {
95
+ activityAwareHelper.removeOnActivityAvailableListener(listener)
96
+ }
97
+
98
+ // endregion
99
+ }
@@ -0,0 +1,25 @@
1
+ package expo.modules.kotlin.activityresult
2
+
3
+ import androidx.annotation.MainThread
4
+ import java.io.Serializable
5
+
6
+ /**
7
+ * This interface is directly based on [androidx.activity.result.ActivityResultCaller], but due to incompatibility
8
+ * of ReactNative and Android's [androidx.lifecycle.Lifecycle] it needed to be adapted.
9
+ * For more information how to use it read [androidx.activity.result.ActivityResultCaller] from `androidx.activity:activity:1.4.0`
10
+ * or even better from `androidx.activity:activity-ktx:1.4.0`.
11
+ *
12
+ * @see [androidx.activity.result.ActivityResultCaller]
13
+ */
14
+ interface AppContextActivityResultCaller {
15
+ /**
16
+ * @see [androidx.activity.result.ActivityResultCaller.registerForActivityResult] from `androidx.activity:activity-ktx:1.4.0`.
17
+ * @param I - input, it is preserved across Activity calls and is delivered to fallback callback
18
+ * @param O - output
19
+ */
20
+ @MainThread
21
+ suspend fun <I : Serializable, O> registerForActivityResult(
22
+ contract: AppContextActivityResultContract<I, O>,
23
+ fallbackCallback: AppContextActivityResultFallbackCallback<I, O>,
24
+ ): AppContextActivityResultLauncher<I, O>
25
+ }
@@ -0,0 +1,27 @@
1
+ package expo.modules.kotlin.activityresult
2
+
3
+ import android.content.Context
4
+ import android.content.Intent
5
+ import java.io.Serializable
6
+
7
+ /**
8
+ * A contract specifying that an activity can be called with an input of type [I] and produce an output of type [O].
9
+ *
10
+ * Makes calling an activity for result type-safe.
11
+ *
12
+ * This interface differs from the original in terms of providing `input` parameter in the [parseResult] method.
13
+ *
14
+ * @see androidx.activity.result.contract.ActivityResultContract
15
+ */
16
+ interface AppContextActivityResultContract<I : Serializable, O> {
17
+ /**
18
+ * Create an intent that can be used for [android.app.Activity.startActivityForResult].
19
+ */
20
+ fun createIntent(context: Context, input: I): Intent
21
+
22
+ /**
23
+ * Convert result obtained from [android.app.Activity.onActivityResult] to [O].
24
+ * @param input the very same input object that is used in [createIntent] method. You can use it to add additional information to constructed result.
25
+ */
26
+ fun parseResult(input: I, resultCode: Int, intent: Intent?): O
27
+ }
@@ -0,0 +1,17 @@
1
+ package expo.modules.kotlin.activityresult
2
+
3
+ import java.io.Serializable
4
+
5
+ /**
6
+ * Interface for fallback callback that has to be registered at the very beginning of module's lifecycle
7
+ * in order to deliver all results in case launching [android.app.Activity] is killed.
8
+ *
9
+ * @see [androidx.activity.result.ActivityResultCallback]
10
+ */
11
+ fun interface AppContextActivityResultFallbackCallback<I : Serializable, O> {
12
+ /**
13
+ * @param input parameters used to construct Intent that launched the operation
14
+ * @param result output constructed by the associated [AppContextActivityResultContract]
15
+ */
16
+ fun onActivityResult(input: I, result: O)
17
+ }
@@ -0,0 +1,30 @@
1
+ package expo.modules.kotlin.activityresult
2
+
3
+ import androidx.activity.result.ActivityResultCallback
4
+ import androidx.activity.result.contract.ActivityResultContract
5
+ import java.io.Serializable
6
+ import kotlin.coroutines.resume
7
+ import kotlin.coroutines.suspendCoroutine
8
+
9
+ /**
10
+ * A launcher for a previously-[AppContextActivityResultCaller.registerForActivityResult] prepared call
11
+ * to start the process of executing an [ActivityResultContract]
12
+ *
13
+ * @param I type of the input required to launch, it also is preserved and delivered in fallback callback
14
+ * @param O result type
15
+ *
16
+ * @see [androidx.activity.result.ActivityResultLauncher]
17
+ */
18
+ abstract class AppContextActivityResultLauncher<I : Serializable, O> {
19
+ /**
20
+ * @param input This would be persisted and restored upon possible Activity destruction by the system
21
+ * to keep context of launching the mechanism.
22
+ */
23
+ abstract fun launch(input: I, callback: ActivityResultCallback<O>)
24
+
25
+ suspend fun launch(input: I): O = suspendCoroutine { continuation ->
26
+ launch(input) { output -> continuation.resume(output) }
27
+ }
28
+
29
+ abstract val contract: AppContextActivityResultContract<I, O>
30
+ }