expo-modules-core 1.3.2 → 1.5.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 (66) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/ExpoModulesCore.podspec +26 -5
  3. package/android/CMakeLists.txt +2 -1
  4. package/android/ExpoModulesCorePlugin.gradle +4 -0
  5. package/android/build.gradle +24 -31
  6. package/android/src/main/AndroidManifest.xml +1 -2
  7. package/android/src/main/cpp/ExpoModulesHostObject.cpp +3 -0
  8. package/android/src/main/cpp/JNIDeallocator.cpp +17 -0
  9. package/android/src/main/cpp/JNIDeallocator.h +25 -0
  10. package/android/src/main/cpp/JSIInteropModuleRegistry.cpp +8 -1
  11. package/android/src/main/cpp/JSIInteropModuleRegistry.h +6 -1
  12. package/android/src/main/cpp/JavaCallback.cpp +9 -0
  13. package/android/src/main/cpp/JavaCallback.h +12 -2
  14. package/android/src/main/cpp/JavaScriptFunction.cpp +13 -0
  15. package/android/src/main/cpp/JavaScriptFunction.h +7 -1
  16. package/android/src/main/cpp/JavaScriptModuleObject.cpp +2 -1
  17. package/android/src/main/cpp/JavaScriptObject.cpp +17 -2
  18. package/android/src/main/cpp/JavaScriptObject.h +10 -3
  19. package/android/src/main/cpp/JavaScriptRuntime.cpp +5 -4
  20. package/android/src/main/cpp/JavaScriptRuntime.h +5 -3
  21. package/android/src/main/cpp/JavaScriptTypedArray.cpp +14 -0
  22. package/android/src/main/cpp/JavaScriptTypedArray.h +6 -0
  23. package/android/src/main/cpp/JavaScriptValue.cpp +32 -4
  24. package/android/src/main/cpp/JavaScriptValue.h +10 -3
  25. package/android/src/main/cpp/MethodMetadata.cpp +1 -1
  26. package/android/src/main/cpp/types/FrontendConverter.cpp +8 -4
  27. package/android/src/main/java/expo/modules/core/interfaces/ReactActivityHandler.java +14 -0
  28. package/android/src/main/java/expo/modules/kotlin/AppContext.kt +4 -1
  29. package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +7 -3
  30. package/android/src/main/java/expo/modules/kotlin/ModuleRegistry.kt +19 -12
  31. package/android/src/main/java/expo/modules/kotlin/devtools/ExpoNetworkInspectOkHttpInterceptors.kt +70 -0
  32. package/android/src/main/java/expo/modules/kotlin/devtools/ExpoRequestCdpInterceptor.kt +72 -0
  33. package/android/src/main/java/expo/modules/kotlin/devtools/OkHttpHeadersExtension.kt +18 -0
  34. package/android/src/main/java/expo/modules/kotlin/devtools/cdp/CdpNetworkTypes.kt +257 -0
  35. package/android/src/main/java/expo/modules/kotlin/jni/JNIDeallocator.kt +24 -15
  36. package/android/src/main/java/expo/modules/kotlin/jni/JSIInteropModuleRegistry.kt +8 -1
  37. package/android/src/main/java/expo/modules/kotlin/jni/JavaCallback.kt +0 -4
  38. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptFunction.kt +0 -4
  39. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptModuleObject.kt +5 -2
  40. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptObject.kt +0 -5
  41. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptValue.kt +0 -4
  42. package/android/src/main/java/expo/modules/kotlin/objects/ObjectDefinitionBuilder.kt +1 -1
  43. package/android/src/main/java/expo/modules/kotlin/types/ColorTypeConverter.kt +3 -0
  44. package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +1 -2
  45. package/android-annotation/build.gradle +2 -2
  46. package/android-annotation-processor/build.gradle +2 -2
  47. package/ios/AppDelegates/ExpoAppDelegate.swift +8 -1
  48. package/ios/JSI/EXJSIInstaller.h +2 -2
  49. package/ios/JSI/EXJSIInstaller.mm +6 -6
  50. package/ios/JSI/EXJavaScriptRuntime.h +0 -6
  51. package/ios/JSI/EXJavaScriptRuntime.mm +0 -23
  52. package/ios/RCTComponentData+Privates.h +17 -0
  53. package/ios/RCTComponentData+Privates.m +15 -0
  54. package/ios/Swift/AppContext.swift +20 -11
  55. package/ios/Swift/DevTools/CdpNetworkTypes.swift +163 -0
  56. package/ios/Swift/DevTools/ExpoRequestCdpInterceptor.swift +71 -0
  57. package/ios/Swift/DevTools/ExpoRequestInterceptorProtocol.swift +183 -0
  58. package/ios/Swift/DevTools/URLRequest+httpBodyData.swift +43 -0
  59. package/ios/Swift/ExpoRuntime.swift +28 -0
  60. package/ios/Swift/Modules/CoreModule.swift +7 -0
  61. package/ios/Swift/SharedObjects/SharedRef.swift +12 -0
  62. package/ios/Swift/Views/ComponentData.swift +1 -1
  63. package/ios/Tests/CoreModuleSpec.swift +27 -0
  64. package/ios/Tests/ExpoRequestCdpInterceptorSpec.swift +165 -0
  65. package/ios/Tests/SharedRefSpec.swift +60 -0
  66. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -10,6 +10,35 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 1.5.0 — 2023-06-21
