expo-modules-core 1.5.7 → 1.6.0

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 (83) hide show
  1. package/CHANGELOG.md +24 -4
  2. package/android/CMakeLists.txt +1 -1
  3. package/android/build.gradle +10 -88
  4. package/android/src/main/cpp/JSIInteropModuleRegistry.cpp +14 -0
  5. package/android/src/main/cpp/JSIInteropModuleRegistry.h +7 -0
  6. package/android/src/main/cpp/JavaScriptRuntime.cpp +4 -1
  7. package/android/src/main/java/expo/modules/adapters/react/ModuleRegistryAdapter.java +25 -9
  8. package/android/src/main/java/expo/modules/core/interfaces/ReactActivityLifecycleListener.java +5 -0
  9. package/android/src/main/java/expo/modules/kotlin/AppContext.kt +38 -22
  10. package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +57 -49
  11. package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +30 -27
  12. package/android/src/main/java/expo/modules/kotlin/ModuleRegistry.kt +2 -1
  13. package/android/src/main/java/expo/modules/kotlin/defaultmodules/CoreModule.kt +11 -0
  14. package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +5 -0
  15. package/android/src/main/java/expo/modules/kotlin/exception/ExceptionDecorator.kt +1 -5
  16. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunction.kt +19 -6
  17. package/android/src/main/java/expo/modules/kotlin/functions/SuspendFunctionComponent.kt +19 -6
  18. package/android/src/main/java/expo/modules/kotlin/jni/JSIInteropModuleRegistry.kt +7 -1
  19. package/android/src/main/java/expo/modules/kotlin/jni/PromiseImpl.kt +34 -7
  20. package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +3 -2
  21. package/android/src/main/java/expo/modules/kotlin/tracing/ExpoTrace.kt +13 -0
  22. package/android/src/main/java/expo/modules/kotlin/views/ErrorView.kt +21 -0
  23. package/android/src/main/java/expo/modules/kotlin/views/ViewDefinitionBuilder.kt +2 -2
  24. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinition.kt +0 -28
  25. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerWrapperDelegate.kt +47 -8
  26. package/build/index.d.ts +1 -0
  27. package/build/index.d.ts.map +1 -1
  28. package/build/index.js +1 -0
  29. package/build/index.js.map +1 -1
  30. package/build/uuid/index.d.ts +3 -0
  31. package/build/uuid/index.d.ts.map +1 -0
  32. package/build/uuid/index.js +3 -0
  33. package/build/uuid/index.js.map +1 -0
  34. package/build/uuid/lib/bytesToUuid.d.ts +3 -0
  35. package/build/uuid/lib/bytesToUuid.d.ts.map +1 -0
  36. package/build/uuid/lib/bytesToUuid.js +37 -0
  37. package/build/uuid/lib/bytesToUuid.js.map +1 -0
  38. package/build/uuid/lib/rng.d.ts +3 -0
  39. package/build/uuid/lib/rng.d.ts.map +1 -0
  40. package/build/uuid/lib/rng.js +35 -0
  41. package/build/uuid/lib/rng.js.map +1 -0
  42. package/build/uuid/lib/sha1.d.ts +3 -0
  43. package/build/uuid/lib/sha1.d.ts.map +1 -0
  44. package/build/uuid/lib/sha1.js +98 -0
  45. package/build/uuid/lib/sha1.js.map +1 -0
  46. package/build/uuid/lib/v35.d.ts +7 -0
  47. package/build/uuid/lib/v35.d.ts.map +1 -0
  48. package/build/uuid/lib/v35.js +51 -0
  49. package/build/uuid/lib/v35.js.map +1 -0
  50. package/build/uuid/types/uuid.types.d.ts +11 -0
  51. package/build/uuid/types/uuid.types.d.ts.map +1 -0
  52. package/build/uuid/types/uuid.types.js +2 -0
  53. package/build/uuid/types/uuid.types.js.map +1 -0
  54. package/build/uuid/v4.d.ts +6 -0
  55. package/build/uuid/v4.d.ts.map +1 -0
  56. package/build/uuid/v4.js +29 -0
  57. package/build/uuid/v4.js.map +1 -0
  58. package/build/uuid/v5.d.ts +11 -0
  59. package/build/uuid/v5.d.ts.map +1 -0
  60. package/build/uuid/v5.js +7 -0
  61. package/build/uuid/v5.js.map +1 -0
  62. package/ios/AppDelegates/EXLegacyAppDelegateWrapper.m +1 -0
  63. package/ios/AppDelegates/ExpoAppDelegate.swift +43 -2
  64. package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.h +1 -1
  65. package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +1 -1
  66. package/ios/ModuleRegistryAdapter/EXModuleRegistryHolderReactModule.h +2 -2
  67. package/ios/ModuleRegistryAdapter/EXModuleRegistryHolderReactModule.m +4 -4
  68. package/ios/ModuleRegistryProvider/EXModuleRegistryProvider.h +2 -1
  69. package/ios/Services/EXReactFontManager.m +31 -7
  70. package/ios/Swift/AppContext.swift +6 -0
  71. package/ios/Swift/ExpoBridgeModule.swift +6 -2
  72. package/ios/Swift/ModuleRegistry.swift +14 -4
  73. package/package.json +2 -2
  74. package/src/index.ts +2 -0
  75. package/src/uuid/index.ts +2 -0
  76. package/src/uuid/lib/bytesToUuid.ts +38 -0
  77. package/src/uuid/lib/rng.ts +42 -0
  78. package/src/uuid/lib/sha1.ts +110 -0
  79. package/src/uuid/lib/v35.ts +67 -0
  80. package/src/uuid/types/uuid.types.ts +12 -0
  81. package/src/uuid/v4.ts +44 -0
  82. package/src/uuid/v5.ts +7 -0
  83. package/android/src/main/java/expo/modules/kotlin/views/ErrorViewGroup.kt +0 -11
