expo-modules-core 0.11.6 → 0.11.8

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,21 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 0.11.8 — 2022-10-13
14
+
15
+ ### 🐛 Bug fixes
16
+
17
+ - Fixed `Updates.reloadAsync` from `expo-updates` occasionally crashes the app. ([#19539](https://github.com/expo/expo/pull/19539) by [@kudo](https://github.com/kudo), [@kudo](https://github.com/kudo))
18
+ - Fixed `JSCRuntime destroyed with a dangling API object` on Android. ([#19487](https://github.com/expo/expo/pull/19487) by [@lukmccall](https://github.com/lukmccall))
19
+
20
+ ## 0.11.7 — 2022-10-06
21
+
22
+ ### 🐛 Bug fixes
23
+
24
+ - 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))
25
+ - Ensure that AppDelegate callbacks are invoked. ([#19393](https://github.com/expo/expo/pull/19393) by [@ferologics](https://github.com/ferologics))
26
+ - 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))
27
+
13
28
  ## 0.11.6 — 2022-10-02
14
29
 
15
30
  ### 🐛 Bug fixes
@@ -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.6'
9
+ version = '0.11.8'
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.6"
164
+ versionName "0.11.8"
165
165
 
166
166
  testInstrumentationRunner "expo.modules.TestRunner"
167
167
 
@@ -12,6 +12,13 @@ namespace expo {
12
12
  ExpoModulesHostObject::ExpoModulesHostObject(JSIInteropModuleRegistry *installer)
13
13
  : installer(installer) {}
14
14
 
15
+ /**
16
+ * Clears jsi references held by JSRegistry and JavaScriptRuntime.
17
+ */
18
+ ExpoModulesHostObject::~ExpoModulesHostObject() {
19
+ installer->runtimeHolder.reset();
20
+ }
21
+
15
22
  jsi::Value ExpoModulesHostObject::get(jsi::Runtime &runtime, const jsi::PropNameID &name) {
16
23
  auto cName = name.utf8(runtime);
17
24
  auto module = installer->getModule(cName);
@@ -20,6 +20,8 @@ class ExpoModulesHostObject : public jsi::HostObject {
20
20
  public:
21
21
  ExpoModulesHostObject(JSIInteropModuleRegistry *installer);
22
22
 
23
+ ~ExpoModulesHostObject() override;
24
+
23
25
  jsi::Value get(jsi::Runtime &, const jsi::PropNameID &name) override;
24
26
 
25
27
  void set(jsi::Runtime &, const jsi::PropNameID &name, const jsi::Value &value) override;
@@ -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();
@@ -137,6 +137,18 @@ void JavaScriptModuleObject::registerProperty(
137
137
  JavaScriptModuleObject::HostObject::HostObject(
138
138
  JavaScriptModuleObject *jsModule) : jsModule(jsModule) {}
139
139
 
140
+ /**
141
+ * Clears all the JSI references held by the `JavaScriptModuleObject`.
142
+ */
143
+ JavaScriptModuleObject::HostObject::~HostObject() {
144
+ if (jsModule->jsiObject != nullptr) {
145
+ jsModule->jsiObject.reset();
146
+ }
147
+ jsModule->methodsMetadata.clear();
148
+ jsModule->constants.clear();
149
+ jsModule->properties.clear();
150
+ }
151
+
140
152
  jsi::Value JavaScriptModuleObject::HostObject::get(jsi::Runtime &runtime,
141
153
  const jsi::PropNameID &name) {
142
154
  auto cName = name.utf8(runtime);
@@ -103,6 +103,8 @@ public:
103
103
  public:
104
104
  HostObject(JavaScriptModuleObject *);
105
105
 
106
+ ~HostObject() override;
107
+
106
108
  jsi::Value get(jsi::Runtime &, const jsi::PropNameID &name) override;
107
109
 
108
110
  void set(jsi::Runtime &, const jsi::PropNameID &name, const jsi::Value &value) override;
@@ -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,27 @@ 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.getReactContext() != reactContext) {
115
+ mModulesProxy = null;
116
+ mWrapperDelegateHolders = null;
117
+ }
107
118
  if (mModulesProxy == null) {
108
- ModuleRegistry moduleRegistry = mModuleRegistryProvider.get(reactContext);
119
+ ModuleRegistry registry = moduleRegistry != null ? moduleRegistry : mModuleRegistryProvider.get(reactContext);
109
120
  if (mModulesProvider != null) {
110
- mModulesProxy = new NativeModulesProxy(reactContext, moduleRegistry, mModulesProvider);
121
+ mModulesProxy = new NativeModulesProxy(reactContext, registry, mModulesProvider);
111
122
  } else {
112
- mModulesProxy = new NativeModulesProxy(reactContext, moduleRegistry);
123
+ mModulesProxy = new NativeModulesProxy(reactContext, registry);
113
124
  }
114
125
  }
126
+
127
+ if (moduleRegistry != null && moduleRegistry != mModulesProxy.getModuleRegistry()) {
128
+ Log.e("expo-modules-core", "NativeModuleProxy was configured with a different instance of the modules registry.");
129
+ }
130
+
115
131
  return mModulesProxy;
116
132
  }
117
133
  }
@@ -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,12 @@ public class NativeModulesProxy extends ReactContextBaseJavaModule {
247
251
  mModuleRegistry.onDestroy();
248
252
  mKotlinInteropModuleRegistry.onDestroy();
249
253
  }
254
+
255
+ ModuleRegistry getModuleRegistry() {
256
+ return mModuleRegistry;
257
+ }
258
+
259
+ /* package */ ReactApplicationContext getReactContext() {
260
+ return getReactApplicationContext();
261
+ }
250
262
  }
@@ -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
 
@@ -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
 
@@ -141,8 +145,12 @@ open class ExpoAppDelegate: UIResponder, UIApplicationDelegate {
141
145
  }
142
146
  }
143
147
 
144
- subs.forEach { subscriber in
145
- 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
+ }
146
154
  }
147
155
  }
148
156
 
@@ -212,8 +220,12 @@ open class ExpoAppDelegate: UIResponder, UIApplicationDelegate {
212
220
  }
213
221
  }
214
222
 
215
- subs.forEach { subscriber in
216
- 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
+ }
217
229
  }
218
230
  }
219
231
 
@@ -249,8 +261,12 @@ open class ExpoAppDelegate: UIResponder, UIApplicationDelegate {
249
261
  }
250
262
  }
251
263
 
252
- subs.forEach { subscriber in
253
- 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
+ }
254
270
  }
255
271
  }
256
272
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-modules-core",
3
- "version": "0.11.6",
3
+ "version": "0.11.8",
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": "f6501b4322caa94f2250d2d7953243404fe3020d"
45
+ "gitHead": "da2b9d2bb73100781b31906967669fe521d55e8a"
46
46
  }