14
+
15
+ ### 💡 Others
16
+
17
+ - [iOS] Added Interface Geometry Management section to ExpoAppDelegate. ([#22599](https://github.com/expo/expo/pull/22599) by [@behenate](https://github.com/behenate))
18
+
19
+ ## 1.4.0 — 2023-06-13
20
+
21
+ ### 📚 3rd party library updates
22
+
23
+ - Updated `robolectric` to `4.10` and `junit` to `4.13.2`. ([#22395](https://github.com/expo/expo/pull/22395) by [@josephyanks](https://github.com/josephyanks))
24
+
25
+ ### 🎉 New features
26
+
27
+ - Added `ReactActivityHandler.getDelayLoadAppHandler` interface on Android. ([#20273](https://github.com/expo/expo/pull/20273) by [@kudo](https://github.com/kudo))
28
+ - [iOS] Introduced shared refs – a way to pass native objects among different independent modules. ([#22583](https://github.com/expo/expo/pull/22583) by [@tsapeta](https://github.com/tsapeta))
29
+ - Added support for React Native 0.72. ([#22588](https://github.com/expo/expo/pull/22588) by [@kudo](https://github.com/kudo))
30
+
31
+ ### 🐛 Bug fixes
32
+
33
+ - Fix failing instrumentation tests in JavaScriptViewModule. ([#22518](https://github.com/expo/expo/pull/22518) by [@aleqsio](https://github.com/aleqsio))
34
+ - Fixed Android build warnings for Gradle version 8. ([#22537](https://github.com/expo/expo/pull/22537), [#22609](https://github.com/expo/expo/pull/22609) by [@kudo](https://github.com/kudo))
35
+ - [Android] Fix the `Color` converter doesn't work on devices with SDK version below 26. ([#22191](https://github.com/expo/expo/pull/22191) by [@lukmccall](https://github.com/lukmccall))
36
+ - Refactored network inspector code and add unit tests. ([#22669](https://github.com/expo/expo/pull/22669), [#22693](https://github.com/expo/expo/pull/22693) by [@kudo](https://github.com/kudo))
37
+
38
+ ### 💡 Others
39
+
40
+ - Updated `androidx.activity:activity-ktx` to `1.7.1` and `androidx.fragment:fragment-ktx` to `1.5.7` [#22658](https://github.com/expo/expo/pull/22658) by [@fobos531](https://github.com/fobos531)
41
+
13
42
  ## 1.3.2 — 2023-05-09
14
43
 
15
44
  ### 🐛 Bug fixes
@@ -12,7 +12,7 @@ if ENV["REACT_NATIVE_OVERRIDE_VERSION"]
12
12
  reactNativeVersion = ENV["REACT_NATIVE_OVERRIDE_VERSION"]
13
13
  end
14
14
 
15
- REACT_NATIVE_MINOR_VERSION = reactNativeVersion.split('.')[1].to_i
15
+ reactNativeMinorVersion = reactNativeVersion.split('.')[1].to_i
16
16
 
17
17
  fabric_enabled = ENV['RCT_NEW_ARCH_ENABLED'] == '1'
18
18
  fabric_compiler_flags = '-DRN_FABRIC_ENABLED -DRCT_NEW_ARCH_ENABLED'
@@ -59,16 +59,30 @@ Pod::Spec.new do |s|
59
59
  "FRAMEWORK_SEARCH_PATHS" => "\"${PODS_CONFIGURATION_BUILD_DIR}/React-hermes\"",
60
60
  'OTHER_SWIFT_FLAGS' => "$(inherited) #{fabric_enabled ? fabric_compiler_flags : ''}"
61
61
  }
62
+ user_header_search_paths = [
63
+ '"${PODS_CONFIGURATION_BUILD_DIR}/ExpoModulesCore/Swift Compatibility Header"',
64
+ '"$(PODS_ROOT)/Headers/Private/React-bridging/react/bridging"',
65
+ '"$(PODS_CONFIGURATION_BUILD_DIR)/React-bridging/react_bridging.framework/Headers"',
66
+ ]
67
+ if fabric_enabled && ENV['USE_FRAMEWORKS']
68
+ user_header_search_paths << "\"$(PODS_ROOT)/DoubleConversion\""
69
+ user_header_search_paths << "\"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers\""
70
+ user_header_search_paths << "\"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios\""
71
+ user_header_search_paths << "\"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers\""
72
+ user_header_search_paths << "\"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers\""
73
+ user_header_search_paths << "\"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core\""
74
+ user_header_search_paths << "\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTFabric/RCTFabric.framework/Headers\""
75
+ end
62
76
  s.user_target_xcconfig = {
63
- "HEADER_SEARCH_PATHS" => "\"${PODS_CONFIGURATION_BUILD_DIR}/ExpoModulesCore/Swift Compatibility Header\" \"$(PODS_ROOT)/Headers/Private/React-bridging/react/bridging\" \"$(PODS_CONFIGURATION_BUILD_DIR)/React-bridging/react_bridging.framework/Headers\"",
77
+ "HEADER_SEARCH_PATHS" => user_header_search_paths,
64
78
  }
65
79
 
66
- compiler_flags = folly_compiler_flags + ' ' + "-DREACT_NATIVE_MINOR_VERSION=#{REACT_NATIVE_MINOR_VERSION}"
80
+ compiler_flags = folly_compiler_flags + ' ' + "-DREACT_NATIVE_MINOR_VERSION=#{reactNativeMinorVersion}"
67
81
 
68
82
  s.dependency 'React-Core'
69
83
  s.dependency 'ReactCommon/turbomodule/core'
70
- s.dependency 'React-RCTAppDelegate' if REACT_NATIVE_MINOR_VERSION >= 71
71
- s.dependency 'React-NativeModulesApple' if REACT_NATIVE_MINOR_VERSION >= 72
84
+ s.dependency 'React-RCTAppDelegate' if reactNativeMinorVersion >= 71
85
+ s.dependency 'React-NativeModulesApple' if reactNativeMinorVersion >= 72
72
86
 
73
87
  if fabric_enabled
74
88
  compiler_flags << ' ' << fabric_compiler_flags
@@ -77,6 +91,13 @@ Pod::Spec.new do |s|
77
91
  s.dependency 'RCT-Folly', folly_version
78
92
  end
79
93
 
94
+ unless defined?(install_modules_dependencies)
95
+ # `install_modules_dependencies` is defined from react_native_pods.rb.
96
+ # when running with `pod ipc spec`, this method is not defined and we have to require manually.
97
+ require File.join(File.dirname(`node --print "require.resolve('react-native/package.json')"`), "scripts/react_native_pods")
98
+ end
99
+ install_modules_dependencies(s)
100
+
80
101
  if !$ExpoUseSources&.include?(package['name']) && ENV['EXPO_USE_SOURCE'].to_i == 0 && File.exist?("ios/#{s.name}.xcframework") && Gem::Version.new(Pod::VERSION) >= Gem::Version.new('1.10.0')
81
102
  s.source_files = 'ios/**/*.h', 'common/cpp/**/*.h'
82
103
  s.vendored_frameworks = "ios/#{s.name}.xcframework"
@@ -78,7 +78,8 @@ endif ()
78
78
 
79
79
  if(${UNIT_TEST})
80
80
  if(${USE_HERMES})
81
- set(JSEXECUTOR_LIB ReactAndroid::hermes_executor)
81
+ find_package(hermes-engine REQUIRED CONFIG)
82
+ set(JSEXECUTOR_LIB hermes-engine::libhermes)
82
83
  else()
83
84
  set(JSEXECUTOR_LIB ReactAndroid::jscexecutor)
84
85
  endif()
@@ -30,6 +30,10 @@ ext.applyKotlinExpoModulesCorePlugin = {
30
30
  apply plugin: KotlinExpoModulesCorePlugin
31
31
  }
32
32
 
33
+ ext.boolish = { value ->
34
+ return value.toString().toBoolean()
35
+ }
36
+
33
37
  // [BEGIN] Remove when we drop SDK 47
34
38
  abstract class ExtractReactNativeAARTask extends DefaultTask {
35
39
  @Input
@@ -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.3.2'
9
+ version = '1.5.0'
10
10
 
11
11
  buildscript {
12
12
  def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
@@ -53,12 +53,12 @@ def customDownloadsDir = System.getenv("REACT_NATIVE_DOWNLOADS_DIR")
53
53
  def downloadsDir = customDownloadsDir ? new File(customDownloadsDir) : new File("$buildDir/downloads")
54
54
  def thirdPartyNdkDir = new File("$buildDir/third-party-ndk")
55
55
 
56
- def REACT_NATIVE_BUILD_FROM_SOURCE = findProject(":ReactAndroid") != null
56
+ def REACT_NATIVE_BUILD_FROM_SOURCE = findProject(":packages:react-native:ReactAndroid") != null
57
57
  def REACT_NATIVE_DIR = REACT_NATIVE_BUILD_FROM_SOURCE
58
- ? findProject(":ReactAndroid").getProjectDir().parent
58
+ ? findProject(":packages:react-native:ReactAndroid").getProjectDir().parent
59
59
  : new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).parent
60
60
  def REACT_NATIVE_SO_DIR = REACT_NATIVE_BUILD_FROM_SOURCE
61
- ? Paths.get(findProject(":ReactAndroid").getProjectDir().toString(), "build", "intermediates", "library_*", "*", "jni")
61
+ ? Paths.get(findProject(":packages:react-native:ReactAndroid").getProjectDir().toString(), "build", "intermediates", "library_*", "*", "jni")
62
62
  : "${buildDir}/react/jni"
63
63
 
64
64
  def reactProperties = new Properties()
@@ -79,26 +79,20 @@ def reactNativeArchitectures() {
79
79
  def prebuiltHermesDir = findProperty("expo.prebuiltHermesDir") ?: file("${rootDir}/prebuiltHermes")
80
80
  def prebuiltHermesVersion = file("${prebuiltHermesDir}/.hermesversion").exists() ? file("${prebuiltHermesDir}/.hermesversion").text : null
81
81
  def currentHermesVersion = file("${REACT_NATIVE_DIR}/sdks/.hermesversion").exists() ? file("${REACT_NATIVE_DIR}/sdks/.hermesversion").text : null
82
- def hasHermesProject = findProject(":ReactAndroid:hermes-engine") != null
82
+ def hasHermesProject = findProject(":packages:react-native:ReactAndroid:hermes-engine") != null
83
83
  def prebuiltHermesCacheHit = hasHermesProject && currentHermesVersion == prebuiltHermesVersion
84
84
 
85
85
  // By default we are going to download and unzip hermes inside the /sdks/hermes folder
86
86
  // but you can provide an override for where the hermes source code is located.
87
87
  def hermesDir = System.getenv("REACT_NATIVE_OVERRIDE_HERMES_DIR") ?: file("${REACT_NATIVE_DIR}/sdks/hermes")
88
88
 
89
- def USE_HERMES = false
89
+ def USE_HERMES = true
90
90
  def NEED_DOWNLOAD_HERMES = false
91
91
  def HERMES_HEADER_DIR = null
92
92
  def HERMES_AAR = null
93
93
  if (findProject(":app")) {
94
- def appProjectExt = project(":app").ext
95
- if (appProjectExt.has("react")) {
96
- USE_HERMES = project(":app").ext.react.enableHermes
97
- } else {
98
- USE_HERMES = (findProperty('expo.jsEngine') ?: "jsc") == "hermes"
99
- }
100
- } else {
101
- USE_HERMES = (findProperty('expo.jsEngine') ?: "jsc") == "hermes"
94
+ def appProject = project(":app")
95
+ USE_HERMES = appProject?.hermesEnabled?.toBoolean() || appProject?.ext?.react?.enableHermes?.toBoolean()
102
96
  }
103
97
 
104
98
  // Currently the needs for hermes/jsc are only for androidTest, so we turn on this flag only when `isExpoModulesCoreTests` is true
@@ -126,19 +120,11 @@ if (USE_HERMES) {
126
120
 
127
121
  def isNewArchitectureEnabled = findProperty("newArchEnabled") == "true"
128
122
 
129
- // Creating sources with comments
130
- task androidSourcesJar(type: Jar) {
131
- classifier = 'sources'
132
- from android.sourceSets.main.java.srcDirs
133
- }
134
-
135
123
  afterEvaluate {
136
124
  publishing {
137
125
  publications {
138
126
  release(MavenPublication) {
139
127
  from components.release
140
- // Add additional sourcesJar to artifacts
141
- artifact(androidSourcesJar)
142
128
  }
143
129
  }
144
130
  repositories {
@@ -168,12 +154,13 @@ android {
168
154
  jvmTarget = JavaVersion.VERSION_11.majorVersion
169
155
  }
170
156
 
157
+ namespace "expo.modules"
171
158
  defaultConfig {
172
159
  minSdkVersion safeExtGet("minSdkVersion", 21)
173
160
  targetSdkVersion safeExtGet("targetSdkVersion", 33)
174
161
  consumerProguardFiles 'proguard-rules.pro'
175
162
  versionCode 1
176
- versionName "1.3.2"
163
+ versionName "1.5.0"
177
164
  buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled.toString()
178
165
 
179
166
  testInstrumentationRunner "expo.modules.TestRunner"
@@ -263,6 +250,11 @@ android {
263
250
  }
264
251
  }
265
252
  }
253
+ publishing {
254
+ singleVariant("release") {
255
+ withSourcesJar()
256
+ }
257
+ }
266
258
  }
267
259
 
268
260
 
@@ -284,8 +276,8 @@ dependencies {
284
276
  * We're enforcing the most up-to-date versions of the dependencies here that are used in subclassing chain for ReactActivity.
285
277
  */
286
278
  implementation "androidx.appcompat:appcompat:1.4.1"
287
- implementation "androidx.activity:activity-ktx:1.4.0" // androidx.appcompat:appcompat:1.4.1 depends on version 1.2.3, so we enforce higher one here
288
- implementation "androidx.fragment:fragment-ktx:1.4.1" // androidx.appcomapt:appcompat:1.4.1 depends on version 1.3.4, so we enforce higher one here
279
+ 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
+ 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
289
281
 
290
282
  //noinspection GradleDynamicVersion
291
283
  implementation 'com.facebook.react:react-native:+'
@@ -293,11 +285,12 @@ dependencies {
293
285
  compileOnly 'com.facebook.fbjni:fbjni:0.3.0'
294
286
 
295
287
  testImplementation 'androidx.test:core:1.4.0'
296
- testImplementation 'junit:junit:4.13.1'
288
+ testImplementation 'junit:junit:4.13.2'
297
289
  testImplementation 'io.mockk:mockk:1.12.3'
298
290
  testImplementation "com.google.truth:truth:1.1.2"
299
- testImplementation "org.robolectric:robolectric:4.5.1"
291
+ testImplementation "org.robolectric:robolectric:4.10"
300
292
  testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.0"
293
+ testImplementation "org.json:json:20230227"
301
294
 
302
295
  androidTestImplementation 'androidx.test:runner:1.4.0'
303
296
  androidTestImplementation 'androidx.test:core:1.4.0'
@@ -307,10 +300,10 @@ dependencies {
307
300
  androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.0"
308
301
 
309
302
  if (USE_HERMES) {
310
- def hermesProject = findProject(":ReactAndroid:hermes-engine")
311
- androidTestImplementation (hermesProject ?: files(HERMES_AAR))
303
+ def hermesProject = findProject(":packages:react-native:ReactAndroid:hermes-engine")
304
+ compileOnly (hermesProject ?: files(HERMES_AAR))
312
305
  } else {
313
- androidTestImplementation "org.webkit:android-jsc:+"
306
+ compileOnly "org.webkit:android-jsc:+"
314
307
  }
315
308
  }
316
309
 
@@ -416,7 +409,7 @@ afterEvaluate {
416
409
  if (USE_HERMES) {
417
410
  nativeBuildDependsOn(project, prepareHermes, null)
418
411
  if (hasHermesProject && !prebuiltHermesCacheHit) {
419
- prepareHermes.dependsOn(":ReactAndroid:hermes-engine:assembleDebug")
412
+ prepareHermes.dependsOn(":packages:react-native:ReactAndroid:hermes-engine:assembleDebug")
420
413
  }
421
414
  }
422
415
  }
@@ -1,5 +1,4 @@
1
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
- package="expo.modules">
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
3
2
 
4
3
  <application>
5
4
  <meta-data
@@ -21,6 +21,9 @@ ExpoModulesHostObject::~ExpoModulesHostObject() {
21
21
  facebook::react::LongLivedObjectCollection::get().clear();
22
22
  installer->jsRegistry.reset();
23
23
  installer->runtimeHolder.reset();
24
+ installer->jsInvoker.reset();
25
+ installer->nativeInvoker.reset();
26
+ installer->jniDeallocator.reset();
24
27
  }
25
28
 
26
29
  jsi::Value ExpoModulesHostObject::get(jsi::Runtime &runtime, const jsi::PropNameID &name) {
@@ -0,0 +1,17 @@
1
+ // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2
+
3
+ #include "JNIDeallocator.h"
4
+
5
+ namespace expo {
6
+
7
+ void JNIDeallocator::addReference(
8
+ jni::local_ref<Destructible::javaobject> jniObject
9
+ ) {
10
+ const static auto method = JNIDeallocator::javaClassLocal()
11
+ ->getMethod<void(jni::local_ref<Destructible>)>(
12
+ "addReference"
13
+ );
14
+ method(self(), std::move(jniObject));
15
+ }
16
+
17
+ } // namespace expo
@@ -0,0 +1,25 @@
1
+ // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2
+
3
+ #pragma once
4
+
5
+ #include <fbjni/fbjni.h>
6
+
7
+ namespace jni = facebook::jni;
8
+
9
+ namespace expo {
10
+
11
+ class Destructible : public jni::JavaClass<Destructible> {
12
+ public:
13
+ static auto constexpr kJavaDescriptor = "Lexpo/modules/kotlin/jni/Destructible;";
14
+ };
15
+
16
+ class JNIDeallocator : public jni::JavaClass<JNIDeallocator> {
17
+ public:
18
+ static auto constexpr kJavaDescriptor = "Lexpo/modules/kotlin/jni/JNIDeallocator;";
19
+
20
+ void addReference(
21
+ jni::local_ref<Destructible::javaobject> jniObject
22
+ );
23
+ };
24
+
25
+ } // namespace expo
@@ -37,9 +37,12 @@ JSIInteropModuleRegistry::JSIInteropModuleRegistry(jni::alias_ref<jhybridobject>
37
37
 
38
38
  void JSIInteropModuleRegistry::installJSI(
39
39
  jlong jsRuntimePointer,
40
+ jni::alias_ref<JNIDeallocator::javaobject> jniDeallocator,
40
41
  jni::alias_ref<react::CallInvokerHolder::javaobject> jsInvokerHolder,
41
42
  jni::alias_ref<react::CallInvokerHolder::javaobject> nativeInvokerHolder
42
43
  ) {
44
+ this->jniDeallocator = jni::make_global(jniDeallocator);
45
+
43
46
  auto runtime = reinterpret_cast<jsi::Runtime *>(jsRuntimePointer);
44
47
 
45
48
  jsRegistry = std::make_unique<JSReferencesCache>(*runtime);
@@ -73,10 +76,14 @@ void JSIInteropModuleRegistry::installJSI(
73
76
  );
74
77
  }
75
78
 
76
- void JSIInteropModuleRegistry::installJSIForTests() {
79
+ void JSIInteropModuleRegistry::installJSIForTests(
80
+ jni::alias_ref<JNIDeallocator::javaobject> jniDeallocator
81
+ ) {
77
82
  #if !UNIT_TEST
78
83
  throw std::logic_error("The function is only available when UNIT_TEST is defined.");
79
84
  #else
85
+ this->jniDeallocator = jni::make_global(jniDeallocator);
86
+
80
87
  runtimeHolder = std::make_shared<JavaScriptRuntime>(this);
81
88
  jsi::Runtime &jsiRuntime = runtimeHolder->get();
82
89
 
@@ -8,6 +8,7 @@
8
8
  #include "JavaScriptObject.h"
9
9
  #include "JavaReferencesCache.h"
10
10
  #include "JSReferencesCache.h"
11
+ #include "JNIDeallocator.h"
11
12
 
12
13
  #include <fbjni/fbjni.h>
13
14
  #include <jsi/jsi.h>
@@ -39,6 +40,7 @@ public:
39
40
  */
40
41
  void installJSI(
41
42
  jlong jsRuntimePointer,
43
+ jni::alias_ref<JNIDeallocator::javaobject> jniDeallocator,
42
44
  jni::alias_ref<react::CallInvokerHolder::javaobject> jsInvokerHolder,
43
45
  jni::alias_ref<react::CallInvokerHolder::javaobject> nativeInvokerHolder
44
46
  );
@@ -46,7 +48,9 @@ public:
46
48
  /**
47
49
  * Initializes the test runtime. Shouldn't be used in the production.
48
50
  */
49
- void installJSIForTests();
51
+ void installJSIForTests(
52
+ jni::alias_ref<JNIDeallocator::javaobject> jniDeallocator
53
+ );
50
54
 
51
55
  /**
52
56
  * Gets a module for a given name. It will throw an exception if the module doesn't exist.
@@ -97,6 +101,7 @@ public:
97
101
  std::shared_ptr<react::CallInvoker> nativeInvoker;
98
102
  std::shared_ptr<JavaScriptRuntime> runtimeHolder;
99
103
  std::unique_ptr<JSReferencesCache> jsRegistry;
104
+ jni::global_ref<JNIDeallocator::javaobject> jniDeallocator;
100
105
  private:
101
106
  friend HybridBase;
102
107
  jni::global_ref<JSIInteropModuleRegistry::javaobject> javaPart_;
@@ -1,6 +1,7 @@
1
1
  // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2
2
 
3
3
  #include "JavaCallback.h"
4
+ #include "JSIInteropModuleRegistry.h"
4
5
 
5
6
  namespace expo {
6
7
 
@@ -21,6 +22,14 @@ void JavaCallback::registerNatives() {
21
22
  });
22
23
  }
23
24
 
25
+ jni::local_ref<JavaCallback::javaobject> JavaCallback::newInstance(
26
+ JSIInteropModuleRegistry *jsiInteropModuleRegistry,
27
+ Callback callback
28
+ ) {
29
+ auto object = JavaCallback::newObjectCxxArgs(std::move(callback));
30
+ jsiInteropModuleRegistry->jniDeallocator->addReference(object);
31
+ return object;
32
+ }
24
33
 
25
34
  void JavaCallback::invoke() {
26
35
  callback(nullptr);
@@ -2,6 +2,8 @@
2
2
 
3
3
  #pragma once
4
4
 
5
+ #include "JNIDeallocator.h"
6
+
5
7
  #include <fbjni/fbjni.h>
6
8
  #include <folly/dynamic.h>
7
9
 
@@ -12,18 +14,26 @@ namespace jni = facebook::jni;
12
14
  namespace react = facebook::react;
13
15
 
14
16
  namespace expo {
15
- class JavaCallback : public jni::HybridClass<JavaCallback> {
17
+ class JSIInteropModuleRegistry;
18
+
19
+ class JavaCallback : public jni::HybridClass<JavaCallback, Destructible> {
16
20
  public:
17
21
  static auto constexpr
18
22
  kJavaDescriptor = "Lexpo/modules/kotlin/jni/JavaCallback;";
19
23
  static auto constexpr TAG = "JavaCallback";
20
24
 
25
+ using Callback = std::function<void(folly::dynamic)>;
26
+
21
27
  static void registerNatives();
22
28
 
29
+ static jni::local_ref<JavaCallback::javaobject> newInstance(
30
+ JSIInteropModuleRegistry *jsiInteropModuleRegistry,
31
+ Callback callback
32
+ );
33
+
23
34
  private:
24
35
  friend HybridBase;
25
36
 
26
- using Callback = std::function<void(folly::dynamic)>;
27
37
 
28
38
  JavaCallback(Callback callback);
29
39
 
@@ -53,4 +53,17 @@ jobject JavaScriptFunction::invoke(
53
53
  auto convertedResult = converter->convert(rt, env, moduleRegistry, result);
54
54
  return convertedResult;
55
55
  }
56
+
57
+ jni::local_ref<JavaScriptFunction::javaobject> JavaScriptFunction::newInstance(
58
+ JSIInteropModuleRegistry *jsiInteropModuleRegistry,
59
+ std::weak_ptr<JavaScriptRuntime> runtime,
60
+ std::shared_ptr<jsi::Function> jsFunction
61
+ ) {
62
+ auto function = JavaScriptFunction::newObjectCxxArgs(
63
+ std::move(runtime),
64
+ std::move(jsFunction)
65
+ );
66
+ jsiInteropModuleRegistry->jniDeallocator->addReference(function);
67
+ return function;
68
+ }
56
69
  } // namespace expo
@@ -18,7 +18,7 @@ namespace expo {
18
18
  /**
19
19
  * Represents any JavaScript function. Its purpose is to expose the `jsi::Function` API back to Kotlin.
20
20
  */
21
- class JavaScriptFunction : public jni::HybridClass<JavaScriptFunction>, JSIFunctionWrapper {
21
+ class JavaScriptFunction : public jni::HybridClass<JavaScriptFunction, Destructible>, JSIFunctionWrapper {
22
22
  public:
23
23
  static auto constexpr
24
24
  kJavaDescriptor = "Lexpo/modules/kotlin/jni/JavaScriptFunction;";
@@ -26,6 +26,12 @@ public:
26
26
 
27
27
  static void registerNatives();
28
28
 
29
+ static jni::local_ref<JavaScriptFunction::javaobject> newInstance(
30
+ JSIInteropModuleRegistry *jsiInteropModuleRegistry,
31
+ std::weak_ptr<JavaScriptRuntime> runtime,
32
+ std::shared_ptr<jsi::Function> jsFunction
33
+ );
34
+
29
35
  JavaScriptFunction(
30
36
  std::weak_ptr<JavaScriptRuntime> runtime,
31
37
  std::shared_ptr<jsi::Function> jsFunction
@@ -199,7 +199,8 @@ std::shared_ptr<jsi::Object> JavaScriptModuleObject::getJSIObject(jsi::Runtime &
199
199
  JavaReferencesCache::instance()->getJClass(
200
200
  "expo/modules/kotlin/sharedobjects/SharedObject").clazz
201
201
  )) {
202
- auto jsThisObject = JavaScriptObject::newObjectCxxArgs(
202
+ auto jsThisObject = JavaScriptObject::newInstance(
203
+ jsiInteropModuleRegistry,
203
204
  jsiInteropModuleRegistry->runtimeHolder,
204
205
  thisObject
205
206
  );
@@ -7,6 +7,7 @@
7
7
  #include "JSITypeConverter.h"
8
8
  #include "ObjectDeallocator.h"
9
9
  #include "JavaReferencesCache.h"
10
+ #include "JSIInteropModuleRegistry.h"
10
11
 
11
12
  namespace expo {
12
13
  void JavaScriptObject::registerNatives() {
@@ -73,7 +74,11 @@ jni::local_ref<JavaScriptValue::javaobject> JavaScriptObject::jniGetProperty(
73
74
  jni::alias_ref<jstring> name
74
75
  ) {
75
76
  auto result = std::make_shared<jsi::Value>(getProperty(name->toStdString()));
76
- return JavaScriptValue::newObjectCxxArgs(runtimeHolder, result);
77
+ return JavaScriptValue::newInstance(
78
+ runtimeHolder.getModuleRegistry(),
79
+ runtimeHolder,
80
+ result
81
+ );
77
82
  }
78
83
 
79
84
  std::vector<std::string> JavaScriptObject::getPropertyNames() {
@@ -107,7 +112,7 @@ jni::local_ref<jni::JArrayClass<jstring>> JavaScriptObject::jniGetPropertyNames(
107
112
  jni::local_ref<JavaScriptFunction::javaobject> JavaScriptObject::jniAsFunction() {
108
113
  auto &jsRuntime = runtimeHolder.getJSRuntime();
109
114
  auto jsFuncion = std::make_shared<jsi::Function>(jsObject->asFunction(jsRuntime));
110
- return JavaScriptFunction::newObjectCxxArgs(runtimeHolder, jsFuncion);
115
+ return JavaScriptFunction::newInstance(runtimeHolder.getModuleRegistry(), runtimeHolder, jsFuncion);
111
116
  }
112
117
 
113
118
  void JavaScriptObject::setProperty(const std::string &name, jsi::Value value) {
@@ -159,6 +164,16 @@ void JavaScriptObject::defineProperty(
159
164
  });
160
165
  }
161
166
 
167
+ jni::local_ref<JavaScriptObject::javaobject> JavaScriptObject::newInstance(
168
+ JSIInteropModuleRegistry *jsiInteropModuleRegistry,
169
+ std::weak_ptr<JavaScriptRuntime> runtime,
170
+ std::shared_ptr<jsi::Object> jsObject
171
+ ) {
172
+ auto object = JavaScriptObject::newObjectCxxArgs(std::move(runtime), std::move(jsObject));
173
+ jsiInteropModuleRegistry->jniDeallocator->addReference(object);
174
+ return object;
175
+ }
176
+
162
177
  void JavaScriptObject::defineNativeDeallocator(
163
178
  jni::alias_ref<JNIFunctionBody::javaobject> deallocator
164
179
  ) {
@@ -7,6 +7,7 @@
7
7
  #include "JavaScriptRuntime.h"
8
8
  #include "WeakRuntimeHolder.h"
9
9
  #include "JNIFunctionBody.h"
10
+ #include "JNIDeallocator.h"
10
11
 
11
12
  #include <fbjni/fbjni.h>
12
13
  #include <jsi/jsi.h>
@@ -24,7 +25,7 @@ class JavaScriptFunction;
24
25
  /**
25
26
  * Represents any JavaScript object. Its purpose is to exposes `jsi::Object` API back to Kotlin.
26
27
  */
27
- class JavaScriptObject : public jni::HybridClass<JavaScriptObject>, JSIObjectWrapper {
28
+ class JavaScriptObject : public jni::HybridClass<JavaScriptObject, Destructible>, JSIObjectWrapper {
28
29
  public:
29
30
  static auto constexpr
30
31
  kJavaDescriptor = "Lexpo/modules/kotlin/jni/JavaScriptObject;";
@@ -32,6 +33,12 @@ public:
32
33
 
33
34
  static void registerNatives();
34
35
 
36
+ static jni::local_ref<JavaScriptObject::javaobject> newInstance(
37
+ JSIInteropModuleRegistry *jsiInteropModuleRegistry,
38
+ std::weak_ptr<JavaScriptRuntime> runtime,
39
+ std::shared_ptr<jsi::Object> jsObject
40
+ );
41
+
35
42
  JavaScriptObject(
36
43
  std::weak_ptr<JavaScriptRuntime> runtime,
37
44
  std::shared_ptr<jsi::Object> jsObject
@@ -84,13 +91,13 @@ private:
84
91
 
85
92
  bool jniHasProperty(jni::alias_ref<jstring> name);
86
93
 
87
- jni::local_ref<jni::HybridClass<JavaScriptValue>::javaobject> jniGetProperty(
94
+ jni::local_ref<jni::HybridClass<JavaScriptValue, Destructible>::javaobject> jniGetProperty(
88
95
  jni::alias_ref<jstring> name
89
96
  );
90
97
 
91
98
  jni::local_ref<jni::JArrayClass<jstring>> jniGetPropertyNames();
92
99
 
93
- jni::local_ref<jni::HybridClass<JavaScriptFunction>::javaobject> jniAsFunction();
100
+ jni::local_ref<jni::HybridClass<JavaScriptFunction, Destructible>::javaobject> jniAsFunction();
94
101
 
95
102
  /**
96
103
  * Unsets property with the given name.
@@ -4,7 +4,7 @@
4
4
  #include "JavaScriptValue.h"
5
5
  #include "JavaScriptObject.h"
6
6
  #include "Exceptions.h"
7
- #include "JavaScriptRuntime.h"
7
+ #include "JSIInteropModuleRegistry.h"
8
8
 
9
9
  #if UNIT_TEST
10
10
 
@@ -125,7 +125,8 @@ jni::local_ref<JavaScriptValue::javaobject>
125
125
  JavaScriptRuntime::evaluateScript(const std::string &script) {
126
126
  auto scriptBuffer = std::make_shared<jsi::StringBuffer>(script);
127
127
  try {
128
- return JavaScriptValue::newObjectCxxArgs(
128
+ return JavaScriptValue::newInstance(
129
+ jsiInteropModuleRegistry,
129
130
  weak_from_this(),
130
131
  std::make_shared<jsi::Value>(runtime->evaluateJavaScript(scriptBuffer, "<<evaluated>>"))
131
132
  );
@@ -148,12 +149,12 @@ JavaScriptRuntime::evaluateScript(const std::string &script) {
148
149
 
149
150
  jni::local_ref<JavaScriptObject::javaobject> JavaScriptRuntime::global() {
150
151
  auto global = std::make_shared<jsi::Object>(runtime->global());
151
- return JavaScriptObject::newObjectCxxArgs(weak_from_this(), global);
152
+ return JavaScriptObject::newInstance(jsiInteropModuleRegistry, weak_from_this(), global);
152
153
  }
153
154
 
154
155
  jni::local_ref<JavaScriptObject::javaobject> JavaScriptRuntime::createObject() {
155
156
  auto newObject = std::make_shared<jsi::Object>(*runtime);
156
- return JavaScriptObject::newObjectCxxArgs(weak_from_this(), newObject);
157
+ return JavaScriptObject::newInstance(jsiInteropModuleRegistry, weak_from_this(), newObject);
157
158
  }
158
159
 
159
160
  void JavaScriptRuntime::drainJSEventLoop() {