expo-modules-core 2.0.0-preview.0 → 2.0.0-preview.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 (54) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/ExpoModulesCore.podspec +15 -2
  3. package/android/build.gradle +3 -3
  4. package/android/src/main/java/expo/modules/adapters/react/apploader/RNHeadlessAppLoader.kt +68 -21
  5. package/android/src/main/java/expo/modules/adapters/react/permissions/PermissionsService.kt +14 -5
  6. package/android/src/main/java/expo/modules/adapters/react/services/EventEmitterModule.java +2 -0
  7. package/android/src/main/java/expo/modules/adapters/react/services/UIManagerModuleWrapper.java +5 -0
  8. package/android/src/main/java/expo/modules/core/ModulePriorities.kt +1 -1
  9. package/android/src/main/java/expo/modules/core/ModuleRegistry.java +1 -0
  10. package/android/src/main/java/expo/modules/core/arguments/ReadableArguments.java +1 -0
  11. package/android/src/main/java/expo/modules/interfaces/taskManager/TaskServiceProviderHelper.kt +41 -0
  12. package/android/src/main/java/expo/modules/interfaces/taskManager/TaskServiceProviderInterface.java +18 -0
  13. package/android/src/main/java/expo/modules/kotlin/Promise.kt +6 -6
  14. package/android/src/main/java/expo/modules/kotlin/classcomponent/ClassComponentBuilder.kt +2 -2
  15. package/android/src/main/java/expo/modules/kotlin/devtools/ExpoRequestCdpInterceptor.kt +4 -3
  16. package/android/src/main/java/expo/modules/kotlin/events/EventEmitter.kt +2 -0
  17. package/android/src/main/java/expo/modules/kotlin/events/KModuleEventEmitterWrapper.kt +12 -2
  18. package/android/src/main/java/expo/modules/kotlin/exception/CommonExceptions.kt +16 -0
  19. package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +0 -22
  20. package/android/src/main/java/expo/modules/kotlin/modules/ModuleUtils.kt +25 -0
  21. package/android/src/main/java/expo/modules/kotlin/objects/ObjectDefinitionBuilder.kt +15 -0
  22. package/android/src/main/java/expo/modules/kotlin/sharedobjects/SharedObject.kt +1 -0
  23. package/android/src/main/java/expo/modules/kotlin/types/JSTypeConverterHelper.kt +1 -0
  24. package/android/src/main/java/expo/modules/kotlin/viewevent/ViewEvent.kt +1 -1
  25. package/android/src/main/java/expo/modules/kotlin/views/ExpoView.kt +37 -1
  26. package/android/src/main/java/expo/modules/kotlin/views/GroupViewManagerWrapper.kt +2 -14
  27. package/android/src/main/java/expo/modules/kotlin/views/SimpleViewManagerWrapper.kt +2 -14
  28. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerWrapperDelegate.kt +11 -12
  29. package/build/ts-declarations/global.d.ts +17 -16
  30. package/build/ts-declarations/global.d.ts.map +1 -1
  31. package/ios/AppDelegates/EXAppDelegateWrapper.mm +0 -3
  32. package/ios/Core/{Convertibles → Arguments}/Either.swift +29 -12
  33. package/ios/Core/DynamicTypes/DynamicEitherType.swift +47 -0
  34. package/ios/Core/DynamicTypes/DynamicEnumType.swift +4 -0
  35. package/ios/Core/DynamicTypes/DynamicOptionalType.swift +1 -1
  36. package/ios/Core/Modules/CoreModule.swift +2 -2
  37. package/ios/Core/Protocols/AnyExpoView.swift +6 -0
  38. package/ios/Core/SharedObjects/SharedRef.swift +1 -1
  39. package/ios/Core/Views/ComponentData.swift +1 -1
  40. package/ios/Core/Views/ExpoView.swift +9 -0
  41. package/ios/Core/Views/SwiftUI/SwiftUIHostingView.swift +28 -8
  42. package/ios/Core/Views/SwiftUI/SwiftUIViewDefinition.swift +1 -1
  43. package/ios/DevTools/ExpoRequestCdpInterceptor.swift +1 -1
  44. package/ios/DevTools/ExpoRequestInterceptorProtocol.swift +11 -0
  45. package/ios/DevTools/URLAuthenticationChallengeForwardSender.swift +33 -0
  46. package/ios/DevTools/URLSessionSessionDelegateProxy.swift +15 -0
  47. package/ios/Legacy/NativeModulesProxy/EXNativeModulesProxy.mm +5 -1
  48. package/ios/Tests/DynamicEitherTypeSpec.swift +93 -0
  49. package/ios/Tests/DynamicTypeSpec.swift +18 -0
  50. package/ios/Tests/EitherSpec.swift +0 -44
  51. package/package.json +2 -2
  52. package/src/ts-declarations/global.ts +22 -20
  53. package/ios/Interfaces/BarcodeScanner/EXBarcodeScannerInterface.h +0 -22
  54. package/ios/Interfaces/BarcodeScanner/EXBarcodeScannerProviderInterface.h +0 -9
