expo-modules-core 0.11.5 → 0.11.7

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,17 +10,31 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 0.11.7 — 2022-10-06
14
+
15
+ ### 🐛 Bug fixes
16
+
17
+ - Fixed `ModuleRegistry` be initialized twice when startup on Android. ([#19384](https://github.com/expo/expo/pull/19384) by [@kudo](https://github.com/kudo) and [@lukmccall](https://github.com/lukmccall))
18
+ - Ensure that AppDelegate callbacks are invoked. ([#19393](https://github.com/expo/expo/pull/19393) by [@ferologics](https://github.com/ferologics))
19
+ - Fixed Android crash when Activity is destroyed before `AppContext.onHostDestroy` call. ([#19406](https://github.com/expo/expo/pull/19406) by [@kudo](https://github.com/kudo))
20
+
21
+ ## 0.11.6 — 2022-10-02
22
+
23
+ ### 🐛 Bug fixes
24
+
25
+ - Give precedence to `UIBackgroundFetchResult.newData` over `.failed` in proxied `ExpoAppDelegate.swift` completion handlers. ([#19311](https://github.com/expo/expo/pull/19311) by [@ferologics](https://github.com/ferologics))
26
+
13
27
  ## 0.11.5 — 2022-09-01
14
28
 
15
29
  ### 🐛 Bug fixes
16
30
 
17
- - Removed the hard dependency to Hermes or JSC in *libexpo-modules-core.so* on Android and fixed the broken support for react-native-v8. ([#18899](https://github.com/expo/expo/pull/18899) by [@kudo](https://github.com/kudo))
31
+ - Removed the hard dependency to Hermes or JSC in _libexpo-modules-core.so_ on Android and fixed the broken support for react-native-v8. ([#18899](https://github.com/expo/expo/pull/18899) by [@kudo](https://github.com/kudo))
18
32
 
19
33
  ## 0.11.4 — 2022-08-18
20
34
 
21
35
  ### 🐛 Bug fixes
22
36
 
23
- - Fix issue with Android builds when gradle clean and build were called concurrently. ([#18518](https://github.com/expo/expo/pull/18518) by [EdwardDrapkin](https://github.com/EdwardDrapkin))
37
+ - Fix issue with Android builds when gradle clean and build were called concurrently. ([#18518](https://github.com/expo/expo/pull/18518) by [EdwardDrapkin](https://github.com/EdwardDrapkin))
24
38
  - Fixed `FabricUIManager` errors when turning on new architecture mode on Android. ([#18472](https://github.com/expo/expo/pull/18472) by [@kudo](https://github.com/kudo))
25
39
 
26
40
  ## 0.11.3 — 2022-07-18
@@ -6,7 +6,7 @@ apply plugin: 'maven-publish'
6
6
  apply plugin: "de.undercouch.download"
7
7
 
8
8
  group = 'host.exp.exponent'
9
- version = '0.11.5'
9
+ version = '0.11.7'
10
10
 
11
11
  buildscript {
12
12
  def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
@@ -161,7 +161,7 @@ android {
161
161
  targetSdkVersion safeExtGet("targetSdkVersion", 31)
162
162
  consumerProguardFiles 'proguard-rules.pro'
163
163
  versionCode 1
164
- versionName "0.11.5"
164
+ versionName "0.11.7"
165
165
 
166
166
  testInstrumentationRunner "expo.modules.TestRunner"
167
167
 
@@ -59,7 +59,7 @@ void JSIInteropModuleRegistry::installJSI(
59
59
 
60
60
  void JSIInteropModuleRegistry::installJSIForTests() {
61
61
  #if !UNIT_TEST
62
- throw std::logic_error("The function is only avaiable when UNIT_TEST is defined.");
62
+ throw std::logic_error("The function is only available when UNIT_TEST is defined.");
63
63
  #else
64
64
  runtimeHolder = std::make_shared<JavaScriptRuntime>();
65
65
  jsi::Runtime &jsiRuntime = *runtimeHolder->get();
@@ -1,5 +1,8 @@
1
1
  package expo.modules.adapters.react;
2
2
 
3
+ import android.util.Log;
4
+ import androidx.annotation.Nullable;
5
+
3
6
  import com.facebook.react.ReactPackage;
4
7
  import com.facebook.react.bridge.NativeModule;
5
8
  import com.facebook.react.bridge.ReactApplicationContext;
@@ -46,7 +49,8 @@ public class ModuleRegistryAdapter implements ReactPackage {
46
49
 
47
50
  @Override
48
51
  public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
49
- ModuleRegistry moduleRegistry = mModuleRegistryProvider.get(reactContext);
52
+ NativeModulesProxy proxy = getOrCreateNativeModulesProxy(reactContext, null);
53
+ ModuleRegistry moduleRegistry = proxy.getModuleRegistry();
50
54
 
51
55
  for (InternalModule internalModule : mReactAdapterPackage.createInternalModules(reactContext)) {
52
56
  moduleRegistry.registerInternalModule(internalModule);
@@ -54,7 +58,7 @@ public class ModuleRegistryAdapter implements ReactPackage {
54
58
 
55
59
  List<NativeModule> nativeModules = getNativeModulesFromModuleRegistry(reactContext, moduleRegistry);
56
60
  if (mWrapperDelegateHolders != null) {
57
- KotlinInteropModuleRegistry kotlinInteropModuleRegistry = getOrCreateNativeModulesProxy(reactContext).getKotlinInteropModuleRegistry();
61
+ KotlinInteropModuleRegistry kotlinInteropModuleRegistry = proxy.getKotlinInteropModuleRegistry();
58
62
  kotlinInteropModuleRegistry.updateModuleHoldersInViewManagers(mWrapperDelegateHolders);
59
63
  }
60
64
 
@@ -64,7 +68,7 @@ public class ModuleRegistryAdapter implements ReactPackage {
64
68
  protected List<NativeModule> getNativeModulesFromModuleRegistry(ReactApplicationContext reactContext, ModuleRegistry moduleRegistry) {
65
69
  List<NativeModule> nativeModulesList = new ArrayList<>(2);
66
70
 
67
- nativeModulesList.add(getOrCreateNativeModulesProxy(reactContext));
71
+ nativeModulesList.add(getOrCreateNativeModulesProxy(reactContext, moduleRegistry));
68
72
 
69
73
  // Add listener that will notify expo.modules.core.ModuleRegistry when all modules are ready
70
74
  nativeModulesList.add(new ModuleRegistryReadyNotifier(moduleRegistry));
@@ -93,7 +97,7 @@ public class ModuleRegistryAdapter implements ReactPackage {
93
97
  }
94
98
  }
95
99
 
96
- NativeModulesProxy modulesProxy = Objects.requireNonNull(getOrCreateNativeModulesProxy(reactContext));
100
+ NativeModulesProxy modulesProxy = Objects.requireNonNull(getOrCreateNativeModulesProxy(reactContext, null));
97
101
  KotlinInteropModuleRegistry kotlinInteropModuleRegistry = modulesProxy.getKotlinInteropModuleRegistry();
98
102
  List<ViewManager<?, ?>> kViewManager = kotlinInteropModuleRegistry.exportViewManagers();
99
103
  // Saves all holders that needs to be in sync with module registry
@@ -103,15 +107,26 @@ public class ModuleRegistryAdapter implements ReactPackage {
103
107
  return viewManagerList;
104
108
  }
105
109
 
106
- private NativeModulesProxy getOrCreateNativeModulesProxy(ReactApplicationContext reactContext) {
110
+ private synchronized NativeModulesProxy getOrCreateNativeModulesProxy(
111
+ ReactApplicationContext reactContext,
112
+ @Nullable ModuleRegistry moduleRegistry
113
+ ) {
114
+ if (mModulesProxy != null && mModulesProxy.getKotlinInteropModuleRegistry().getWasDestroyed()) {
115
+ mModulesProxy = null;
116
+ }
107
117
  if (mModulesProxy == null) {
108
- ModuleRegistry moduleRegistry = mModuleRegistryProvider.get(reactContext);
118
+ ModuleRegistry registry = moduleRegistry != null ? moduleRegistry : mModuleRegistryProvider.get(reactContext);
109
119
  if (mModulesProvider != null) {
110
- mModulesProxy = new NativeModulesProxy(reactContext, moduleRegistry, mModulesProvider);
120
+ mModulesProxy = new NativeModulesProxy(reactContext, registry, mModulesProvider);
111
121
  } else {
112
- mModulesProxy = new NativeModulesProxy(reactContext, moduleRegistry);
122
+ mModulesProxy = new NativeModulesProxy(reactContext, registry);
113
123
  }
114
124
  }
125
+
126
+ if (moduleRegistry != null && moduleRegistry != mModulesProxy.getModuleRegistry()) {
127
+ Log.e("expo-modules-core", "NativeModuleProxy was configured with a different instance of the modules registry.");
128
+ }
129
+
115
130
  return mModulesProxy;
116
131
  }
117
132
  }
@@ -1,5 +1,6 @@
1
1
  package expo.modules.adapters.react;
2
2
 
3
+ import android.util.Log;
3
4
  import android.util.SparseArray;
4
5
 
5
6
  import com.facebook.react.bridge.Dynamic;
@@ -127,6 +128,9 @@ public class NativeModulesProxy extends ReactContextBaseJavaModule {
127
128
  constants.put(MODULES_CONSTANTS_KEY, modulesConstants);
128
129
  constants.put(EXPORTED_METHODS_KEY, exportedMethodsMap);
129
130
  constants.put(VIEW_MANAGERS_METADATA_KEY, viewManagersMetadata);
131
+
132
+ Log.i("ExpoModulesCore", "✅ Constants was exported");
133
+
130
134
  return constants;
131
135
  }
132
136
 
@@ -247,4 +251,8 @@ public class NativeModulesProxy extends ReactContextBaseJavaModule {
247
251
  mModuleRegistry.onDestroy();
248
252
  mKotlinInteropModuleRegistry.onDestroy();
249
253
  }
254
+
255
+ ModuleRegistry getModuleRegistry() {
256
+ return mModuleRegistry;
257
+ }
250
258
  }
@@ -5,12 +5,14 @@ package expo.modules.kotlin
5
5
  import android.app.Activity
6
6
  import android.content.Context
7
7
  import android.content.Intent
8
+ import android.util.Log
8
9
  import androidx.annotation.MainThread
9
10
  import androidx.appcompat.app.AppCompatActivity
10
11
  import com.facebook.react.bridge.ReactApplicationContext
11
12
  import com.facebook.react.turbomodule.core.CallInvokerHolderImpl
12
13
  import expo.modules.core.errors.ContextDestroyedException
13
14
  import expo.modules.core.interfaces.ActivityProvider
15
+ import expo.modules.core.interfaces.JavaScriptContextProvider
14
16
  import expo.modules.interfaces.barcodescanner.BarCodeScannerInterface
15
17
  import expo.modules.interfaces.camera.CameraViewInterface
16
18
  import expo.modules.interfaces.constants.ConstantsInterface
@@ -86,18 +88,25 @@ class AppContext(
86
88
  * Initializes a JSI part of the module registry.
87
89
  * It will be a NOOP if the remote debugging was activated.
88
90
  */
89
- fun installJSIInterop() {
90
- jsiInterop = JSIInteropModuleRegistry(this)
91
- val reactContext = reactContextHolder.get() ?: return
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
- }
91
+ fun installJSIInterop() = synchronized<Unit>(this) {
92
+ try {
93
+ jsiInterop = JSIInteropModuleRegistry(this)
94
+ val reactContext = reactContextHolder.get() ?: return
95
+ val jsContextHolder = legacyModule<JavaScriptContextProvider>()?.javaScriptContextRef
96
+ val catalystInstance = reactContext.catalystInstance ?: return
97
+ jsContextHolder
98
+ ?.takeIf { it != 0L }
99
+ ?.let {
100
+ jsiInterop.installJSI(
101
+ it,
102
+ catalystInstance.jsCallInvokerHolder as CallInvokerHolderImpl,
103
+ catalystInstance.nativeCallInvokerHolder as CallInvokerHolderImpl
104
+ )
105
+ Log.i("ExpoModulesCore", "✅ JSI interop was installed")
106
+ }
107
+ } catch (e: Throwable) {
108
+ Log.e("ExpoModulesCore", "Cannot install JSI interop: $e", e)
109
+ }
101
110
  }
102
111
 
103
112
  /**
@@ -223,11 +232,9 @@ class AppContext(
223
232
  }
224
233
 
225
234
  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
- )
235
+ currentActivity?.let {
236
+ activityResultsManager.onHostDestroy(it)
237
+ }
231
238
  registry.post(EventName.ACTIVITY_DESTROYS)
232
239
  }
233
240
 
@@ -25,6 +25,9 @@ class KotlinInteropModuleRegistry(
25
25
  private val registry: ModuleRegistry
26
26
  get() = appContext.registry
27
27
 
28
+ var wasDestroyed = false
29
+ private set
30
+
28
31
  fun hasModule(name: String): Boolean = registry.hasModule(name)
29
32
 
30
33
  fun callMethod(moduleName: String, method: String, arguments: ReadableArray, promise: Promise) {
@@ -108,6 +111,7 @@ class KotlinInteropModuleRegistry(
108
111
 
109
112
  fun onDestroy() {
110
113
  appContext.onDestroy()
114
+ wasDestroyed = true
111
115
  }
112
116
 
113
117
  fun installJSIInterop() {
@@ -74,5 +74,6 @@ class ModuleRegistry(
74
74
  forEach {
75
75
  it.cleanUp()
76
76
  }
77
+ registry.clear()
77
78
  }
78
79
  }
@@ -90,9 +90,13 @@ static dispatch_once_t onceToken;
90
90
  }
91
91
  }
92
92
  };
93
-
94
- for (id<UIApplicationDelegate> subcontractor in subcontractorsArray) {
95
- [subcontractor application:application performFetchWithCompletionHandler:handler];
93
+
94
+ if (subcontractorsLeft == 0) {
95
+ completionHandler(fetchResult);
96
+ } else {
97
+ for (id<UIApplicationDelegate> subcontractor in subcontractorsArray) {
98
+ [subcontractor application:application performFetchWithCompletionHandler:handler];
99
+ }
96
100
  }
97
101
  }
98
102
 
@@ -201,9 +205,13 @@ static dispatch_once_t onceToken;
201
205
  }
202
206
  }
203
207
  };
204
-
205
- for (id<UIApplicationDelegate> subcontractor in subcontractorsArray) {
206
- [subcontractor application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:handler];
208
+
209
+ if (subcontractorsLeft == 0) {
210
+ completionHandler(fetchResult);
211
+ } else {
212
+ for (id<UIApplicationDelegate> subcontractor in subcontractorsArray) {
213
+ [subcontractor application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:handler];
214
+ }
207
215
  }
208
216
  }
209
217
 
@@ -92,8 +92,12 @@ open class ExpoAppDelegate: UIResponder, UIApplicationDelegate {
92
92
  }
93
93
  }
94
94
 
95
- subs.forEach {
96
- $0.application?(application, handleEventsForBackgroundURLSession: identifier, completionHandler: handler)
95
+ if subs.isEmpty {
96
+ completionHandler()
97
+ } else {
98
+ subs.forEach {
99
+ $0.application?(application, handleEventsForBackgroundURLSession: identifier, completionHandler: handler)
100
+ }
97
101
  }
98
102
  }
99
103
 
@@ -115,27 +119,38 @@ open class ExpoAppDelegate: UIResponder, UIApplicationDelegate {
115
119
  let selector = #selector(application(_:didReceiveRemoteNotification:fetchCompletionHandler:))
116
120
  let subs = subscribers.filter { $0.responds(to: selector) }
117
121
  var subscribersLeft = subs.count
118
- var fetchResult: UIBackgroundFetchResult = .noData
119
122
  let dispatchQueue = DispatchQueue(label: "expo.application.remoteNotification", qos: .userInteractive)
123
+ var failedCount = 0
124
+ var newDataCount = 0
120
125
 
121
126
  let handler = { (result: UIBackgroundFetchResult) in
122
127
  dispatchQueue.sync {
123
128
  if result == .failed {
124
- fetchResult = .failed
125
- } else if fetchResult != .failed && result == .newData {
126
- fetchResult = .newData
129
+ failedCount += 1
130
+ } else if result == .newData {
131
+ newDataCount += 1
127
132
  }
128
133
 
129
134
  subscribersLeft -= 1
130
135
 
131
136
  if subscribersLeft == 0 {
132
- completionHandler(fetchResult)
137
+ if newDataCount > 0 {
138
+ completionHandler(.newData)
139
+ } else if failedCount > 0 {
140
+ completionHandler(.failed)
141
+ } else {
142
+ completionHandler(.noData)
143
+ }
133
144
  }
134
145
  }
135
146
  }
136
147
 
137
- subs.forEach { subscriber in
138
- subscriber.application?(application, didReceiveRemoteNotification: userInfo, fetchCompletionHandler: handler)
148
+ if subs.isEmpty {
149
+ completionHandler(.noData)
150
+ } else {
151
+ subs.forEach { subscriber in
152
+ subscriber.application?(application, didReceiveRemoteNotification: userInfo, fetchCompletionHandler: handler)
153
+ }
139
154
  }
140
155
  }
141
156
 
@@ -205,8 +220,12 @@ open class ExpoAppDelegate: UIResponder, UIApplicationDelegate {
205
220
  }
206
221
  }
207
222
 
208
- subs.forEach { subscriber in
209
- subscriber.application?(application, performActionFor: shortcutItem, completionHandler: handler)
223
+ if subs.isEmpty {
224
+ completionHandler(result)
225
+ } else {
226
+ subs.forEach { subscriber in
227
+ subscriber.application?(application, performActionFor: shortcutItem, completionHandler: handler)
228
+ }
210
229
  }
211
230
  }
212
231
 
@@ -216,27 +235,38 @@ open class ExpoAppDelegate: UIResponder, UIApplicationDelegate {
216
235
  let selector = #selector(application(_:performFetchWithCompletionHandler:))
217
236
  let subs = subscribers.filter { $0.responds(to: selector) }
218
237
  var subscribersLeft = subs.count
219
- var fetchResult: UIBackgroundFetchResult = .noData
220
238
  let dispatchQueue = DispatchQueue(label: "expo.application.performFetch", qos: .userInteractive)
239
+ var failedCount = 0
240
+ var newDataCount = 0
221
241
 
222
242
  let handler = { (result: UIBackgroundFetchResult) in
223
243
  dispatchQueue.sync {
224
244
  if result == .failed {
225
- fetchResult = .failed
226
- } else if fetchResult != .failed && result == .newData {
227
- fetchResult = .newData
245
+ failedCount += 1
246
+ } else if result == .newData {
247
+ newDataCount += 1
228
248
  }
229
249
 
230
250
  subscribersLeft -= 1
231
251
 
232
252
  if subscribersLeft == 0 {
233
- completionHandler(fetchResult)
253
+ if newDataCount > 0 {
254
+ completionHandler(.newData)
255
+ } else if failedCount > 0 {
256
+ completionHandler(.failed)
257
+ } else {
258
+ completionHandler(.noData)
259
+ }
234
260
  }
235
261
  }
236
262
  }
237
263
 
238
- subs.forEach { subscriber in
239
- subscriber.application?(application, performFetchWithCompletionHandler: handler)
264
+ if subs.isEmpty {
265
+ completionHandler(.noData)
266
+ } else {
267
+ subs.forEach { subscriber in
268
+ subscriber.application?(application, performFetchWithCompletionHandler: handler)
269
+ }
240
270
  }
241
271
  }
242
272
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-modules-core",
3
- "version": "0.11.5",
3
+ "version": "0.11.7",
4
4
  "description": "The core of Expo Modules architecture",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -42,5 +42,5 @@
42
42
  "@testing-library/react-hooks": "^7.0.1",
43
43
  "expo-module-scripts": "^2.0.0"
44
44
  },
45
- "gitHead": "9508df4babe9f5418a79c1fc1628c48936c206de"
45
+ "gitHead": "d94331a2fd0db76d4a8438ae7216b43082999bf1"
46
46
  }