expo-modules-core 1.1.0 → 1.2.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.
- package/CHANGELOG.md +29 -0
- package/android/CMakeLists.txt +9 -25
- package/android/ExpoModulesCorePlugin.gradle +0 -1
- package/android/build.gradle +29 -23
- package/android/legacy/CMakeLists.txt +2 -0
- package/android/src/fabric/CMakeLists.txt +12 -9
- package/android/src/main/cpp/JavaReferencesCache.cpp +6 -0
- package/android/src/main/cpp/JavaReferencesCache.h +20 -6
- package/android/src/main/cpp/JavaScriptModuleObject.cpp +9 -9
- package/android/src/main/cpp/JavaScriptModuleObject.h +5 -3
- package/android/src/main/cpp/JavaScriptRuntime.cpp +4 -0
- package/android/src/main/cpp/MethodMetadata.cpp +13 -2
- package/android/src/main/cpp/types/CppType.h +12 -11
- package/android/src/main/cpp/types/FrontendConverter.cpp +23 -0
- package/android/src/main/cpp/types/FrontendConverter.h +15 -0
- package/android/src/main/cpp/types/FrontendConverterProvider.cpp +1 -0
- package/android/src/main/java/expo/modules/kotlin/DynamicExtenstions.kt +3 -0
- package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +8 -2
- package/android/src/main/java/expo/modules/kotlin/functions/AnyFunction.kt +35 -24
- package/android/src/main/java/expo/modules/kotlin/jni/CppType.kt +1 -0
- package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptValue.kt +4 -0
- package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +1 -4
- package/android/src/main/java/expo/modules/kotlin/objects/ObjectDefinitionBuilder.kt +30 -0
- package/android/src/main/java/expo/modules/kotlin/objects/ObjectDefinitionData.kt +5 -1
- package/android/src/main/java/expo/modules/kotlin/types/JSTypeConverter.kt +1 -0
- package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +6 -0
- package/android/src/main/java/expo/modules/kotlin/views/AnyViewProp.kt +2 -0
- package/android/src/main/java/expo/modules/kotlin/views/ConcreteViewProp.kt +2 -0
- package/android/src/main/java/expo/modules/kotlin/views/ViewDefinitionBuilder.kt +56 -6
- package/android/src/main/java/expo/modules/kotlin/views/ViewGroupDefinitionBuilder.kt +73 -1
- package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinition.kt +20 -16
- package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +2 -2
- package/build/NativeViewManagerAdapter.native.d.ts.map +1 -1
- package/build/NativeViewManagerAdapter.native.js +19 -1
- package/build/NativeViewManagerAdapter.native.js.map +1 -1
- package/build/SyntheticPlatformEmitter.d.ts +1 -1
- package/build/SyntheticPlatformEmitter.d.ts.map +1 -1
- package/build/SyntheticPlatformEmitter.js +1 -1
- package/build/SyntheticPlatformEmitter.js.map +1 -1
- package/ios/Fabric/ExpoFabricView.swift +6 -6
- package/ios/Fabric/ExpoFabricViewObjC.h +1 -1
- package/ios/Fabric/ExpoFabricViewObjC.mm +3 -9
- package/ios/Swift/Conversions.swift +5 -2
- package/ios/Swift/ExpoBridgeModule.swift +23 -2
- package/ios/Swift/Functions/AnyFunction.swift +4 -0
- package/ios/Swift/Functions/ConcurrentFunctionDefinition.swift +271 -0
- package/ios/Swift/Functions/SyncFunctionComponent.swift +8 -4
- package/ios/Swift/Objects/ObjectDefinitionBuilder.swift +25 -0
- package/ios/Swift/Objects/ObjectDefinitionComponents.swift +6 -0
- package/ios/Swift/Views/ViewModuleWrapper.swift +7 -9
- package/ios/Tests/FunctionSpec.swift +26 -2
- package/package.json +2 -2
- package/src/NativeViewManagerAdapter.native.tsx +23 -2
- package/src/SyntheticPlatformEmitter.ts +1 -1
- package/build/SyntheticPlatformEmitter.web.d.ts +0 -6
- package/build/SyntheticPlatformEmitter.web.d.ts.map +0 -1
- package/build/SyntheticPlatformEmitter.web.js +0 -6
- package/build/SyntheticPlatformEmitter.web.js.map +0 -1
- package/src/SyntheticPlatformEmitter.web.ts +0 -5
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,35 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 1.2.0 — 2023-02-03
|
|
14
|
+
|
|
15
|
+
### 🎉 New features
|
|
16
|
+
|
|
17
|
+
- View-related DSL functions do not require providing the view's type in function parameters on Android. ([#20751](https://github.com/expo/expo/pull/20751) by [@lukmccall](https://github.com/lukmccall))
|
|
18
|
+
- Add support for the `Long` type as function parameters on Android. ([#20787](https://github.com/expo/expo/pull/20787) by [@lukmccall](https://github.com/lukmccall))
|
|
19
|
+
- [Android] Added experimental support for building the function result from the object definition. ([#20864](https://github.com/expo/expo/pull/20864) by [@lukmccall](https://github.com/lukmccall))
|
|
20
|
+
- Removed boost dependency which needs extra downloading on Android. ([#21000](https://github.com/expo/expo/pull/21000) by [@kudo](https://github.com/kudo))
|
|
21
|
+
|
|
22
|
+
### 🐛 Bug fixes
|
|
23
|
+
|
|
24
|
+
- Fix view prop setter not being called when its new value is `null` or `undefined`. ([#20755](https://github.com/expo/expo/pull/20755) & [#20766](https://github.com/expo/expo/pull/20766) by [@tsapeta](https://github.com/tsapeta) & [@lukmccall](https://github.com/lukmccall))
|
|
25
|
+
- Fixed "Tried to register two views with the same name" error on fast refresh. ([#20788](https://github.com/expo/expo/pull/20788) by [@tsapeta](https://github.com/tsapeta))
|
|
26
|
+
|
|
27
|
+
### 💡 Others
|
|
28
|
+
|
|
29
|
+
- On Android bump `compileSdkVersion` and `targetSdkVersion` to `33`. ([#20721](https://github.com/expo/expo/pull/20721) by [@lukmccall](https://github.com/lukmccall))
|
|
30
|
+
|
|
31
|
+
## 1.1.1 — 2023-01-06
|
|
32
|
+
|
|
33
|
+
### 🎉 New features
|
|
34
|
+
|
|
35
|
+
- Added support for concurrent (async/await) functions in Swift. ([#20645](https://github.com/expo/expo/pull/20645) by [@tsapeta](https://github.com/tsapeta))
|
|
36
|
+
- [iOS] Added experimental support for building the function result from the object definition. ([#20623](https://github.com/expo/expo/pull/20623) by [@tsapeta](https://github.com/tsapeta))
|
|
37
|
+
|
|
38
|
+
### 🐛 Bug fixes
|
|
39
|
+
|
|
40
|
+
- Fixed boost build error on Android. ([#20719](https://github.com/expo/expo/pull/20719) by [@kudo](https://github.com/kudo))
|
|
41
|
+
|
|
13
42
|
## 1.1.0 — 2022-12-30
|
|
14
43
|
|
|
15
44
|
### 🎉 New features
|
package/android/CMakeLists.txt
CHANGED
|
@@ -6,7 +6,9 @@ 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} ${
|
|
9
|
+
set(ignoreMe "${PROJECT_BUILD_DIR} ${REACT_ANDROID_BUILD_DIR} ${REACT_ANDROID_DIR} ${HERMES_HEADER_DIR} ${BOOST_VERSION}")
|
|
10
|
+
|
|
11
|
+
string(APPEND CMAKE_CXX_FLAGS " -DREACT_NATIVE_TARGET_VERSION=${REACT_NATIVE_TARGET_VERSION}")
|
|
10
12
|
|
|
11
13
|
if (${NATIVE_DEBUG})
|
|
12
14
|
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g")
|
|
@@ -76,26 +78,12 @@ endif ()
|
|
|
76
78
|
|
|
77
79
|
if(${UNIT_TEST})
|
|
78
80
|
if(${USE_HERMES})
|
|
79
|
-
|
|
80
|
-
find_library(
|
|
81
|
-
JSEXECUTOR_LIB
|
|
82
|
-
hermes
|
|
83
|
-
PATHS ${HERMES_SO_DIR}
|
|
84
|
-
NO_CMAKE_FIND_ROOT_PATH
|
|
85
|
-
)
|
|
86
|
-
set(JSEXECUTOR_INCLUDE ${HERMES_HEADER_DIR} ${HERMES_HEADER_DIR}/API ${HERMES_HEADER_DIR}/public)
|
|
81
|
+
set(JSEXECUTOR_LIB ReactAndroid::hermes_executor)
|
|
87
82
|
else()
|
|
88
|
-
|
|
89
|
-
JSEXECUTOR_LIB
|
|
90
|
-
jscexecutor
|
|
91
|
-
PATHS ${LIBRN_DIR}
|
|
92
|
-
NO_CMAKE_FIND_ROOT_PATH
|
|
93
|
-
)
|
|
94
|
-
set(JSEXECUTOR_INCLUDE "")
|
|
83
|
+
set(JSEXECUTOR_LIB ReactAndroid::jscexecutor)
|
|
95
84
|
endif()
|
|
96
85
|
else()
|
|
97
86
|
set(JSEXECUTOR_LIB "")
|
|
98
|
-
set(JSEXECUTOR_INCLUDE "")
|
|
99
87
|
endif()
|
|
100
88
|
|
|
101
89
|
# find libraries
|
|
@@ -118,22 +106,18 @@ target_include_directories(
|
|
|
118
106
|
|
|
119
107
|
# header only imports from turbomodule, e.g. CallInvokerHolder.h
|
|
120
108
|
"${REACT_NATIVE_DIR}/ReactAndroid/src/main/jni/react/turbomodule"
|
|
121
|
-
|
|
122
|
-
"${BUILD_DIR}/third-party-ndk/boost/boost_${BOOST_VERSION}"
|
|
123
109
|
"${COMMON_DIR}"
|
|
124
|
-
"${JSEXECUTOR_INCLUDE}"
|
|
125
110
|
"${SRC_DIR}/fabric"
|
|
126
111
|
)
|
|
127
112
|
|
|
128
113
|
# linking
|
|
129
114
|
|
|
115
|
+
include("${REACT_NATIVE_DIR}/ReactAndroid/cmake-utils/folly-flags.cmake")
|
|
116
|
+
|
|
130
117
|
target_compile_options(
|
|
131
118
|
${PACKAGE_NAME}
|
|
132
|
-
PRIVATE
|
|
133
|
-
|
|
134
|
-
-DFOLLY_HAVE_MEMRCHR=1
|
|
135
|
-
-DFOLLY_USE_LIBCPP=1
|
|
136
|
-
-DFOLLY_MOBILE=1
|
|
119
|
+
PRIVATE
|
|
120
|
+
${folly_FLAGS}
|
|
137
121
|
)
|
|
138
122
|
|
|
139
123
|
target_link_libraries(
|
|
@@ -74,7 +74,6 @@ class LegacyReactNativeLibsExtractionPlugin implements Plugin<Project> {
|
|
|
74
74
|
def reactProperties = new Properties()
|
|
75
75
|
new File("$REACT_NATIVE_DIR/ReactAndroid/gradle.properties").withInputStream { reactProperties.load(it) }
|
|
76
76
|
def FOLLY_VERSION = reactProperties.getProperty("FOLLY_VERSION")
|
|
77
|
-
def BOOST_VERSION = reactProperties.getProperty("BOOST_VERSION")
|
|
78
77
|
def DOUBLE_CONVERSION_VERSION = reactProperties.getProperty("DOUBLE_CONVERSION_VERSION")
|
|
79
78
|
def REACT_NATIVE_VERSION = System.getenv("REACT_NATIVE_OVERRIDE_VERSION") ?: reactProperties.getProperty("VERSION_NAME")
|
|
80
79
|
def REACT_NATIVE_TARGET_VERSION = REACT_NATIVE_VERSION.split("\\.")[1].toInteger()
|
package/android/build.gradle
CHANGED
|
@@ -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.
|
|
9
|
+
version = '1.2.0'
|
|
10
10
|
|
|
11
11
|
buildscript {
|
|
12
12
|
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
|
|
@@ -150,24 +150,13 @@ afterEvaluate {
|
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
android {
|
|
153
|
-
compileSdkVersion safeExtGet("compileSdkVersion",
|
|
153
|
+
compileSdkVersion safeExtGet("compileSdkVersion", 33)
|
|
154
154
|
|
|
155
|
-
if (
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
ndkVersion rootProject.ext.ndkVersion
|
|
161
|
-
}
|
|
162
|
-
} else {
|
|
163
|
-
// This ndkVersion should align to prebuilt react-native building ndkVersion.
|
|
164
|
-
// Because the unwind library is different before NDK r23 and after,
|
|
165
|
-
// if we build this library with newer NDK, C++ exceptions are incompatible between these libraries.
|
|
166
|
-
// For example, C++ exceptions throwing from hermes are not catchable from this library.
|
|
167
|
-
// Ref: https://android.googlesource.com/platform/ndk/+/master/docs/BuildSystemMaintainers.md#unwinding
|
|
168
|
-
//
|
|
169
|
-
// TODO: Revisit this version when upgrade react-native 0.71 (Expo SDK 48)
|
|
170
|
-
ndkVersion = "21.4.7075529"
|
|
155
|
+
if (rootProject.hasProperty("ndkPath")) {
|
|
156
|
+
ndkPath rootProject.ext.ndkPath
|
|
157
|
+
}
|
|
158
|
+
if (rootProject.hasProperty("ndkVersion")) {
|
|
159
|
+
ndkVersion rootProject.ext.ndkVersion
|
|
171
160
|
}
|
|
172
161
|
|
|
173
162
|
compileOptions {
|
|
@@ -181,10 +170,10 @@ android {
|
|
|
181
170
|
|
|
182
171
|
defaultConfig {
|
|
183
172
|
minSdkVersion safeExtGet("minSdkVersion", 21)
|
|
184
|
-
targetSdkVersion safeExtGet("targetSdkVersion",
|
|
173
|
+
targetSdkVersion safeExtGet("targetSdkVersion", 33)
|
|
185
174
|
consumerProguardFiles 'proguard-rules.pro'
|
|
186
175
|
versionCode 1
|
|
187
|
-
versionName "1.
|
|
176
|
+
versionName "1.2.0"
|
|
188
177
|
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled.toString()
|
|
189
178
|
|
|
190
179
|
testInstrumentationRunner "expo.modules.TestRunner"
|
|
@@ -300,7 +289,7 @@ dependencies {
|
|
|
300
289
|
//noinspection GradleDynamicVersion
|
|
301
290
|
implementation 'com.facebook.react:react-native:+'
|
|
302
291
|
|
|
303
|
-
compileOnly 'com.facebook.fbjni:fbjni:0.
|
|
292
|
+
compileOnly 'com.facebook.fbjni:fbjni:0.3.0'
|
|
304
293
|
|
|
305
294
|
testImplementation 'androidx.test:core:1.4.0'
|
|
306
295
|
testImplementation 'junit:junit:4.13.1'
|
|
@@ -404,10 +393,27 @@ def prepareBoost = tasks.register('prepareBoost', Copy) {
|
|
|
404
393
|
}
|
|
405
394
|
}
|
|
406
395
|
|
|
396
|
+
void nativeBuildDependsOn(project, dependsOnTask, buildTypesIncludes) {
|
|
397
|
+
def buildTasks = project.tasks.findAll { task ->
|
|
398
|
+
def taskName = task.name
|
|
399
|
+
if (taskName.contains("Clean")) { return false }
|
|
400
|
+
if (taskName.contains("externalNative") || taskName.contains("CMake") || taskName.contains("generateJsonModel")) {
|
|
401
|
+
if (buildTypesIncludes == null) { return true }
|
|
402
|
+
for (buildType in buildTypesIncludes) {
|
|
403
|
+
if (taskName.contains(buildType)) { return true }
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
return false
|
|
407
|
+
}
|
|
408
|
+
buildTasks.forEach { task -> task.dependsOn(dependsOnTask) }
|
|
409
|
+
}
|
|
410
|
+
|
|
407
411
|
afterEvaluate {
|
|
408
|
-
|
|
412
|
+
if (REACT_NATIVE_TARGET_VERSION < 71) {
|
|
413
|
+
nativeBuildDependsOn(project, prepareBoost, null)
|
|
414
|
+
}
|
|
409
415
|
if (USE_HERMES) {
|
|
410
|
-
|
|
416
|
+
nativeBuildDependsOn(project, prepareHermes, null)
|
|
411
417
|
if (hasHermesProject && !prebuiltHermesCacheHit) {
|
|
412
418
|
prepareHermes.dependsOn(":ReactAndroid:hermes-engine:assembleDebug")
|
|
413
419
|
}
|
|
@@ -9,6 +9,8 @@ set(PACKAGE_NAME "expo-modules-core")
|
|
|
9
9
|
set(BUILD_DIR ${CMAKE_SOURCE_DIR}/../build)
|
|
10
10
|
set(ignoreMe "${PROJECT_BUILD_DIR} ${REACT_ANDROID_BUILD_DIR} ${REACT_ANDROID_DIR} ${HERMES_HEADER_DIR}")
|
|
11
11
|
|
|
12
|
+
string(APPEND CMAKE_CXX_FLAGS " -DREACT_NATIVE_TARGET_VERSION=${REACT_NATIVE_TARGET_VERSION}")
|
|
13
|
+
|
|
12
14
|
if (${NATIVE_DEBUG})
|
|
13
15
|
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g")
|
|
14
16
|
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g")
|
|
@@ -9,24 +9,27 @@ add_library(fabric STATIC
|
|
|
9
9
|
${SOURCES}
|
|
10
10
|
)
|
|
11
11
|
|
|
12
|
+
include("${REACT_NATIVE_DIR}/ReactAndroid/cmake-utils/folly-flags.cmake")
|
|
13
|
+
|
|
12
14
|
target_compile_options(fabric PRIVATE
|
|
13
15
|
"-std=c++17"
|
|
14
|
-
|
|
15
|
-
-DFOLLY_HAVE_CLOCK_GETTIME=1
|
|
16
|
-
-DFOLLY_HAVE_MEMRCHR=1
|
|
17
|
-
-DFOLLY_USE_LIBCPP=1
|
|
18
|
-
-DFOLLY_MOBILE=1
|
|
16
|
+
${folly_FLAGS}
|
|
19
17
|
)
|
|
20
18
|
|
|
19
|
+
find_package(ReactAndroid REQUIRED CONFIG)
|
|
20
|
+
|
|
21
|
+
find_package(fbjni REQUIRED CONFIG)
|
|
22
|
+
|
|
23
|
+
get_target_property(INCLUDE_fabricjni
|
|
24
|
+
ReactAndroid::fabricjni
|
|
25
|
+
INTERFACE_INCLUDE_DIRECTORIES)
|
|
26
|
+
|
|
21
27
|
target_include_directories(fabric PRIVATE
|
|
22
28
|
"${REACT_NATIVE_DIR}/ReactCommon"
|
|
23
29
|
"${COMMON_FABRIC_DIR}"
|
|
30
|
+
"${INCLUDE_fabricjni}/react/fabric"
|
|
24
31
|
)
|
|
25
32
|
|
|
26
|
-
find_package(ReactAndroid REQUIRED CONFIG)
|
|
27
|
-
|
|
28
|
-
find_package(fbjni REQUIRED CONFIG)
|
|
29
|
-
|
|
30
33
|
target_link_libraries(fabric
|
|
31
34
|
CommonSettings
|
|
32
35
|
fbjni::fbjni
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
#include "JavaReferencesCache.h"
|
|
4
4
|
|
|
5
|
+
#include <vector>
|
|
6
|
+
|
|
5
7
|
namespace expo {
|
|
6
8
|
std::shared_ptr<JavaReferencesCache> JavaReferencesCache::instance() {
|
|
7
9
|
static std::shared_ptr<JavaReferencesCache> singleton{new JavaReferencesCache};
|
|
@@ -21,6 +23,10 @@ void JavaReferencesCache::loadJClasses(JNIEnv *env) {
|
|
|
21
23
|
{"<init>", "(I)V"}
|
|
22
24
|
});
|
|
23
25
|
|
|
26
|
+
loadJClass(env, "java/lang/Long", {
|
|
27
|
+
{"<init>", "(J)V"}
|
|
28
|
+
});
|
|
29
|
+
|
|
24
30
|
loadJClass(env, "java/lang/Float", {
|
|
25
31
|
{"<init>", "(F)V"}
|
|
26
32
|
});
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
#pragma once
|
|
4
4
|
|
|
5
5
|
#include <fbjni/fbjni.h>
|
|
6
|
-
#include "boost/functional/hash.hpp"
|
|
7
6
|
|
|
8
7
|
#include <memory>
|
|
9
8
|
#include <unordered_map>
|
|
@@ -11,11 +10,26 @@
|
|
|
11
10
|
namespace jni = facebook::jni;
|
|
12
11
|
|
|
13
12
|
namespace expo {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
|
|
14
|
+
template <typename T>
|
|
15
|
+
inline void hash_combine(std::size_t& seed, const T& v)
|
|
16
|
+
{
|
|
17
|
+
std::hash<T> hasher;
|
|
18
|
+
// Reference from: https://github.com/boostorg/container_hash/blob/boost-1.76.0/include/boost/container_hash/hash.hpp
|
|
19
|
+
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
struct pairhash {
|
|
23
|
+
template <typename A, typename B>
|
|
24
|
+
std::size_t operator()(const std::pair<A, B>& v) const {
|
|
25
|
+
std::size_t seed = 0;
|
|
26
|
+
hash_combine(seed, v.first);
|
|
27
|
+
hash_combine(seed, v.second);
|
|
28
|
+
return seed;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
using MethodHashMap = std::unordered_map<std::pair<std::string, std::string>, jmethodID, pairhash>;
|
|
19
33
|
|
|
20
34
|
/**
|
|
21
35
|
* Singleton registry used to store references to often used Java classes.
|
|
@@ -42,13 +42,15 @@ void JavaScriptModuleObject::registerNatives() {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
std::shared_ptr<jsi::Object> JavaScriptModuleObject::getJSIObject(jsi::Runtime &runtime) {
|
|
45
|
-
if (
|
|
46
|
-
|
|
47
|
-
jsiObject = std::make_shared<jsi::Object>(
|
|
48
|
-
jsi::Object::createFromHostObject(runtime, hostObject));
|
|
45
|
+
if (auto object = jsiObject.lock()) {
|
|
46
|
+
return object;
|
|
49
47
|
}
|
|
50
48
|
|
|
51
|
-
|
|
49
|
+
auto hostObject = std::make_shared<JavaScriptModuleObject::HostObject>(this);
|
|
50
|
+
auto object = std::make_shared<jsi::Object>(
|
|
51
|
+
jsi::Object::createFromHostObject(runtime, hostObject));
|
|
52
|
+
jsiObject = object;
|
|
53
|
+
return object;
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
void JavaScriptModuleObject::exportConstants(
|
|
@@ -143,9 +145,8 @@ JavaScriptModuleObject::HostObject::HostObject(
|
|
|
143
145
|
* Clears all the JSI references held by the `JavaScriptModuleObject`.
|
|
144
146
|
*/
|
|
145
147
|
JavaScriptModuleObject::HostObject::~HostObject() {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}
|
|
148
|
+
jObjectRef.reset();
|
|
149
|
+
jsModule->jsiObject.reset();
|
|
149
150
|
jsModule->methodsMetadata.clear();
|
|
150
151
|
jsModule->constants.clear();
|
|
151
152
|
jsModule->properties.clear();
|
|
@@ -236,5 +237,4 @@ JavaScriptModuleObject::JavaScriptModuleObject(jni::alias_ref<jhybridobject> jTh
|
|
|
236
237
|
: javaPart_(jni::make_global(jThis)) {
|
|
237
238
|
longLivedObjectCollection_ = std::make_shared<react::LongLivedObjectCollection>();
|
|
238
239
|
}
|
|
239
|
-
|
|
240
240
|
} // namespace expo
|
|
@@ -105,7 +105,7 @@ public:
|
|
|
105
105
|
public:
|
|
106
106
|
HostObject(JavaScriptModuleObject *);
|
|
107
107
|
|
|
108
|
-
|
|
108
|
+
~HostObject() override;
|
|
109
109
|
|
|
110
110
|
jsi::Value get(jsi::Runtime &, const jsi::PropNameID &name) override;
|
|
111
111
|
|
|
@@ -113,6 +113,7 @@ public:
|
|
|
113
113
|
|
|
114
114
|
std::vector<jsi::PropNameID> getPropertyNames(jsi::Runtime &rt) override;
|
|
115
115
|
|
|
116
|
+
jni::global_ref<jobject> jObjectRef;
|
|
116
117
|
private:
|
|
117
118
|
JavaScriptModuleObject *jsModule;
|
|
118
119
|
};
|
|
@@ -125,8 +126,10 @@ private:
|
|
|
125
126
|
/**
|
|
126
127
|
* A reference to the `JavaScriptModuleObject::HostObject`.
|
|
127
128
|
* Simple we cached that value to return the same object each time.
|
|
129
|
+
* It's a weak reference because the JS runtime holds the actual object.
|
|
130
|
+
* Doing that allows the runtime to deallocate jsi::Object if it's not needed anymore.
|
|
128
131
|
*/
|
|
129
|
-
std::
|
|
132
|
+
std::weak_ptr<jsi::Object> jsiObject;
|
|
130
133
|
jni::global_ref<JavaScriptModuleObject::javaobject> javaPart_;
|
|
131
134
|
|
|
132
135
|
/**
|
|
@@ -149,6 +152,5 @@ private:
|
|
|
149
152
|
* The `LongLivedObjectCollection` to hold `LongLivedObject` (callbacks or promises) for this module.
|
|
150
153
|
*/
|
|
151
154
|
std::shared_ptr<react::LongLivedObjectCollection> longLivedObjectCollection_;
|
|
152
|
-
|
|
153
155
|
};
|
|
154
156
|
} // namespace expo
|
|
@@ -164,7 +164,7 @@ MethodMetadata::MethodMetadata(
|
|
|
164
164
|
args(args),
|
|
165
165
|
isAsync(isAsync),
|
|
166
166
|
jBodyReference(std::move(jBodyReference)),
|
|
167
|
-
longLivedObjectCollection_(longLivedObjectCollection) {
|
|
167
|
+
longLivedObjectCollection_(std::move(longLivedObjectCollection)) {
|
|
168
168
|
argTypes.reserve(args);
|
|
169
169
|
for (size_t i = 0; i < args; i++) {
|
|
170
170
|
auto expectedType = expectedArgTypes->getElement(i);
|
|
@@ -186,7 +186,7 @@ MethodMetadata::MethodMetadata(
|
|
|
186
186
|
isAsync(isAsync),
|
|
187
187
|
argTypes(std::move(expectedArgTypes)),
|
|
188
188
|
jBodyReference(std::move(jBodyReference)),
|
|
189
|
-
longLivedObjectCollection_(longLivedObjectCollection) {
|
|
189
|
+
longLivedObjectCollection_(std::move(longLivedObjectCollection)) {
|
|
190
190
|
}
|
|
191
191
|
|
|
192
192
|
std::shared_ptr<jsi::Function> MethodMetadata::toJSFunction(
|
|
@@ -270,6 +270,9 @@ jsi::Value MethodMetadata::callSync(
|
|
|
270
270
|
if (env->IsInstanceOf(unpackedResult, cache->getJClass("java/lang/Integer").clazz)) {
|
|
271
271
|
return {jni::static_ref_cast<jni::JInteger>(result)->value()};
|
|
272
272
|
}
|
|
273
|
+
if (env->IsInstanceOf(unpackedResult, cache->getJClass("java/lang/Long").clazz)) {
|
|
274
|
+
return {(double) jni::static_ref_cast<jni::JLong>(result)->value()};
|
|
275
|
+
}
|
|
273
276
|
if (env->IsInstanceOf(unpackedResult, cache->getJClass("java/lang/String").clazz)) {
|
|
274
277
|
return jsi::String::createFromUtf8(
|
|
275
278
|
rt,
|
|
@@ -300,6 +303,14 @@ jsi::Value MethodMetadata::callSync(
|
|
|
300
303
|
->consume();
|
|
301
304
|
return jsi::valueFromDynamic(rt, dynamic);
|
|
302
305
|
}
|
|
306
|
+
if (env->IsInstanceOf(unpackedResult, JavaScriptModuleObject::javaClassStatic().get())) {
|
|
307
|
+
auto anonymousObject = jni::static_ref_cast<JavaScriptModuleObject::javaobject>(result)
|
|
308
|
+
->cthis();
|
|
309
|
+
anonymousObject->jsiInteropModuleRegistry = moduleRegistry;
|
|
310
|
+
auto hostObject = std::make_shared<JavaScriptModuleObject::HostObject>(anonymousObject);
|
|
311
|
+
hostObject->jObjectRef = jni::make_global(result);
|
|
312
|
+
return jsi::Object::createFromHostObject(rt, hostObject);
|
|
313
|
+
}
|
|
303
314
|
|
|
304
315
|
return jsi::Value::undefined();
|
|
305
316
|
}
|
|
@@ -11,16 +11,17 @@ enum CppType {
|
|
|
11
11
|
NONE = 0,
|
|
12
12
|
DOUBLE = 1 << 0,
|
|
13
13
|
INT = 1 << 1,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
14
|
+
LONG = 1 << 2,
|
|
15
|
+
FLOAT = 1 << 3,
|
|
16
|
+
BOOLEAN = 1 << 4,
|
|
17
|
+
STRING = 1 << 5,
|
|
18
|
+
JS_OBJECT = 1 << 6,
|
|
19
|
+
JS_VALUE = 1 << 7,
|
|
20
|
+
READABLE_ARRAY = 1 << 8,
|
|
21
|
+
READABLE_MAP = 1 << 9,
|
|
22
|
+
TYPED_ARRAY = 1 << 10,
|
|
23
|
+
PRIMITIVE_ARRAY = 1 << 11,
|
|
24
|
+
LIST = 1 << 12,
|
|
25
|
+
MAP = 1 << 13
|
|
25
26
|
};
|
|
26
27
|
} // namespace expo
|
|
@@ -40,6 +40,23 @@ bool IntegerFrontendConverter::canConvert(jsi::Runtime &rt, const jsi::Value &va
|
|
|
40
40
|
return value.isNumber();
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
jobject LongFrontendConverter::convert(
|
|
44
|
+
jsi::Runtime &rt,
|
|
45
|
+
JNIEnv *env,
|
|
46
|
+
JSIInteropModuleRegistry *moduleRegistry,
|
|
47
|
+
const jsi::Value &value
|
|
48
|
+
) const {
|
|
49
|
+
auto &longClass = JavaReferencesCache::instance()
|
|
50
|
+
->getJClass("java/lang/Long");
|
|
51
|
+
jmethodID longConstructor = longClass.getMethod("<init>", "(J)V");
|
|
52
|
+
return env->NewObject(longClass.clazz, longConstructor,
|
|
53
|
+
static_cast<jlong>(value.getNumber()));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
bool LongFrontendConverter::canConvert(jsi::Runtime &rt, const jsi::Value &value) const {
|
|
57
|
+
return value.isNumber();
|
|
58
|
+
}
|
|
59
|
+
|
|
43
60
|
jobject FloatFrontendConverter::convert(
|
|
44
61
|
jsi::Runtime &rt,
|
|
45
62
|
JNIEnv *env,
|
|
@@ -293,6 +310,12 @@ jobject PrimitiveArrayFrontendConverter::convert(
|
|
|
293
310
|
&JNIEnv::SetIntArrayRegion
|
|
294
311
|
);
|
|
295
312
|
}
|
|
313
|
+
if (parameterType == CppType::LONG) {
|
|
314
|
+
return _createPrimitiveArray(
|
|
315
|
+
&JNIEnv::NewLongArray,
|
|
316
|
+
&JNIEnv::SetLongArrayRegion
|
|
317
|
+
);
|
|
318
|
+
}
|
|
296
319
|
if (parameterType == CppType::DOUBLE) {
|
|
297
320
|
return _createPrimitiveArray(
|
|
298
321
|
&JNIEnv::NewDoubleArray,
|
|
@@ -55,6 +55,21 @@ public:
|
|
|
55
55
|
bool canConvert(jsi::Runtime &rt, const jsi::Value &value) const override;
|
|
56
56
|
};
|
|
57
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Converter from js number to [java.lang.Long].
|
|
60
|
+
*/
|
|
61
|
+
class LongFrontendConverter : public FrontendConverter {
|
|
62
|
+
public:
|
|
63
|
+
jobject convert(
|
|
64
|
+
jsi::Runtime &rt,
|
|
65
|
+
JNIEnv *env,
|
|
66
|
+
JSIInteropModuleRegistry *moduleRegistry,
|
|
67
|
+
const jsi::Value &value
|
|
68
|
+
) const override;
|
|
69
|
+
|
|
70
|
+
bool canConvert(jsi::Runtime &rt, const jsi::Value &value) const override;
|
|
71
|
+
};
|
|
72
|
+
|
|
58
73
|
/**
|
|
59
74
|
* Converter from js number to [java.lang.Float].
|
|
60
75
|
*/
|
|
@@ -12,6 +12,7 @@ void FrontendConverterProvider::createConverters() {
|
|
|
12
12
|
#define RegisterConverter(type, clazz) simpleConverters.insert({type, std::make_shared<clazz>()})
|
|
13
13
|
RegisterConverter(CppType::NONE, UnknownFrontendConverter);
|
|
14
14
|
RegisterConverter(CppType::INT, IntegerFrontendConverter);
|
|
15
|
+
RegisterConverter(CppType::LONG, LongFrontendConverter);
|
|
15
16
|
RegisterConverter(CppType::FLOAT, FloatFrontendConverter);
|
|
16
17
|
RegisterConverter(CppType::DOUBLE, DoubleFrontendConverter);
|
|
17
18
|
RegisterConverter(CppType::BOOLEAN, BooleanFrontendConverter);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package expo.modules.kotlin
|
|
2
2
|
|
|
3
3
|
import com.facebook.react.bridge.Dynamic
|
|
4
|
+
import com.facebook.react.bridge.DynamicFromObject
|
|
4
5
|
|
|
5
6
|
inline fun <T> Dynamic.recycle(block: Dynamic.() -> T): T {
|
|
6
7
|
try {
|
|
@@ -9,3 +10,5 @@ inline fun <T> Dynamic.recycle(block: Dynamic.() -> T): T {
|
|
|
9
10
|
this.recycle()
|
|
10
11
|
}
|
|
11
12
|
}
|
|
13
|
+
|
|
14
|
+
val DynamicNull = DynamicFromObject(null)
|
|
@@ -85,8 +85,14 @@ internal class MissingTypeConverter(
|
|
|
85
85
|
message = "Cannot find type converter for '$forType'.",
|
|
86
86
|
)
|
|
87
87
|
|
|
88
|
-
internal class InvalidArgsNumberException(received: Int, expected: Int) :
|
|
89
|
-
CodedException(
|
|
88
|
+
internal class InvalidArgsNumberException(received: Int, expected: Int, required: Int = expected) :
|
|
89
|
+
CodedException(
|
|
90
|
+
message = if (required < expected) {
|
|
91
|
+
"Received $received arguments, but $expected was expected and at least $required is required"
|
|
92
|
+
} else {
|
|
93
|
+
"Received $received arguments, but $expected was expected"
|
|
94
|
+
}
|
|
95
|
+
)
|
|
90
96
|
|
|
91
97
|
internal class MethodNotFoundException :
|
|
92
98
|
CodedException(message = "Method does not exist.")
|
|
@@ -22,6 +22,20 @@ abstract class AnyFunction(
|
|
|
22
22
|
) {
|
|
23
23
|
internal val argsCount get() = desiredArgsTypes.size
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* A minimum number of arguments the functions needs which equals to `argumentsCount` reduced by the number of trailing optional arguments.
|
|
27
|
+
*/
|
|
28
|
+
internal val requiredArgumentsCount = run {
|
|
29
|
+
val nonNullableArgIndex = desiredArgsTypes
|
|
30
|
+
.reversed()
|
|
31
|
+
.indexOfFirst { !it.kType.isMarkedNullable }
|
|
32
|
+
if (nonNullableArgIndex < 0) {
|
|
33
|
+
return@run desiredArgsTypes.size
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return@run desiredArgsTypes.size - nonNullableArgIndex
|
|
37
|
+
}
|
|
38
|
+
|
|
25
39
|
/**
|
|
26
40
|
* Tries to convert arguments from RN representation to expected types.
|
|
27
41
|
*
|
|
@@ -30,23 +44,22 @@ abstract class AnyFunction(
|
|
|
30
44
|
*/
|
|
31
45
|
@Throws(CodedException::class)
|
|
32
46
|
protected fun convertArgs(args: ReadableArray): Array<out Any?> {
|
|
33
|
-
if (
|
|
34
|
-
throw InvalidArgsNumberException(args.size(), desiredArgsTypes.size)
|
|
47
|
+
if (requiredArgumentsCount > args.size() || args.size() > desiredArgsTypes.size) {
|
|
48
|
+
throw InvalidArgsNumberException(args.size(), desiredArgsTypes.size, requiredArgumentsCount)
|
|
35
49
|
}
|
|
36
50
|
|
|
37
51
|
val finalArgs = Array<Any?>(desiredArgsTypes.size) { null }
|
|
38
52
|
val argIterator = args.iterator()
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
finalArgs[index] = desiredType.convert(this)
|
|
47
|
-
}
|
|
53
|
+
for (index in 0 until args.size()) {
|
|
54
|
+
val desiredType = desiredArgsTypes[index]
|
|
55
|
+
argIterator.next().recycle {
|
|
56
|
+
exceptionDecorator({ cause ->
|
|
57
|
+
ArgumentCastException(desiredType.kType, index, type, cause)
|
|
58
|
+
}) {
|
|
59
|
+
finalArgs[index] = desiredType.convert(this)
|
|
48
60
|
}
|
|
49
61
|
}
|
|
62
|
+
}
|
|
50
63
|
return finalArgs
|
|
51
64
|
}
|
|
52
65
|
|
|
@@ -58,30 +71,28 @@ abstract class AnyFunction(
|
|
|
58
71
|
*/
|
|
59
72
|
@Throws(CodedException::class)
|
|
60
73
|
protected fun convertArgs(args: Array<Any?>): Array<out Any?> {
|
|
61
|
-
if (
|
|
62
|
-
throw InvalidArgsNumberException(args.size, desiredArgsTypes.size)
|
|
74
|
+
if (requiredArgumentsCount > args.size || args.size > desiredArgsTypes.size) {
|
|
75
|
+
throw InvalidArgsNumberException(args.size, desiredArgsTypes.size, requiredArgumentsCount)
|
|
63
76
|
}
|
|
64
77
|
|
|
65
78
|
val finalArgs = Array<Any?>(desiredArgsTypes.size) { null }
|
|
66
79
|
val argIterator = args.iterator()
|
|
67
|
-
|
|
68
|
-
.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}) {
|
|
75
|
-
finalArgs[index] = desiredType.convert(element)
|
|
76
|
-
}
|
|
80
|
+
for (index in args.indices) {
|
|
81
|
+
val element = argIterator.next()
|
|
82
|
+
val desiredType = desiredArgsTypes[index]
|
|
83
|
+
exceptionDecorator({ cause ->
|
|
84
|
+
ArgumentCastException(desiredType.kType, index, ReadableType.String, cause)
|
|
85
|
+
}) {
|
|
86
|
+
finalArgs[index] = desiredType.convert(element)
|
|
77
87
|
}
|
|
88
|
+
}
|
|
78
89
|
return finalArgs
|
|
79
90
|
}
|
|
80
91
|
|
|
81
92
|
/**
|
|
82
93
|
* Attaches current function to the provided js object.
|
|
83
94
|
*/
|
|
84
|
-
|
|
95
|
+
abstract fun attachToJSObject(appContext: AppContext, jsObject: JavaScriptModuleObject)
|
|
85
96
|
|
|
86
97
|
fun getCppRequiredTypes(): List<ExpectedType> {
|
|
87
98
|
return desiredArgsTypes.map { it.getCppRequiredTypes() }
|