expo-modules-core 1.11.0 β†’ 1.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -10,6 +10,12 @@
10
10
 
11
11
  ### πŸ’‘ Others
12
12
 
13
+ ## 1.11.1 β€” 2023-12-12
14
+
15
+ ### πŸ› Bug fixes
16
+
17
+ - [Android] Fixed `OnCreate` was called before the `React` instance was ready. ([#25866](https://github.com/expo/expo/pull/25866) by [@lukmccall](https://github.com/lukmccall))
18
+
13
19
  ## 1.11.0 β€” 2023-12-12
14
20
 
15
21
  ### πŸŽ‰ New features
@@ -5,7 +5,7 @@ apply plugin: 'kotlin-android'
5
5
  apply plugin: 'maven-publish'
6
6
 
7
7
  group = 'host.exp.exponent'
8
- version = '1.11.0'
8
+ version = '1.11.1'
9
9
 
10
10
  def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
11
11
  if (expoModulesCorePlugin.exists()) {
@@ -143,7 +143,7 @@ android {
143
143
  defaultConfig {
144
144
  consumerProguardFiles 'proguard-rules.pro'
145
145
  versionCode 1
146
- versionName "1.11.0"
146
+ versionName "1.11.1"
147
147
  buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled.toString()
148
148
 
149
149
  testInstrumentationRunner "expo.modules.TestRunner"
@@ -97,7 +97,10 @@ public class NativeModulesProxy extends ReactContextBaseJavaModule {
97
97
  }
98
98
 
99
99
  mModuleRegistry.ensureIsInitialized();
100
- getKotlinInteropModuleRegistry().installJSIInterop();
100
+
101
+ KotlinInteropModuleRegistry kotlinModuleRegistry = getKotlinInteropModuleRegistry();
102
+ kotlinModuleRegistry.emitOnCreate();
103
+ kotlinModuleRegistry.installJSIInterop();
101
104
 
102
105
  Collection<ExportedModule> exportedModules = mModuleRegistry.getAllExportedModules();
103
106
 
@@ -121,7 +121,7 @@ class AppContext(
121
121
  addActivityEventListener(reactLifecycleDelegate)
122
122
 
123
123
  // Registering modules has to happen at the very end of `AppContext` creation. Some modules need to access
124
- // `AppContext` during their initialisation (or during `OnCreate` method), so we need to ensure all `AppContext`'s
124
+ // `AppContext` during their initialisation, so we need to ensure all `AppContext`'s
125
125
  // properties are initialized first. Not having that would trigger NPE.
126
126
  registry.register(ErrorManagerModule())
127
127
  registry.register(NativeModulesProxyModule())
@@ -131,6 +131,12 @@ class AppContext(
131
131
  }
132
132
  }
133
133
 
134
+ fun onCreate() = trace("AppContext.onCreate") {
135
+ registry.readyForPostingEvents()
136
+ registry.post(EventName.MODULE_CREATE)
137
+ registry.flushTheEventQueue()
138
+ }
139
+
134
140
  /**
135
141
  * Initializes a JSI part of the module registry.
136
142
  * It will be a NOOP if the remote debugging was activated.
@@ -128,6 +128,10 @@ class KotlinInteropModuleRegistry(
128
128
  appContext.installJSIInterop()
129
129
  }
130
130
 
131
+ fun emitOnCreate() {
132
+ appContext.onCreate()
133
+ }
134
+
131
135
  fun setLegacyModulesProxy(proxyModule: NativeModulesProxy) {
132
136
  appContext.legacyModulesProxyHolder = WeakReference(proxyModule)
133
137
  }
@@ -16,6 +16,10 @@ class ModuleRegistry(
16
16
  @PublishedApi
17
17
  internal val registry = mutableMapOf<String, ModuleHolder<*>>()
18
18
 
19
+ private val eventQueue = mutableListOf<PostponedEvent>()
20
+
21
+ private var isReadyForPostingEvents = false
22
+
19
23
  fun <T : Module> register(module: T) = trace("ModuleRegistry.register(${module.javaClass})") {
20
24
  module._appContext = requireNotNull(appContext.get()) { "Cannot create a module for invalid app context." }
21
25
 
@@ -30,7 +34,6 @@ class ModuleRegistry(
30
34
  }
31
35
 
32
36
  holder.apply {
33
- post(EventName.MODULE_CREATE)
34
37
  registerContracts()
35
38
  }
36
39
 
@@ -73,20 +76,30 @@ class ModuleRegistry(
73
76
  }
74
77
 
75
78
  fun post(eventName: EventName) {
79
+ if (addToQueueIfNeeded(eventName)) {
80
+ return
81
+ }
82
+
76
83
  forEach {
77
84
  it.post(eventName)
78
85
  }
79
86
  }
80
87
 
81
- @Suppress("UNCHECKED_CAST")
82
88
  fun <Sender> post(eventName: EventName, sender: Sender) {
89
+ if (addToQueueIfNeeded(eventName, sender)) {
90
+ return
91
+ }
92
+
83
93
  forEach {
84
94
  it.post(eventName, sender)
85
95
  }
86
96
  }
87
97
 
88
- @Suppress("UNCHECKED_CAST")
89
98
  fun <Sender, Payload> post(eventName: EventName, sender: Sender, payload: Payload) {
99
+ if (addToQueueIfNeeded(eventName, sender, payload)) {
100
+ return
101
+ }
102
+
90
103
  forEach {
91
104
  it.post(eventName, sender, payload)
92
105
  }
@@ -98,4 +111,60 @@ class ModuleRegistry(
98
111
  registry.clear()
99
112
  logger.info("βœ… ModuleRegistry was destroyed")
100
113
  }
114
+
115
+ /**
116
+ * Tell the modules registry it can handle events as they come, without adding them to the event queue.
117
+ */
118
+ fun readyForPostingEvents() = synchronized(this) {
119
+ isReadyForPostingEvents = true
120
+ }
121
+
122
+ fun flushTheEventQueue() = synchronized(this) {
123
+ eventQueue.forEach { event ->
124
+ forEach {
125
+ event.post(it)
126
+ }
127
+ }
128
+ eventQueue.clear()
129
+ }
130
+
131
+ /**
132
+ * It’s important that the [EventName.MODULE_CREATE] event is emitted first by the registry.
133
+ * However, some events like [EventName.ACTIVITY_ENTERS_FOREGROUND] are automatically emitted when the catalyst instance is created.
134
+ * To ensure the correct order of events, we capture all events that are emitted
135
+ * during the initialization phase and send them back to the modules later.
136
+ * This way, we can ensure that the order of events is correct.
137
+ */
138
+ private fun addToQueueIfNeeded(
139
+ eventName: EventName,
140
+ sender: Any? = null,
141
+ payload: Any? = null
142
+ ): Boolean = synchronized(this) {
143
+ if (isReadyForPostingEvents) {
144
+ return false
145
+ }
146
+
147
+ eventQueue.add(PostponedEvent(eventName, sender, payload))
148
+ return true
149
+ }
150
+
151
+ data class PostponedEvent(
152
+ val eventName: EventName,
153
+ val sender: Any? = null,
154
+ val payload: Any? = null
155
+ ) {
156
+ fun post(moduleHolder: ModuleHolder<*>) {
157
+ if (sender != null && payload != null) {
158
+ moduleHolder.post(eventName, sender, payload)
159
+ return
160
+ }
161
+
162
+ if (sender != null) {
163
+ moduleHolder.post(eventName, sender)
164
+ return
165
+ }
166
+
167
+ moduleHolder.post(eventName)
168
+ }
169
+ }
101
170
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-modules-core",
3
- "version": "1.11.0",
3
+ "version": "1.11.1",
4
4
  "description": "The core of Expo Modules architecture",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -44,5 +44,5 @@
44
44
  "@testing-library/react-hooks": "^7.0.1",
45
45
  "expo-module-scripts": "^3.0.0"
46
46
  },
47
- "gitHead": "6aca7ce098ddc667776a3d7cf612adbb985e264a"
47
+ "gitHead": "298f6e97c5eda609a25e87a7951540480119a403"
48
48
  }