package/CHANGELOG.md CHANGED
@@ -10,6 +10,73 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 2.0.0-preview.10 — 2024-11-07
14
+
15
+ ### 🐛 Bug fixes
16
+
17
+ - [iOS] Fixed broken self-signed connections from network inspector. ([#32670](https://github.com/expo/expo/pull/32670) by [@kudo](https://github.com/kudo))
18
+
19
+ ## 2.0.0-preview.9 — 2024-10-31
20
+
21
+ ### 💡 Others
22
+
23
+ - [Android] Fix `ClassCastException` in headless app loader under the old architecture. ([#32390](https://github.com/expo/expo/pull/32390) by [@robertying](https://github.com/robertying))
24
+
25
+ ## 2.0.0-preview.8 — 2024-10-31
26
+
27
+ ### 🛠 Breaking changes
28
+
29
+ - Remove expo barcode scanner interface. ([#32198](https://github.com/expo/expo/pull/32198) by [@aleqsio](https://github.com/aleqsio))
30
+
31
+ ### 💡 Others
32
+
33
+ - [android] Added helper for looking up TaskService instance used by expo-task-manager ([#32300](https://github.com/expo/expo/pull/32300) by [@chrfalch](https://github.com/chrfalch))
34
+ - Made TypeScript declaration for `process` an interface. ([#32464](https://github.com/expo/expo/pull/32464) by [@tsapeta](https://github.com/tsapeta))
35
+
36
+ ## 2.0.0-preview.7 — 2024-10-29
37
+
38
+ ### 💡 Others
39
+
40
+ - [Android] Added `shouldUseAndroidLayout` flag to `ExpoView`. ([#32446](https://github.com/expo/expo/pull/32446) by [@lukmccall](https://github.com/lukmccall))
41
+
42
+ ## 2.0.0-preview.6 — 2024-10-29
43
+
44
+ _This version does not introduce any user-facing changes._
45
+
46
+ ## 2.0.0-preview.5 — 2024-10-28
47
+
48
+ ### 🐛 Bug fixes
49
+
50
+ - Fixed updating props on SwiftUI views on the New Architecture. ([#32381](https://github.com/expo/expo/pull/32381) by [@tsapeta](https://github.com/tsapeta))
51
+ - Fixed build error when `use_frameworks!`. ([#32358](https://github.com/expo/expo/pull/32358) by [@kudo](https://github.com/kudo))
52
+
53
+ ## 2.0.0-preview.4 — 2024-10-25
54
+
55
+ ### 💡 Others
56
+
57
+ - Added a new dynamic type dedicated for Either types. ([#32328](https://github.com/expo/expo/pull/32328) by [@tsapeta](https://github.com/tsapeta))
58
+
59
+ ## 2.0.0-preview.3 — 2024-10-24
60
+
61
+ _This version does not introduce any user-facing changes._
62
+
63
+ ## 2.0.0-preview.2 — 2024-10-24
64
+
65
+ ### 🐛 Bug fixes
66
+
67
+ - [iOS] Fix optionals conversion. ([#32239](https://github.com/expo/expo/pull/32239) by [@aleqsio](https://github.com/aleqsio))
68
+ - Fixed retain cycle for `ExpoRequestCdpInterceptor`. ([#32289](https://github.com/expo/expo/pull/32289) by [@kudo](https://github.com/kudo))
69
+
70
+ ### 💡 Others
71
+
72
+ - [android] Add enum event support to OnStartObserving and OnStopObserving. ([#32251](https://github.com/expo/expo/pull/32251), [#32287](https://github.com/expo/expo/pull/32287) by [@wschurman](https://github.com/wschurman))
73
+
74
+ ## 2.0.0-preview.1 — 2024-10-22
75
+
76
+ ### 🐛 Bug fixes
77
+
78
+ - [iOS] Removed window synthesis in `EXAppDelegateWrapper` to fix crashes caused by deallocated `RCTFabricSurface`. ([#32233](https://github.com/expo/expo/pull/32233) by [@tsapeta](https://github.com/tsapeta))
79
+
13
80
  ## 2.0.0-preview.0 — 2024-10-22
14
81
 
15
82
  ### 🛠 Breaking changes
@@ -50,6 +117,8 @@
50
117
 
51
118
  ### 🐛 Bug fixes
52
119
 
120
+ - [Android] Fixed `RNHeadlessAppLoader` class for New Architecture support. ([#32146](https://github.com/expo/expo/pull/32146) by [@chrfalch](https://github.com/chrfalch))
121
+ - [iOS] Fix using enums as optional arguments. ([#32147](https://github.com/expo/expo/pull/32147) by [@aleqsio](https://github.com/aleqsio))
53
122
  - [Android] Change JS return type for kotlin `null` to be `null` instead of `undefined`. ([#31301](https://github.com/expo/expo/pull/31301) by [@aleqsio](https://github.com/aleqsio))
54
123
  - [iOS] Swift `Enumerable`s did not correctly convert to JS values. ([#30191](https://github.com/expo/expo/pull/30191) by [@vonovak](https://github.com/vonovak))
55
124
  - [jest] Fix `uuid` mock in `jest-expo`. ([#29840](https://github.com/expo/expo/pull/29840) by [@EvanBacon](https://github.com/EvanBacon))
@@ -75,6 +144,7 @@
75
144
  - Fixed iOS reload crash on New Architecture mode. ([#31789](https://github.com/expo/expo/pull/31789) by [@kudo](https://github.com/kudo))
76
145
  - [iOS] Fixed views using the incorrect `AppContext` instance. ([#31897](https://github.com/expo/expo/pull/31897) by [@lukmccall](https://github.com/lukmccall))
77
146
  - [iOS] Fixed crashes on the New Architecture when dispatching events during the props update. ([#31971](https://github.com/expo/expo/pull/31971) by [@tsapeta](https://github.com/tsapeta))
147
+ - Fixed `registerAdditionalModuleClasses` deadlock issue on old architecture mode. ([#32209](https://github.com/expo/expo/pull/32209) by [@kudo](https://github.com/kudo))
78
148
 
79
149
  ### 💡 Others
80
150
 
@@ -118,6 +188,7 @@
118
188
  - [Android] Renamed `SharedObject.deallocate` to `SharedObject.sharedObjectDidRelease`. ([#31921](https://github.com/expo/expo/pull/31921) by [@lukmccall](https://github.com/lukmccall))
119
189
  - [Android] Throws a descriptive error when trying to use a released `SharedObject`. ([#31922](https://github.com/expo/expo/pull/31922) by [@lukmccall](https://github.com/lukmccall))
120
190
  - Include error cause message in logger ([#31929](https://github.com/expo/expo/pull/31929), [#31953](https://github.com/expo/expo/pull/31953) by [@wschurman](https://github.com/wschurman))
191
+ - [Android] Started using view's event dispatchers with the `surfaceId`. ([#32227](https://github.com/expo/expo/pull/32227) by [@lukmccall](https://github.com/lukmccall))
121
192
 
122
193
  ### ⚠️ Notices
123
194
 
@@ -47,19 +47,32 @@ Pod::Spec.new do |s|
47
47
  s.static_framework = true
48
48
  s.header_dir = 'ExpoModulesCore'
49
49
 
50
+ header_search_paths = []
51
+ if ENV['USE_FRAMEWORKS']
52
+ header_search_paths.concat([
53
+ # [begin] transitive dependencies of React-RCTAppDelegate that are not defined modules
54
+ '"${PODS_CONFIGURATION_BUILD_DIR}/React-RuntimeApple/React_RuntimeApple.framework/Headers"',
55
+ '"${PODS_CONFIGURATION_BUILD_DIR}/React-RuntimeCore/React_RuntimeCore.framework/Headers"',
56
+ '"${PODS_CONFIGURATION_BUILD_DIR}/React-jserrorhandler/React_jserrorhandler.framework/Headers"',
57
+ '"${PODS_CONFIGURATION_BUILD_DIR}/React-runtimescheduler/React_runtimescheduler.framework/Headers"',
58
+ '"${PODS_CONFIGURATION_BUILD_DIR}/React-performancetimeline/React_performancetimeline.framework/Headers"',
59
+ '"${PODS_CONFIGURATION_BUILD_DIR}/React-rendererconsistency/React_rendererconsistency.framework/Headers"',
60
+ # [end] transitive dependencies of React-RCTAppDelegate that are not defined modules
61
+ ])
62
+ end
50
63
  # Swift/Objective-C compatibility
51
64
  s.pod_target_xcconfig = {
52
65
  'USE_HEADERMAP' => 'YES',
53
66
  'DEFINES_MODULE' => 'YES',
54
67
  'CLANG_CXX_LANGUAGE_STANDARD' => 'c++20',
55
68
  'SWIFT_COMPILATION_MODE' => 'wholemodule',
56
- 'OTHER_SWIFT_FLAGS' => "$(inherited) #{new_arch_enabled ? new_arch_compiler_flags : ''}"
69
+ 'OTHER_SWIFT_FLAGS' => "$(inherited) #{new_arch_enabled ? new_arch_compiler_flags : ''}",
70
+ 'HEADER_SEARCH_PATHS' => header_search_paths.join(' '),
57
71
  }
58
72
  s.user_target_xcconfig = {
59
73
  "HEADER_SEARCH_PATHS" => [
60
74
  '"${PODS_CONFIGURATION_BUILD_DIR}/ExpoModulesCore/Swift Compatibility Header"',
61
75
  '"$(PODS_ROOT)/Headers/Private/Yoga"', # Expo.h -> ExpoModulesCore-umbrella.h -> Fabric ViewProps.h -> Private Yoga headers
62
-
63
76
  ],
64
77
  }
65
78
 
@@ -3,7 +3,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
3
3
  apply plugin: 'com.android.library'
4
4
 
5
5
  group = 'host.exp.exponent'
6
- version = '2.0.0-preview.0'
6
+ version = '2.0.0-preview.10'
7
7
 
8
8
  def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
9
9
  apply from: expoModulesCorePlugin
@@ -67,7 +67,7 @@ android {
67
67
  defaultConfig {
68
68
  consumerProguardFiles 'proguard-rules.pro'
69
69
  versionCode 1
70
- versionName "2.0.0-preview.0"
70
+ versionName "2.0.0-preview.10"
71
71
  buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled.toString()
72
72
 
73
73
  testInstrumentationRunner "expo.modules.TestRunner"
@@ -198,7 +198,7 @@ dependencies {
198
198
 
199
199
  if (shouldTurnWarningsIntoErrors) {
200
200
  tasks.withType(JavaCompile) configureEach {
201
- options.compilerArgs << "-Werror" << "-Xlint:all"
201
+ options.compilerArgs << "-Werror" << "-Xlint:all" << '-Xlint:-serial' << '-Xlint:-rawtypes'
202
202
  }
203
203
  tasks.withType(KotlinCompile) configureEach {
204
204
  compilerOptions.allWarningsAsErrors = true
@@ -1,16 +1,18 @@
1
1
  package expo.modules.adapters.react.apploader
2
2
 
3
+ import android.annotation.SuppressLint
3
4
  import android.content.Context
4
5
  import com.facebook.react.ReactApplication
5
6
  import com.facebook.react.ReactInstanceEventListener
6
7
  import com.facebook.react.ReactInstanceManager
7
8
  import com.facebook.react.bridge.ReactContext
8
9
  import com.facebook.react.common.LifecycleState
10
+ import expo.modules.BuildConfig
9
11
  import expo.modules.apploader.HeadlessAppLoader
10
12
  import expo.modules.core.interfaces.Consumer
11
13
  import expo.modules.core.interfaces.DoNotStrip
12
14
 
13
- private val appRecords: MutableMap<String, ReactInstanceManager> = mutableMapOf()
15
+ private val appRecords: MutableMap<String, ReactContext> = mutableMapOf()
14
16
 
15
17
  class RNHeadlessAppLoader @DoNotStrip constructor(private val context: Context) : HeadlessAppLoader {
16
18
 
@@ -22,16 +24,35 @@ class RNHeadlessAppLoader @DoNotStrip constructor(private val context: Context)
22
24
  }
23
25
 
24
26
  if (context.applicationContext is ReactApplication) {
25
- val reactInstanceManager = (context.applicationContext as ReactApplication).reactNativeHost.reactInstanceManager
26
27
  if (!appRecords.containsKey(params.appScopeKey)) {
27
- reactInstanceManager.addReactInstanceEventListener(object : ReactInstanceEventListener {
28
- override fun onReactContextInitialized(context: ReactContext) {
29
- HeadlessAppLoaderNotifier.notifyAppLoaded(params.appScopeKey)
30
- callback?.apply(true)
31
- }
32
- })
33
- appRecords[params.appScopeKey] = reactInstanceManager
34
- if (!reactInstanceManager.hasStartedCreatingInitialContext()) {
28
+ // In old arch reactHost will be null
29
+ if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
30
+ // New architecture
31
+ val reactHost = (context.applicationContext as ReactApplication).reactHost ?: throw IllegalStateException("Your application does not have a valid reactHost")
32
+ reactHost.addReactInstanceEventListener(
33
+ object : ReactInstanceEventListener {
34
+ override fun onReactContextInitialized(context: ReactContext) {
35
+ reactHost.removeReactInstanceEventListener(this)
36
+ HeadlessAppLoaderNotifier.notifyAppLoaded(params.appScopeKey)
37
+ appRecords[params.appScopeKey] = context
38
+ callback?.apply(true)
39
+ }
40
+ }
41
+ )
42
+ reactHost.start()
43
+ } else {
44
+ // Old architecture
45
+ val reactInstanceManager = (context.applicationContext as ReactApplication).reactNativeHost.reactInstanceManager
46
+ reactInstanceManager.addReactInstanceEventListener(
47
+ object : ReactInstanceEventListener {
48
+ override fun onReactContextInitialized(context: ReactContext) {
49
+ HeadlessAppLoaderNotifier.notifyAppLoaded(params.appScopeKey)
50
+ reactInstanceManager.removeReactInstanceEventListener(this)
51
+ appRecords[params.appScopeKey] = context
52
+ callback?.apply(true)
53
+ }
54
+ }
55
+ )
35
56
  reactInstanceManager.createReactContextInBackground()
36
57
  }
37
58
  } else {
@@ -42,18 +63,34 @@ class RNHeadlessAppLoader @DoNotStrip constructor(private val context: Context)
42
63
  }
43
64
  }
44
65
 
66
+ @SuppressLint("VisibleForTests")
45
67
  override fun invalidateApp(appScopeKey: String?): Boolean {
46
68
  return if (appRecords.containsKey(appScopeKey) && appRecords[appScopeKey] != null) {
47
- val appRecord: ReactInstanceManager = appRecords[appScopeKey]!!
48
- android.os.Handler(context.mainLooper).post {
49
- // Only destroy the `ReactInstanceManager` if it does not bind with an Activity.
50
- // And The Activity would take over the ownership of `ReactInstanceManager`.
51
- // This case happens when a user clicks a background task triggered notification immediately.
52
- if (appRecord.lifecycleState == LifecycleState.BEFORE_CREATE) {
53
- appRecord.destroy()
69
+ val reactContext = appRecords[appScopeKey] ?: return false
70
+ if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
71
+ // New architecture
72
+ val reactHost = (reactContext.applicationContext as ReactApplication).reactHost ?: throw IllegalStateException("Your application does not have a valid reactHost")
73
+ android.os.Handler(reactContext.mainLooper).post {
74
+ reactHost.destroy("Closing headless task app", null)
75
+ HeadlessAppLoaderNotifier.notifyAppDestroyed(appScopeKey)
76
+ appRecords.remove(appScopeKey)
77
+ }
78
+ } else {
79
+ // Old architecture
80
+ val reactNativeHost = (reactContext.applicationContext as ReactApplication).reactNativeHost
81
+ if (reactNativeHost.hasInstance()) {
82
+ val reactInstanceManager: ReactInstanceManager = reactNativeHost.reactInstanceManager
83
+ android.os.Handler(reactContext.mainLooper).post {
84
+ // Only destroy the `ReactInstanceManager` if it does not bind with an Activity.
85
+ // And The Activity would take over the ownership of `ReactInstanceManager`.
86
+ // This case happens when a user clicks a background task triggered notification immediately.
87
+ if (reactInstanceManager.lifecycleState == LifecycleState.BEFORE_CREATE) {
88
+ reactInstanceManager.destroy()
89
+ }
90
+ HeadlessAppLoaderNotifier.notifyAppDestroyed(appScopeKey)
91
+ appRecords.remove(appScopeKey)
92
+ }
54
93
  }
55
- HeadlessAppLoaderNotifier.notifyAppDestroyed(appScopeKey)
56
- appRecords.remove(appScopeKey)
57
94
  }
58
95
  true
59
96
  } else {
@@ -61,8 +98,18 @@ class RNHeadlessAppLoader @DoNotStrip constructor(private val context: Context)
61
98
  }
62
99
  }
63
100
 
64
- override fun isRunning(appScopeKey: String?): Boolean =
65
- appRecords.contains(appScopeKey) && appRecords[appScopeKey]!!.hasStartedCreatingInitialContext()
101
+ override fun isRunning(appScopeKey: String?): Boolean {
102
+ val reactContext = appRecords[appScopeKey] ?: return false
103
+ if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
104
+ // New architecture - We can return true since the fact that we have a reactContext
105
+ // means that we've already called start on the reactHost
106
+ return true
107
+ } else {
108
+ // Old architecture
109
+ val reactNativeHost = (reactContext.applicationContext as ReactApplication).reactNativeHost
110
+ return reactNativeHost.reactInstanceManager.hasStartedCreatingInitialContext()
111
+ }
112
+ }
66
113
 
67
114
  //endregion HeadlessAppLoader
68
115
  }
@@ -13,7 +13,6 @@ import androidx.core.content.ContextCompat
13
13
  import com.facebook.react.modules.core.PermissionAwareActivity
14
14
  import com.facebook.react.modules.core.PermissionListener
15
15
  import expo.modules.core.ModuleRegistry
16
- import expo.modules.core.Promise
17
16
  import expo.modules.core.interfaces.ActivityProvider
18
17
  import expo.modules.core.interfaces.InternalModule
19
18
  import expo.modules.core.interfaces.LifecycleEventListener
@@ -59,7 +58,12 @@ open class PermissionsService(val context: Context) : InternalModule, Permission
59
58
  mAskedPermissionsCache = context.applicationContext.getSharedPreferences(PREFERENCE_FILENAME, Context.MODE_PRIVATE)
60
59
  }
61
60
 
62
- override fun getPermissionsWithPromise(promise: Promise, vararg permissions: String) {
61
+ override fun getPermissionsWithPromise(
62
+ promise:
63
+ @Suppress("DEPRECATION")
64
+ expo.modules.core.Promise,
65
+ vararg permissions: String
66
+ ) {
63
67
  getPermissions(
64
68
  PermissionsResponseListener { permissionsMap: MutableMap<String, PermissionsResponse> ->
65
69
  val areAllGranted = permissionsMap.all { (_, response) -> response.status == PermissionsStatus.GRANTED }
@@ -86,7 +90,12 @@ open class PermissionsService(val context: Context) : InternalModule, Permission
86
90
  )
87
91
  }
88
92
 
89
- override fun askForPermissionsWithPromise(promise: Promise, vararg permissions: String) {
93
+ override fun askForPermissionsWithPromise(
94
+ promise:
95
+ @Suppress("DEPRECATION")
96
+ expo.modules.core.Promise,
97
+ vararg permissions: String
98
+ ) {
90
99
  askForPermissions(
91
100
  PermissionsResponseListener {
92
101
  getPermissionsWithPromise(promise, *permissions)
@@ -165,7 +174,7 @@ open class PermissionsService(val context: Context) : InternalModule, Permission
165
174
  return requestedPermissions!!.contains(permission)
166
175
  }
167
176
  return false
168
- } catch (e: PackageManager.NameNotFoundException) {
177
+ } catch (_: PackageManager.NameNotFoundException) {
169
178
  return false
170
179
  }
171
180
  }
@@ -206,7 +215,7 @@ open class PermissionsService(val context: Context) : InternalModule, Permission
206
215
  private fun canAskAgain(permission: String): Boolean {
207
216
  return mActivityProvider?.currentActivity?.let {
208
217
  ActivityCompat.shouldShowRequestPermissionRationale(it, permission)
209
- } ?: false
218
+ } == true
210
219
  }
211
220
 
212
221
  private fun parseNativeResult(permissionsString: Array<out String>, grantResults: IntArray): Map<String, PermissionsResponse> {
@@ -35,6 +35,7 @@ public class EventEmitterModule implements EventEmitter, InternalModule {
35
35
  }
36
36
 
37
37
  @Override
38
+ @SuppressWarnings("deprecation")
38
39
  public void emit(final int viewId, final String eventName, final Bundle eventBody) {
39
40
  final EventDispatcher dispatcher = UIManagerHelper.getEventDispatcherForReactTag(mReactContext, viewId);
40
41
  dispatcher.dispatchEvent(new com.facebook.react.uimanager.events.Event(viewId) {
@@ -65,6 +66,7 @@ public class EventEmitterModule implements EventEmitter, InternalModule {
65
66
  return Collections.singletonList((Class) EventEmitter.class);
66
67
  }
67
68
 
69
+ @SuppressWarnings("deprecation")
68
70
  private static com.facebook.react.uimanager.events.Event getReactEventFromEvent(final int viewId, final Event event) {
69
71
  return new com.facebook.react.uimanager.events.Event(viewId) {
70
72
  @Override
@@ -70,6 +70,7 @@ public class UIManagerModuleWrapper implements
70
70
  }
71
71
 
72
72
  @Override
73
+ @SuppressWarnings("deprecation")
73
74
  public <T> void addUIBlock(final int tag, final UIBlock<T> block, final Class<T> tClass) {
74
75
  UIBlockInterface uiBlock = new UIBlockInterface() {
75
76
  @Override
@@ -105,6 +106,7 @@ public class UIManagerModuleWrapper implements
105
106
  }
106
107
 
107
108
  @Override
109
+ @SuppressWarnings("deprecation")
108
110
  public void addUIBlock(final GroupUIBlock block) {
109
111
  UIBlockInterface uiBlock = new UIBlockInterface() {
110
112
  @Override
@@ -141,6 +143,7 @@ public class UIManagerModuleWrapper implements
141
143
 
142
144
  @Nullable
143
145
  @Override
146
+ @SuppressWarnings("deprecation")
144
147
  public View resolveView(int viewTag) {
145
148
  final com.facebook.react.bridge.UIManager uiManager = UIManagerHelper.getUIManagerForReactTag(getContext(), viewTag);
146
149
  if (uiManager == null) {
@@ -263,6 +266,7 @@ public class UIManagerModuleWrapper implements
263
266
  }
264
267
 
265
268
  @androidx.annotation.OptIn(markerClass = FrameworkAPI.class)
269
+ @SuppressWarnings("deprecation")
266
270
  public CallInvokerHolderImpl getJSCallInvokerHolder() {
267
271
  return (CallInvokerHolderImpl) mReactContext.getCatalystInstance().getJSCallInvokerHolder();
268
272
  }
@@ -273,5 +277,6 @@ public class UIManagerModuleWrapper implements
273
277
  }
274
278
  }
275
279
 
280
+ @SuppressWarnings("deprecation")
276
281
  interface UIBlockInterface extends com.facebook.react.uimanager.UIBlock, com.facebook.react.fabric.interop.UIBlock {
277
282
  }
@@ -20,7 +20,7 @@ object ModulePriorities {
20
20
  // {key} to {value}
21
21
  // key: full qualified class name
22
22
  // value: priority value, the higher value takes precedence
23
- "expo.modules.splashscreen.SplashScreenPackage" to 11,
23
+ "host.exp.exponent.experience.splashscreen.legacy.SplashScreenPackage" to 11,
24
24
  "expo.modules.updates.UpdatesPackage" to 10
25
25
  )
26
26
  }
@@ -40,6 +40,7 @@ public class ModuleRegistry {
40
40
  return (T) mInternalModulesMap.get(interfaceClass);
41
41
  }
42
42
 
43
+ @SuppressWarnings("unchecked")
43
44
  public <T> T getSingletonModule(String singletonName, Class<T> singletonClass) {
44
45
  return (T) mSingletonModulesMap.get(singletonName);
45
46
  }
@@ -63,6 +63,7 @@ public interface ReadableArguments {
63
63
 
64
64
  int size();
65
65
 
66
+ @SuppressWarnings("unchecked")
66
67
  default Bundle toBundle() {
67
68
  Bundle bundle = new Bundle();
68
69
  for (String key : keys()) {
@@ -0,0 +1,41 @@
1
+ package expo.modules.interfaces.taskManager
2
+
3
+ import android.content.Context
4
+ import expo.modules.core.ModulePriorities
5
+ import expo.modules.core.interfaces.DoNotStrip
6
+ import expo.modules.core.interfaces.Package
7
+
8
+ @DoNotStrip
9
+ object TaskServiceProviderHelper {
10
+ /**
11
+ Uses reflection to look through the current list of packages and attempts to find
12
+ one that provides a TaskServiceInterface implementation.
13
+ @param context Provide the application context (context.getApplicationContext())
14
+ @return A implementation of the TaskServiceInterface it a package offers it
15
+ */
16
+ @DoNotStrip
17
+ fun getTaskServiceImpl(context: Context): TaskServiceInterface? {
18
+ // Use reflection to get the packages list from ExpoModulesPackageList without
19
+ // creating the reactInstanceManager. ExpoModulesPackageList is generated by
20
+ // autolinking and should safely be callable in this way - we already have a
21
+ // few other places in our code where it is called like this.
22
+ val expoModules: Class<*>? = try {
23
+ Class.forName("expo.modules.ExpoModulesPackageList")
24
+ } catch (e: ClassNotFoundException) {
25
+ // Handle the exception, e.g., log it or fallback to a default behavior
26
+ return null
27
+ }
28
+ val getPackageList = expoModules?.getMethod("getPackageList") ?: return null
29
+
30
+ // Invoke and get the list of packages
31
+ val result = getPackageList.invoke(null) as? List<*> ?: return null
32
+ val packages = result.filterIsInstance<Package>()
33
+ .sortedByDescending { ModulePriorities.get(it::class.qualifiedName) }
34
+
35
+ // Check if any of the packages are providing a task manager implementation
36
+ return packages
37
+ .filterIsInstance<TaskServiceProviderInterface>()
38
+ .firstOrNull()
39
+ ?.getTaskServiceImpl(context)
40
+ }
41
+ }
@@ -0,0 +1,18 @@
1
+ package expo.modules.interfaces.taskManager;
2
+
3
+ import android.content.Context;
4
+
5
+ import expo.modules.core.interfaces.Package;
6
+
7
+ /**
8
+ * Interface defining a package that provides a TaskServiceInterface implementation.
9
+ * This is utilized when an app is launched in the background without an activity.
10
+ * It enables running expo-task-manager JavaScript tasks in the background via the HeadlessAppLoader.
11
+ */
12
+ public interface TaskServiceProviderInterface extends Package {
13
+ /**
14
+ * @param context Current application context
15
+ * @return A task service implementation that can be provided without having setup the whole app
16
+ */
17
+ TaskServiceInterface getTaskServiceImpl(Context context);
18
+ }
@@ -46,15 +46,15 @@ fun Promise.toBridgePromise(): com.facebook.react.bridge.Promise {
46
46
  }
47
47
 
48
48
  override fun reject(code: String, message: String?) {
49
- expoPromise.reject(code ?: unknownCode, message, null)
49
+ expoPromise.reject(code, message, null)
50
50
  }
51
51
 
52
52
  override fun reject(code: String, throwable: Throwable?) {
53
- expoPromise.reject(code ?: unknownCode, null, throwable)
53
+ expoPromise.reject(code, null, throwable)
54
54
  }
55
55
 
56
56
  override fun reject(code: String, message: String?, throwable: Throwable?) {
57
- expoPromise.reject(code ?: unknownCode, message, throwable)
57
+ expoPromise.reject(code, message, throwable)
58
58
  }
59
59
 
60
60
  override fun reject(throwable: Throwable) {
@@ -66,15 +66,15 @@ fun Promise.toBridgePromise(): com.facebook.react.bridge.Promise {
66
66
  }
67
67
 
68
68
  override fun reject(code: String, userInfo: WritableMap) {
69
- expoPromise.reject(code ?: unknownCode, null, null)
69
+ expoPromise.reject(code, null, null)
70
70
  }
71
71
 
72
72
  override fun reject(code: String, throwable: Throwable?, userInfo: WritableMap) {
73
- expoPromise.reject(code ?: unknownCode, null, throwable)
73
+ expoPromise.reject(code, null, throwable)
74
74
  }
75
75
 
76
76
  override fun reject(code: String, message: String?, userInfo: WritableMap) {
77
- expoPromise.reject(code ?: unknownCode, message, null)
77
+ expoPromise.reject(code, message, null)
78
78
  }
79
79
 
80
80
  override fun reject(code: String?, message: String?, throwable: Throwable?, userInfo: WritableMap?) {
@@ -32,10 +32,10 @@ class ClassComponentBuilder<SharedObjectType : Any>(
32
32
 
33
33
  if (eventsDefinition != null && isSharedObject) {
34
34
  listOf("__expo_onStartListeningToEvent" to SharedObject::onStartListeningToEvent, "__expo_onStopListeningToEvent" to SharedObject::onStopListeningToEvent)
35
- .forEach { (name, function) ->
35
+ .forEach { (name, listener) ->
36
36
  SyncFunctionComponent(name, arrayOf(ownerType, toAnyType<String>()), toReturnType<Unit>()) { (self, eventName) ->
37
37
  enforceType<SharedObject, String>(self, eventName)
38
- function.invoke(self, eventName)
38
+ listener.invoke(self, eventName)
39
39
  }.also { function ->
40
40
  function.enumerable(false)
41
41
  syncFunctions[name] = function
@@ -14,6 +14,7 @@ import kotlinx.coroutines.launch
14
14
  import okhttp3.Request
15
15
  import okhttp3.Response
16
16
  import okhttp3.ResponseBody
17
+ import java.lang.ref.WeakReference
17
18
  import java.math.BigDecimal
18
19
  import java.math.RoundingMode
19
20
 
@@ -22,18 +23,18 @@ import java.math.RoundingMode
22
23
  * dispatch CDP (Chrome DevTools Protocol: https://chromedevtools.github.io/devtools-protocol/) events.
23
24
  */
24
25
  object ExpoRequestCdpInterceptor : ExpoNetworkInspectOkHttpInterceptorsDelegate {
25
- private var delegate: Delegate? = null
26
+ private var delegate: WeakReference<Delegate?> = WeakReference(null)
26
27
  internal var coroutineScope = CoroutineScope(Dispatchers.Default)
27
28
 
28
29
  fun setDelegate(delegate: Delegate?) {
29
30
  coroutineScope.launch {
30
- this@ExpoRequestCdpInterceptor.delegate = delegate
31
+ this@ExpoRequestCdpInterceptor.delegate = WeakReference(delegate)
31
32
  }
32
33
  }
33
34
 
34
35
  private fun dispatchEvent(event: Event) {
35
36
  coroutineScope.launch {
36
- this@ExpoRequestCdpInterceptor.delegate?.dispatch(event.toJson())
37
+ this@ExpoRequestCdpInterceptor.delegate.get()?.dispatch(event.toJson())
37
38
  }
38
39
  }
39
40
 
@@ -1,5 +1,6 @@
1
1
  package expo.modules.kotlin.events
2
2
 
3
+ import android.view.View
3
4
  import com.facebook.react.bridge.WritableMap
4
5
  import expo.modules.kotlin.records.Record
5
6
 
@@ -10,4 +11,5 @@ interface EventEmitter : expo.modules.core.interfaces.services.EventEmitter {
10
11
  fun emit(eventName: String, eventBody: Record?)
11
12
  fun emit(eventName: String, eventBody: Map<*, *>?)
12
13
  fun emit(viewId: Int, eventName: String, eventBody: WritableMap?, coalescingKey: Short? = null)
14
+ fun emit(view: View, eventName: String, eventBody: WritableMap?, coalescingKey: Short? = null)
13
15
  }
@@ -1,6 +1,7 @@
1
1
  package expo.modules.kotlin.events
2
2
 
3
3
  import android.os.Bundle
4
+ import android.view.View
4
5
  import com.facebook.react.bridge.Arguments
5
6
  import com.facebook.react.bridge.ReactApplicationContext
6
7
  import com.facebook.react.bridge.ReadableNativeMap
@@ -96,15 +97,24 @@ open class KEventEmitterWrapper(
96
97
  override fun emit(viewId: Int, eventName: String, eventBody: WritableMap?, coalescingKey: Short?) {
97
98
  val context = reactContextHolder.get() ?: return
98
99
  UIManagerHelper.getEventDispatcherForReactTag(context, viewId)
99
- ?.dispatchEvent(UIEvent(viewId, eventName, eventBody, coalescingKey))
100
+ ?.dispatchEvent(UIEvent(surfaceId = -1, viewId, eventName, eventBody, coalescingKey))
101
+ }
102
+
103
+ override fun emit(view: View, eventName: String, eventBody: WritableMap?, coalescingKey: Short?) {
104
+ val context = reactContextHolder.get() ?: return
105
+ val surfaceId = UIManagerHelper.getSurfaceId(view)
106
+ val viewId = view.id
107
+ UIManagerHelper.getEventDispatcherForReactTag(context, view.id)
108
+ ?.dispatchEvent(UIEvent(surfaceId, viewId, eventName, eventBody, coalescingKey))
100
109
  }
101
110
 
102
111
  private class UIEvent(
112
+ surfaceId: Int,
103
113
  viewId: Int,
104
114
  private val eventName: String,
105
115
  private val eventBody: WritableMap?,
106
116
  private val coalescingKey: Short?
107
- ) : com.facebook.react.uimanager.events.Event<UIEvent>(viewId) {
117
+ ) : com.facebook.react.uimanager.events.Event<UIEvent>(surfaceId, viewId) {
108
118
  override fun getEventName(): String = normalizeEventName(eventName)
109
119
  override fun canCoalesce(): Boolean = coalescingKey != null
110
120
  override fun getCoalescingKey(): Short = coalescingKey ?: 0
@@ -70,4 +70,20 @@ class Exceptions {
70
70
  * An exception to throw when the root view is missing.
71
71
  */
72
72
  class MissingRootView : CodedException(message = "The root view is missing")
73
+
74
+ /**
75
+ * An exception to throw to indicate that a method has been passed an illegal or inappropriate argument.
76
+ */
77
+ class IllegalArgument(
78
+ message: String,
79
+ cause: Throwable? = null
80
+ ) : CodedException(message, cause)
81
+
82
+ /**
83
+ * An exception to signal that a method has been invoked at an illegal or inappropriate time.
84
+ */
85
+ class IllegalStateException(
86
+ message: String,
87
+ cause: Throwable? = null
88
+ ) : CodedException(message, cause)
73
89
  }