package/CHANGELOG.md CHANGED
@@ -10,13 +10,33 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 1.6.0 — 2023-07-28
14
+
15
+ ### 🐛 Bug fixes
16
+
17
+ - [iOS] Fixed custom fonts support on Fabric. ([#23666](https://github.com/expo/expo/pull/23666) by [@aleqsio](https://github.com/aleqsio))
18
+ - [Android] Fixed splash screen is missing when using the `getDelayLoadAppHandler()` from expo-updates. ([#23747](https://github.com/expo/expo/pull/23747) by [@kudo](https://github.com/kudo))
19
+
20
+ ### 💡 Others
21
+
22
+ - Fork `uuid@3.4.0` and move into `expo-modules-core`. Remove the original dependency. ([#23249](https://github.com/expo/expo/pull/23249) by [@alanhughes](https://github.com/alanjhughes))
23
+ - Improved error handling when working with native promises on Android. ([#23571](https://github.com/expo/expo/pull/23571) by [@lukmccall](https://github.com/lukmccall))
24
+ - Added tracing to avoid slow app startup on Android. ([#23653](https://github.com/expo/expo/pull/23653) by [@lukmccall](https://github.com/lukmccall))
25
+
26
+ ## 1.5.8 - 2023-07-23
27
+
28
+ ### 🐛 Bug fixes
29
+
30
+ - Fixed the `ErrorViewGroup` cannot be cast to module view class exception on Android. ([#23651](https://github.com/expo/expo/pull/23651) by [@lukmccall](https://github.com/lukmccall))
31
+ - [iOS] Fix allowed orientations set in `Info.plist` being ignored when no delegates requested a different orientation. ([#23593](https://github.com/expo/expo/pull/23593) by [@behenate](https://github.com/behenate))
32
+
13
33
  ## 1.5.7 — 2023-07-12
14
34
 
15
35
  ### 🐛 Bug fixes
16
36
 
17
37
  - Fixed regressions and crashes in the dev client introduced by [#23405](https://github.com/expo/expo/pull/23405). ([#23491](https://github.com/expo/expo/pull/23491) by [@kudo](https://github.com/kudo))
18
38
 
19
- ## 1.5.6 2023-07-10
39
+ ## 1.5.6 - 2023-07-10
20
40
 
21
41
  ### 🐛 Bug fixes
22
42
 
@@ -24,14 +44,14 @@
24
44
  - Fixed `SoLoader` does not work on Android. ([#23415](https://github.com/expo/expo/pull/23415) by [@kudo](https://github.com/kudo))
25
45
  - Fixed slower boot time on Android. ([#23345](https://github.com/expo/expo/pull/23345) by [@lukmccall](https://github.com/lukmccall))
26
46
 
27
- ## 1.5.5 2023-07-07
47
+ ## 1.5.5 - 2023-07-07
28
48
 
29
49
  ### 🐛 Bug fixes
30
50
 
31
51
  - Improved the OkHttp network inspector stability on Android. ([#23350](https://github.com/expo/expo/pull/23350) by [@kudo](https://github.com/kudo))
32
- - [iOS] Fix conversion to `URL` type that failed despite receiving a string that contained a valid URL. ([#23331](https://github.com/expo/expo/pull/23331) by [@alanhughes](https://github.com/alanjhughes))
52
+ - [iOS] Fix conversion to `URL` type that failed despite receiving a string that contained a valid URL. ([#23331](https://github.com/expo/expo/pull/23331) by [@alanhughes](https://github.com/alanjhughes)) ([#23331](https://github.com/expo/expo/pull/23331) by [@alanjhughes](https://github.com/alanjhughes))
33
53
 
34
- ## 1.5.4 2023-07-04
54
+ ## 1.5.4 - 2023-07-04
35
55
 
36
56
  ### 🐛 Bug fixes
37
57
 
@@ -6,7 +6,7 @@ set(CMAKE_VERBOSE_MAKEFILE ON)
6
6
  set(CMAKE_CXX_STANDARD 17)
7
7
  set(PACKAGE_NAME "expo-modules-core")
8
8
  set(BUILD_DIR ${CMAKE_SOURCE_DIR}/build)
9
- set(ignoreMe "${PROJECT_BUILD_DIR} ${REACT_ANDROID_BUILD_DIR} ${REACT_ANDROID_DIR} ${HERMES_HEADER_DIR} ${BOOST_VERSION}")
9
+ set(ignoreMe "${PROJECT_BUILD_DIR} ${REACT_ANDROID_BUILD_DIR} ${REACT_ANDROID_DIR} ${BOOST_VERSION}")
10
10
 
11
11
  string(APPEND CMAKE_CXX_FLAGS " -DREACT_NATIVE_TARGET_VERSION=${REACT_NATIVE_TARGET_VERSION}")
12
12
 
@@ -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 = '1.5.7'
9
+ version = '1.6.0'
10
10
 
11
11
  buildscript {
12
12
  def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
@@ -76,20 +76,7 @@ def reactNativeArchitectures() {
76
76
  }
77
77
 
78
78
  // HERMES
79
- def prebuiltHermesDir = findProperty("expo.prebuiltHermesDir") ?: file("${rootDir}/prebuiltHermes")
80
- def prebuiltHermesVersion = file("${prebuiltHermesDir}/.hermesversion").exists() ? file("${prebuiltHermesDir}/.hermesversion").text : null
81
- def currentHermesVersion = file("${REACT_NATIVE_DIR}/sdks/.hermesversion").exists() ? file("${REACT_NATIVE_DIR}/sdks/.hermesversion").text : null
82
- def hasHermesProject = findProject(":packages:react-native:ReactAndroid:hermes-engine") != null
83
- def prebuiltHermesCacheHit = hasHermesProject && currentHermesVersion == prebuiltHermesVersion
84
-
85
- // By default we are going to download and unzip hermes inside the /sdks/hermes folder
86
- // but you can provide an override for where the hermes source code is located.
87
- def hermesDir = System.getenv("REACT_NATIVE_OVERRIDE_HERMES_DIR") ?: file("${REACT_NATIVE_DIR}/sdks/hermes")
88
-
89
79
  def USE_HERMES = true
90
- def NEED_DOWNLOAD_HERMES = false
91
- def HERMES_HEADER_DIR = null
92
- def HERMES_AAR = null
93
80
  if (findProject(":app")) {
94
81
  def appProject = project(":app")
95
82
  USE_HERMES = appProject?.hermesEnabled?.toBoolean() || appProject?.ext?.react?.enableHermes?.toBoolean()
@@ -97,25 +84,6 @@ if (findProject(":app")) {
97
84
 
98
85
  // Currently the needs for hermes/jsc are only for androidTest, so we turn on this flag only when `isExpoModulesCoreTests` is true
99
86
  USE_HERMES = USE_HERMES && isExpoModulesCoreTests
100
-
101
- if (USE_HERMES) {
102
- if (prebuiltHermesCacheHit) {
103
- HERMES_HEADER_DIR = file("${thirdPartyNdkDir}/hermes/prefab/modules/libhermes/include")
104
- HERMES_AAR = file("${prebuiltHermesDir}/hermes-engine-debug.aar")
105
- } else if (hasHermesProject) {
106
- HERMES_HEADER_DIR = file("${thirdPartyNdkDir}/hermes/prefab/modules/libhermes/include")
107
- HERMES_AAR = file("${REACT_NATIVE_DIR}/ReactAndroid/hermes-engine/build/outputs/aar/hermes-engine-debug.aar")
108
- } else {
109
- def prebuiltAAR = fileTree(REACT_NATIVE_DIR).matching { include "**/hermes-engine/**/hermes-engine-*-debug.aar" }
110
- if (prebuiltAAR.any()) {
111
- HERMES_AAR = prebuiltAAR.singleFile
112
- } else {
113
- HERMES_AAR = file("${hermesEngineDir}/android/hermes-debug.aar")
114
- }
115
- HERMES_HEADER_DIR = file("${hermesDir}")
116
- NEED_DOWNLOAD_HERMES = true
117
- }
118
- }
119
87
  // END HERMES
120
88
 
121
89
  def isNewArchitectureEnabled = findProperty("newArchEnabled") == "true"
@@ -160,7 +128,7 @@ android {
160
128
  targetSdkVersion safeExtGet("targetSdkVersion", 33)
161
129
  consumerProguardFiles 'proguard-rules.pro'
162
130
  versionCode 1
163
- versionName "1.5.7"
131
+ versionName "1.6.0"
164
132
  buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled.toString()
165
133
 
166
134
  testInstrumentationRunner "expo.modules.TestRunner"
@@ -174,7 +142,6 @@ android {
174
142
  "-DREACT_NATIVE_TARGET_VERSION=${REACT_NATIVE_TARGET_VERSION}",
175
143
  "-DBOOST_VERSION=${BOOST_VERSION}",
176
144
  "-DUSE_HERMES=${USE_HERMES}",
177
- "-DHERMES_HEADER_DIR=${HERMES_HEADER_DIR}",
178
145
  "-DIS_NEW_ARCHITECTURE_ENABLED=${isNewArchitectureEnabled}",
179
146
  "-DPROJECT_BUILD_DIR=$buildDir",
180
147
  "-DREACT_ANDROID_DIR=${REACT_NATIVE_DIR}/ReactAndroid",
@@ -279,6 +246,8 @@ dependencies {
279
246
  implementation "androidx.activity:activity-ktx:1.7.1" // androidx.appcompat:appcompat:1.4.1 depends on version 1.2.3, so we enforce higher one here
280
247
  implementation "androidx.fragment:fragment-ktx:1.5.7" // androidx.appcomapt:appcompat:1.4.1 depends on version 1.3.4, so we enforce higher one here
281
248
 
249
+ implementation("androidx.tracing:tracing-ktx:1.1.0")
250
+
282
251
  //noinspection GradleDynamicVersion
283
252
  implementation 'com.facebook.react:react-native:+'
284
253
 
@@ -299,11 +268,12 @@ dependencies {
299
268
  androidTestImplementation "com.google.truth:truth:1.1.2"
300
269
  androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.0"
301
270
 
302
- if (USE_HERMES) {
303
- def hermesProject = findProject(":packages:react-native:ReactAndroid:hermes-engine")
304
- compileOnly (hermesProject ?: files(HERMES_AAR))
305
- } else {
306
- compileOnly "org.webkit:android-jsc:+"
271
+ if (isExpoModulesCoreTests) {
272
+ if (USE_HERMES) {
273
+ compileOnly "com.facebook.react:hermes-android"
274
+ } else {
275
+ compileOnly "org.webkit:android-jsc:+"
276
+ }
307
277
  }
308
278
  }
309
279
 
@@ -322,48 +292,6 @@ def createNativeDepsDirectories = project.tasks.findByName('createNativeDepsDire
322
292
  thirdPartyNdkDir.mkdirs()
323
293
  }
324
294
 
325
- // TODO: Remove all these hermes code when we update our repo to react-native 0.71 by using prefab
326
- task downloadHermes(type: Download) {
327
- def hermesVersion = currentHermesVersion ?: "main"
328
- src("https://github.com/facebook/hermes/tarball/${hermesVersion}")
329
- onlyIfNewer(true)
330
- overwrite(false)
331
- dest(new File(downloadsDir, "hermes-${hermesVersion}.tar.gz"))
332
- }
333
-
334
- task unzipHermes(dependsOn: downloadHermes, type: Copy) {
335
- from(tarTree(downloadHermes.dest)) {
336
- eachFile { file ->
337
- // We flatten the unzip as the tarball contains a `facebook-hermes-<SHA>`
338
- // folder at the top level.
339
- if (file.relativePath.segments.size() > 1) {
340
- file.relativePath = new org.gradle.api.file.RelativePath(!file.isDirectory(), file.relativePath.segments.drop(1))
341
- }
342
- }
343
- }
344
- into(hermesDir)
345
- }
346
-
347
- task prepareHermes() {
348
- if (!USE_HERMES) {
349
- return
350
- }
351
- dependsOn(createNativeDepsDirectories)
352
- if (NEED_DOWNLOAD_HERMES) {
353
- dependsOn(unzipHermes)
354
- }
355
-
356
- doLast {
357
- def files = zipTree(HERMES_AAR).matching({ it.include "**/*.so", "prefab/modules/libhermes/include/**/*" })
358
-
359
- copy {
360
- from files
361
- from "$REACT_NATIVE_DIR/ReactAndroid/src/main/jni/first-party/hermes/Android.mk"
362
- into "$thirdPartyNdkDir/hermes"
363
- }
364
- }
365
- }
366
-
367
295
  def downloadBoost = tasks.create('downloadBoost', Download) {
368
296
  dependsOn(createNativeDepsDirectories)
369
297
  def srcUrl = REACT_NATIVE_TARGET_VERSION >= 69
@@ -406,12 +334,6 @@ afterEvaluate {
406
334
  if (REACT_NATIVE_TARGET_VERSION < 71) {
407
335
  nativeBuildDependsOn(project, prepareBoost, null)
408
336
  }
409
- if (USE_HERMES) {
410
- nativeBuildDependsOn(project, prepareHermes, null)
411
- if (hasHermesProject && !prebuiltHermesCacheHit) {
412
- prepareHermes.dependsOn(":packages:react-native:ReactAndroid:hermes-engine:assembleDebug")
413
- }
414
- }
415
337
  }
416
338
 
417
339
  if (REACT_NATIVE_TARGET_VERSION < 71) {
@@ -113,6 +113,16 @@ JSIInteropModuleRegistry::callGetJavaScriptModuleObjectMethod(const std::string
113
113
  return method(javaPart_, moduleName);
114
114
  }
115
115
 
116
+ jni::local_ref<JavaScriptModuleObject::javaobject>
117
+ JSIInteropModuleRegistry::callGetCoreModuleObject() const {
118
+ const static auto method = expo::JSIInteropModuleRegistry::javaClassLocal()
119
+ ->getMethod<jni::local_ref<JavaScriptModuleObject::javaobject>()>(
120
+ "getCoreModuleObject"
121
+ );
122
+
123
+ return method(javaPart_);
124
+ }
125
+
116
126
  jni::local_ref<jni::JArrayClass<jni::JString>>
117
127
  JSIInteropModuleRegistry::callGetJavaScriptModulesNames() const {
118
128
  const static auto method = expo::JSIInteropModuleRegistry::javaClassLocal()
@@ -135,6 +145,10 @@ JSIInteropModuleRegistry::getModule(const std::string &moduleName) const {
135
145
  return callGetJavaScriptModuleObjectMethod(moduleName);
136
146
  }
137
147
 
148
+ jni::local_ref<JavaScriptModuleObject::javaobject> JSIInteropModuleRegistry::getCoreModule() const {
149
+ return callGetCoreModuleObject();
150
+ }
151
+
138
152
  bool JSIInteropModuleRegistry::hasModule(const std::string &moduleName) const {
139
153
  return callHasModule(moduleName);
140
154
  }
@@ -82,6 +82,11 @@ public:
82
82
  */
83
83
  jni::local_ref<JavaScriptObject::javaobject> createObject();
84
84
 
85
+ /**
86
+ * Gets a core module.
87
+ */
88
+ jni::local_ref<JavaScriptModuleObject::javaobject> getCoreModule() const;
89
+
85
90
  /**
86
91
  * Adds a shared object to the internal registry
87
92
  * @param native part of the shared object
@@ -113,6 +118,8 @@ private:
113
118
 
114
119
  inline jni::local_ref<jni::JArrayClass<jni::JString>> callGetJavaScriptModulesNames() const;
115
120
 
121
+ inline jni::local_ref<JavaScriptModuleObject::javaobject> callGetCoreModuleObject() const;
122
+
116
123
  inline bool callHasModule(const std::string &moduleName) const;
117
124
  };
118
125
  } // namespace expo
@@ -162,7 +162,10 @@ void JavaScriptRuntime::drainJSEventLoop() {
162
162
  }
163
163
 
164
164
  void JavaScriptRuntime::installMainObject() {
165
- mainObject = std::make_shared<jsi::Object>(*runtime);
165
+ auto coreModule = jsiInteropModuleRegistry->getCoreModule();
166
+ coreModule->cthis()->jsiInteropModuleRegistry = jsiInteropModuleRegistry;
167
+ mainObject = coreModule->cthis()->getJSIObject(*runtime);
168
+
166
169
  auto global = runtime->global();
167
170
  auto objectClass = global.getPropertyAsObject(*runtime, "Object");
168
171
  jsi::Function definePropertyFunction = objectClass.getPropertyAsFunction(
@@ -10,12 +10,15 @@ import java.util.List;
10
10
  import java.util.Objects;
11
11
 
12
12
  import androidx.annotation.Nullable;
13
+
13
14
  import expo.modules.BuildConfig;
14
15
  import expo.modules.adapters.react.views.SimpleViewManagerAdapter;
15
16
  import expo.modules.adapters.react.views.ViewGroupManagerAdapter;
16
17
  import expo.modules.core.ModuleRegistry;
18
+ import expo.modules.core.interfaces.Consumer;
17
19
  import expo.modules.core.interfaces.InternalModule;
18
20
  import expo.modules.core.interfaces.Package;
21
+ import expo.modules.kotlin.AppContext;
19
22
  import expo.modules.kotlin.CoreLoggerKt;
20
23
  import expo.modules.kotlin.KotlinInteropModuleRegistry;
21
24
  import expo.modules.kotlin.ModulesProvider;
@@ -31,6 +34,14 @@ public class ModuleRegistryAdapter implements ReactPackage {
31
34
  protected ModulesProvider mModulesProvider;
32
35
  protected ReactAdapterPackage mReactAdapterPackage = new ReactAdapterPackage();
33
36
  private NativeModulesProxy mModulesProxy;
37
+
38
+ private void setModulesProxy(@Nullable NativeModulesProxy newProxy) {
39
+ mModulesProxy = newProxy;
40
+ if (mModulesProxy != null) {
41
+ mModulesProxy.getKotlinInteropModuleRegistry().setLegacyModulesProxy(mModulesProxy);
42
+ }
43
+ }
44
+
34
45
  // We need to save all view holders to update them when the new kotlin module registry will be created.
35
46
  private List<ViewWrapperDelegateHolder> mWrapperDelegateHolders = null;
36
47
  private FabricComponentsRegistry mFabricComponentsRegistry = null;
@@ -57,7 +68,7 @@ public class ModuleRegistryAdapter implements ReactPackage {
57
68
  moduleRegistry.registerInternalModule(internalModule);
58
69
  }
59
70
 
60
- List<NativeModule> nativeModules = getNativeModulesFromModuleRegistry(reactContext, moduleRegistry);
71
+ List<NativeModule> nativeModules = getNativeModulesFromModuleRegistry(reactContext, moduleRegistry, null);
61
72
  if (mWrapperDelegateHolders != null) {
62
73
  KotlinInteropModuleRegistry kotlinInteropModuleRegistry = proxy.getKotlinInteropModuleRegistry();
63
74
  kotlinInteropModuleRegistry.updateModuleHoldersInViewManagers(mWrapperDelegateHolders);
@@ -66,10 +77,17 @@ public class ModuleRegistryAdapter implements ReactPackage {
66
77
  return nativeModules;
67
78
  }
68
79
 
69
- protected List<NativeModule> getNativeModulesFromModuleRegistry(ReactApplicationContext reactContext, ModuleRegistry moduleRegistry) {
80
+ protected List<NativeModule> getNativeModulesFromModuleRegistry(
81
+ ReactApplicationContext reactContext,
82
+ ModuleRegistry moduleRegistry,
83
+ @Nullable Consumer<AppContext> appContextConsumer
84
+ ) {
70
85
  List<NativeModule> nativeModulesList = new ArrayList<>(2);
71
-
72
- nativeModulesList.add(getOrCreateNativeModulesProxy(reactContext, moduleRegistry));
86
+ NativeModulesProxy nativeModulesProxy = getOrCreateNativeModulesProxy(reactContext, moduleRegistry);
87
+ if (appContextConsumer != null) {
88
+ appContextConsumer.apply(nativeModulesProxy.getKotlinInteropModuleRegistry().getAppContext());
89
+ }
90
+ nativeModulesList.add(nativeModulesProxy);
73
91
 
74
92
  // Add listener that will notify expo.modules.core.ModuleRegistry when all modules are ready
75
93
  nativeModulesList.add(new ModuleRegistryReadyNotifier(moduleRegistry));
@@ -117,17 +135,15 @@ public class ModuleRegistryAdapter implements ReactPackage {
117
135
  @Nullable ModuleRegistry moduleRegistry
118
136
  ) {
119
137
  if (mModulesProxy != null && mModulesProxy.getReactContext() != reactContext) {
120
- mModulesProxy = null;
138
+ setModulesProxy(mModulesProxy);
121
139
  }
122
140
  if (mModulesProxy == null) {
123
141
  ModuleRegistry registry = moduleRegistry != null ? moduleRegistry : mModuleRegistryProvider.get(reactContext);
124
142
  if (mModulesProvider != null) {
125
- mModulesProxy = new NativeModulesProxy(reactContext, registry, mModulesProvider);
143
+ setModulesProxy(new NativeModulesProxy(reactContext, registry, mModulesProvider));
126
144
  } else {
127
- mModulesProxy = new NativeModulesProxy(reactContext, registry);
145
+ setModulesProxy(new NativeModulesProxy(reactContext, registry));
128
146
  }
129
-
130
- mModulesProxy.getKotlinInteropModuleRegistry().setLegacyModulesProxy(mModulesProxy);
131
147
  }
132
148
 
133
149
  if (moduleRegistry != null && moduleRegistry != mModulesProxy.getModuleRegistry()) {
@@ -34,4 +34,9 @@ public interface ReactActivityLifecycleListener {
34
34
  default boolean onBackPressed() {
35
35
  return false;
36
36
  }
37
+
38
+ /**
39
+ * This method is called when the {@link Activity#setContentView} method is invoked on an Activity.
40
+ */
41
+ default void onContentChanged(Activity activity) {}
37
42
  }
@@ -28,6 +28,7 @@ import expo.modules.interfaces.sensors.SensorServiceInterface
28
28
  import expo.modules.interfaces.taskManager.TaskManagerInterface
29
29
  import expo.modules.kotlin.activityresult.ActivityResultsManager
30
30
  import expo.modules.kotlin.activityresult.DefaultAppContextActivityResultCaller
31
+ import expo.modules.kotlin.defaultmodules.CoreModule
31
32
  import expo.modules.kotlin.defaultmodules.ErrorManagerModule
32
33
  import expo.modules.kotlin.defaultmodules.NativeModulesProxyModule
33
34
  import expo.modules.kotlin.events.EventEmitter
@@ -40,6 +41,7 @@ import expo.modules.kotlin.jni.JSIInteropModuleRegistry
40
41
  import expo.modules.kotlin.modules.Module
41
42
  import expo.modules.kotlin.providers.CurrentActivityProvider
42
43
  import expo.modules.kotlin.sharedobjects.SharedObjectRegistry
44
+ import expo.modules.kotlin.tracing.trace
43
45
  import kotlinx.coroutines.CoroutineName
44
46
  import kotlinx.coroutines.CoroutineScope
45
47
  import kotlinx.coroutines.Dispatchers
@@ -58,7 +60,18 @@ class AppContext(
58
60
  private val reactLifecycleDelegate = ReactLifecycleDelegate(this)
59
61
 
60
62
  // We postpone creating the `JSIInteropModuleRegistry` to not load so files in unit tests.
61
- private lateinit var jsiInterop: JSIInteropModuleRegistry
63
+ internal lateinit var jsiInterop: JSIInteropModuleRegistry
64
+
65
+ /**
66
+ * The core module that defines the `expo` object in the global scope of the JS runtime.
67
+ *
68
+ * Note: in current implementation this module won't receive any events.
69
+ */
70
+ internal val coreModule = run {
71
+ val module = CoreModule()
72
+ module._appContext = this
73
+ ModuleHolder(module)
74
+ }
62
75
 
63
76
  internal val sharedObjectRegistry = SharedObjectRegistry()
64
77
 
@@ -120,26 +133,28 @@ class AppContext(
120
133
  * Initializes a JSI part of the module registry.
121
134
  * It will be a NOOP if the remote debugging was activated.
122
135
  */
123
- fun installJSIInterop() = synchronized<Unit>(this) {
124
- try {
125
- jsiInterop = JSIInteropModuleRegistry(this)
126
- val reactContext = reactContextHolder.get() ?: return
127
- val jsContextProvider = legacyModule<JavaScriptContextProvider>() ?: return
128
- val jsContextHolder = jsContextProvider.javaScriptContextRef
129
- val catalystInstance = reactContext.catalystInstance ?: return
130
- jsContextHolder
131
- .takeIf { it != 0L }
132
- ?.let {
133
- jsiInterop.installJSI(
134
- it,
135
- jniDeallocator,
136
- jsContextProvider.jsCallInvokerHolder,
137
- catalystInstance.nativeCallInvokerHolder as CallInvokerHolderImpl
138
- )
139
- logger.info("✅ JSI interop was installed")
140
- }
141
- } catch (e: Throwable) {
142
- logger.error("❌ Cannot install JSI interop: $e", e)
136
+ fun installJSIInterop() = synchronized(this) {
137
+ trace("AppContext.installJSIInterop") {
138
+ try {
139
+ jsiInterop = JSIInteropModuleRegistry(this)
140
+ val reactContext = reactContextHolder.get() ?: return@trace
141
+ val jsContextProvider = legacyModule<JavaScriptContextProvider>() ?: return@trace
142
+ val jsContextHolder = jsContextProvider.javaScriptContextRef
143
+ val catalystInstance = reactContext.catalystInstance ?: return@trace
144
+ jsContextHolder
145
+ .takeIf { it != 0L }
146
+ ?.let {
147
+ jsiInterop.installJSI(
148
+ it,
149
+ jniDeallocator,
150
+ jsContextProvider.jsCallInvokerHolder,
151
+ catalystInstance.nativeCallInvokerHolder as CallInvokerHolderImpl
152
+ )
153
+ logger.info("✅ JSI interop was installed")
154
+ }
155
+ } catch (e: Throwable) {
156
+ logger.error("❌ Cannot install JSI interop: $e", e)
157
+ }
143
158
  }
144
159
  }
145
160
 
@@ -271,10 +286,11 @@ class AppContext(
271
286
  internal val errorManager: ErrorManagerModule?
272
287
  get() = registry.getModule()
273
288
 
274
- internal fun onDestroy() {
289
+ internal fun onDestroy() = trace("AppContext.onDestroy") {
275
290
  reactContextHolder.get()?.removeLifecycleEventListener(reactLifecycleDelegate)
276
291
  registry.post(EventName.MODULE_DESTROY)
277
292
  registry.cleanUp()
293
+ coreModule.module._appContext = null
278
294
  modulesQueue.cancel(ContextDestroyedException())
279
295
  mainQueue.cancel(ContextDestroyedException())
280
296
  backgroundCoroutineScope.cancel(ContextDestroyedException())
@@ -7,6 +7,7 @@ import expo.modules.adapters.react.NativeModulesProxy
7
7
  import expo.modules.kotlin.defaultmodules.NativeModulesProxyModuleName
8
8
  import expo.modules.kotlin.exception.CodedException
9
9
  import expo.modules.kotlin.exception.UnexpectedException
10
+ import expo.modules.kotlin.tracing.trace
10
11
  import expo.modules.kotlin.views.GroupViewManagerWrapper
11
12
  import expo.modules.kotlin.views.SimpleViewManagerWrapper
12
13
  import expo.modules.kotlin.views.ViewManagerWrapperDelegate
@@ -42,55 +43,61 @@ class KotlinInteropModuleRegistry(
42
43
  }
43
44
  }
44
45
 
45
- fun exportedModulesConstants(): Map<ModuleName, ModuleConstants> {
46
- return registry
47
- // prevent infinite recursion - exclude NativeProxyModule constants
48
- .filter { holder -> holder.name != NativeModulesProxyModuleName }
49
- .associate { holder ->
50
- holder.name to holder.definition.constantsProvider()
46
+ fun exportedModulesConstants(): Map<ModuleName, ModuleConstants> =
47
+ trace("KotlinInteropModuleRegistry.exportedModulesConstants") {
48
+ registry
49
+ // prevent infinite recursion - exclude NativeProxyModule constants
50
+ .filter { holder -> holder.name != NativeModulesProxyModuleName }
51
+ .associate { holder ->
52
+ holder.name to holder.definition.constantsProvider()
53
+ }
54
+ }
55
+
56
+ fun exportMethods(exportKey: (String, List<ModuleMethodInfo>) -> Unit = { _, _ -> }): Map<ModuleName, List<ModuleMethodInfo>> =
57
+ trace("KotlinInteropModuleRegistry.exportMethods") {
58
+ registry.associate { holder ->
59
+ val methodsInfo = holder
60
+ .definition
61
+ .asyncFunctions
62
+ .map { (name, method) ->
63
+ mapOf(
64
+ "name" to name,
65
+ "argumentsCount" to method.argsCount
66
+ )
67
+ }
68
+ exportKey(holder.name, methodsInfo)
69
+ holder.name to methodsInfo
51
70
  }
52
- }
71
+ }
53
72
 
54
- fun exportMethods(exportKey: (String, List<ModuleMethodInfo>) -> Unit = { _, _ -> }): Map<ModuleName, List<ModuleMethodInfo>> {
55
- return registry.associate { holder ->
56
- val methodsInfo = holder
57
- .definition
58
- .asyncFunctions
59
- .map { (name, method) ->
60
- mapOf(
61
- "name" to name,
62
- "argumentsCount" to method.argsCount
63
- )
73
+ fun exportViewManagers(): List<ViewManager<*, *>> =
74
+ trace("KotlinInteropModuleRegistry.exportViewManagers") {
75
+ registry
76
+ .filter { it.definition.viewManagerDefinition != null }
77
+ .map {
78
+ val wrapperDelegate = ViewManagerWrapperDelegate(it)
79
+ when (it.definition.viewManagerDefinition!!.getViewManagerType()) {
80
+ expo.modules.core.ViewManager.ViewManagerType.SIMPLE -> SimpleViewManagerWrapper(wrapperDelegate)
81
+ expo.modules.core.ViewManager.ViewManagerType.GROUP -> GroupViewManagerWrapper(wrapperDelegate)
82
+ }
64
83
  }
65
- exportKey(holder.name, methodsInfo)
66
- holder.name to methodsInfo
67
84
  }
68
- }
69
85
 
70
- fun exportViewManagers(): List<ViewManager<*, *>> {
71
- return registry
72
- .filter { it.definition.viewManagerDefinition != null }
73
- .map {
74
- val wrapperDelegate = ViewManagerWrapperDelegate(it)
75
- when (it.definition.viewManagerDefinition!!.getViewManagerType()) {
76
- expo.modules.core.ViewManager.ViewManagerType.SIMPLE -> SimpleViewManagerWrapper(wrapperDelegate)
77
- expo.modules.core.ViewManager.ViewManagerType.GROUP -> GroupViewManagerWrapper(wrapperDelegate)
86
+ fun viewManagersMetadata(): Map<String, Map<String, Any>> =
87
+ trace("KotlinInteropModuleRegistry.viewManagersMetadata") {
88
+ registry
89
+ .filter { it.definition.viewManagerDefinition != null }
90
+ .associate { holder ->
91
+ holder.name to mapOf(
92
+ "propsNames" to (holder.definition.viewManagerDefinition?.propsNames ?: emptyList())
93
+ )
78
94
  }
79
- }
80
- }
81
-
82
- fun viewManagersMetadata(): Map<String, Map<String, Any>> {
83
- return registry
84
- .filter { it.definition.viewManagerDefinition != null }
85
- .associate { holder ->
86
- holder.name to mapOf(
87
- "propsNames" to (holder.definition.viewManagerDefinition?.propsNames ?: emptyList())
88
- )
89
- }
90
- }
95
+ }
91
96
 
92
97
  fun extractViewManagersDelegateHolders(viewManagers: List<ViewManager<*, *>>): List<ViewWrapperDelegateHolder> =
93
- viewManagers.filterIsInstance<ViewWrapperDelegateHolder>()
98
+ trace("KotlinInteropModuleRegistry.extractViewManagersDelegateHolders") {
99
+ viewManagers.filterIsInstance<ViewWrapperDelegateHolder>()
100
+ }
94
101
 
95
102
  /**
96
103
  * Since React Native v0.55, {@link com.facebook.react.ReactPackage#createViewManagers(ReactApplicationContext)}
@@ -100,15 +107,16 @@ class KotlinInteropModuleRegistry(
100
107
  * the instance that was bound with the prop method won't be the same as the instance returned by module registry.
101
108
  * To fix that we need to update all modules holder in exported view managers.
102
109
  */
103
- fun updateModuleHoldersInViewManagers(viewWrapperHolders: List<ViewWrapperDelegateHolder>) {
104
- viewWrapperHolders
105
- .map { it.viewWrapperDelegate }
106
- .forEach { holderWrapper ->
107
- holderWrapper.moduleHolder = requireNotNull(registry.getModuleHolder(holderWrapper.moduleHolder.name)) {
108
- "Cannot update the module holder for ${holderWrapper.moduleHolder.name}."
110
+ fun updateModuleHoldersInViewManagers(viewWrapperHolders: List<ViewWrapperDelegateHolder>) =
111
+ trace("KotlinInteropModuleRegistry.updateModuleHoldersInViewManagers") {
112
+ viewWrapperHolders
113
+ .map { it.viewWrapperDelegate }
114
+ .forEach { holderWrapper ->
115
+ holderWrapper.moduleHolder = requireNotNull(registry.getModuleHolder(holderWrapper.moduleHolder.name)) {
116
+ "Cannot update the module holder for ${holderWrapper.moduleHolder.name}."
117
+ }
109
118
  }
110
- }
111
- }
119
+ }
112
120
 
113
121
  fun onDestroy() {
114
122
  appContext.onDestroy()