expo-modules-core 3.0.5 → 3.0.6
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 +6 -0
- package/android/build.gradle +2 -2
- package/android/src/main/cpp/JavaReferencesCache.cpp +9 -0
- package/android/src/main/cpp/JavaReferencesCache.h +4 -0
- package/android/src/main/cpp/types/CppType.h +1 -0
- package/android/src/main/cpp/types/FrontendConverter.cpp +28 -0
- package/android/src/main/cpp/types/FrontendConverter.h +17 -0
- package/android/src/main/cpp/types/FrontendConverterProvider.cpp +4 -0
- package/android/src/main/java/expo/modules/kotlin/jni/CppType.kt +3 -1
- package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +4 -0
- package/android/src/main/java/expo/modules/kotlin/types/ValueOrUndefined.kt +25 -0
- package/android/src/main/java/expo/modules/kotlin/types/ValueOrUndefinedTypeConverter.kt +38 -0
- package/ios/Core/Views/SwiftUI/SwiftUIVirtualViewObjC.mm +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,12 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 3.0.6 — 2025-08-25
|
|
14
|
+
|
|
15
|
+
### 🎉 New features
|
|
16
|
+
|
|
17
|
+
- [Android] Add new type - `ValueOrUndefined`. ([#39116](https://github.com/expo/expo/pull/39116) by [@lukmccall](https://github.com/lukmccall))
|
|
18
|
+
|
|
13
19
|
## 3.0.5 — 2025-08-21
|
|
14
20
|
|
|
15
21
|
_This version does not introduce any user-facing changes._
|
package/android/build.gradle
CHANGED
|
@@ -25,7 +25,7 @@ if (shouldIncludeCompose) {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
group = 'host.exp.exponent'
|
|
28
|
-
version = '3.0.
|
|
28
|
+
version = '3.0.6'
|
|
29
29
|
|
|
30
30
|
def isExpoModulesCoreTests = {
|
|
31
31
|
Gradle gradle = getGradle()
|
|
@@ -75,7 +75,7 @@ android {
|
|
|
75
75
|
defaultConfig {
|
|
76
76
|
consumerProguardFiles 'proguard-rules.pro'
|
|
77
77
|
versionCode 1
|
|
78
|
-
versionName "3.0.
|
|
78
|
+
versionName "3.0.6"
|
|
79
79
|
buildConfigField "String", "EXPO_MODULES_CORE_VERSION", "\"${versionName}\""
|
|
80
80
|
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled.toString()
|
|
81
81
|
|
|
@@ -54,6 +54,8 @@ JCache::JCache(JNIEnv *env) {
|
|
|
54
54
|
jJavaScriptModuleObject = REGISTER_CLASS("expo/modules/kotlin/jni/JavaScriptModuleObject");
|
|
55
55
|
|
|
56
56
|
#undef REGISTER_CLASS
|
|
57
|
+
|
|
58
|
+
jUndefined = getJUndefined(env);
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
std::shared_ptr<JCache> JCacheHolder::jCache = nullptr;
|
|
@@ -106,4 +108,11 @@ void JCache::unLoad(JNIEnv *env) {
|
|
|
106
108
|
env->DeleteGlobalRef(jJavaScriptModuleObject);
|
|
107
109
|
}
|
|
108
110
|
|
|
111
|
+
jobject JCache::getJUndefined(JNIEnv *env) {
|
|
112
|
+
jclass clazz = env->FindClass("expo/modules/kotlin/types/ValueOrUndefined");
|
|
113
|
+
jmethodID methodId = env->GetStaticMethodID(clazz, "getUndefined", "()Ljava/lang/Object;");
|
|
114
|
+
return env->NewGlobalRef(
|
|
115
|
+
env->CallStaticObjectMethod(clazz, methodId)
|
|
116
|
+
);
|
|
117
|
+
}
|
|
109
118
|
} // namespace expo
|
|
@@ -57,8 +57,12 @@ public:
|
|
|
57
57
|
jclass jSharedObject;
|
|
58
58
|
jclass jJavaScriptModuleObject;
|
|
59
59
|
|
|
60
|
+
jobject jUndefined;
|
|
61
|
+
|
|
60
62
|
void unLoad(JNIEnv *env);
|
|
61
63
|
private:
|
|
64
|
+
static jobject getJUndefined(JNIEnv *env);
|
|
65
|
+
|
|
62
66
|
std::unordered_map<std::string, jclass> jClassRegistry;
|
|
63
67
|
};
|
|
64
68
|
|
|
@@ -648,4 +648,32 @@ jobject NullableFrontendConverter::convert(
|
|
|
648
648
|
return parameterConverter->convert(rt, env, value);
|
|
649
649
|
}
|
|
650
650
|
|
|
651
|
+
ValueOrUndefinedFrontendConverter::ValueOrUndefinedFrontendConverter(
|
|
652
|
+
jni::local_ref<SingleType::javaobject> expectedType
|
|
653
|
+
) : parameterConverter(
|
|
654
|
+
FrontendConverterProvider::instance()->obtainConverter(
|
|
655
|
+
expectedType->getFirstParameterType()
|
|
656
|
+
)
|
|
657
|
+
) {}
|
|
658
|
+
|
|
659
|
+
bool ValueOrUndefinedFrontendConverter::canConvert(
|
|
660
|
+
jsi::Runtime &rt,
|
|
661
|
+
const jsi::Value &value
|
|
662
|
+
) const {
|
|
663
|
+
return value.isUndefined() ||
|
|
664
|
+
parameterConverter->canConvert(rt, value);
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
jobject ValueOrUndefinedFrontendConverter::convert(
|
|
668
|
+
jsi::Runtime &rt,
|
|
669
|
+
JNIEnv *env,
|
|
670
|
+
const jsi::Value &value
|
|
671
|
+
) const {
|
|
672
|
+
if (value.isUndefined()) {
|
|
673
|
+
return env->NewLocalRef(JCacheHolder::get().jUndefined);
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
return parameterConverter->convert(rt, env, value);
|
|
677
|
+
}
|
|
678
|
+
|
|
651
679
|
} // namespace expo
|
|
@@ -438,4 +438,21 @@ public:
|
|
|
438
438
|
private:
|
|
439
439
|
std::shared_ptr<FrontendConverter> parameterConverter;
|
|
440
440
|
};
|
|
441
|
+
|
|
442
|
+
class ValueOrUndefinedFrontendConverter : public FrontendConverter {
|
|
443
|
+
public:
|
|
444
|
+
ValueOrUndefinedFrontendConverter(
|
|
445
|
+
jni::local_ref<jni::JavaClass<SingleType>::javaobject> expectedType
|
|
446
|
+
);
|
|
447
|
+
|
|
448
|
+
jobject convert(
|
|
449
|
+
jsi::Runtime &rt,
|
|
450
|
+
JNIEnv *env,
|
|
451
|
+
const jsi::Value &value
|
|
452
|
+
) const override;
|
|
453
|
+
|
|
454
|
+
bool canConvert(jsi::Runtime &rt, const jsi::Value &value) const override;
|
|
455
|
+
private:
|
|
456
|
+
std::shared_ptr<FrontendConverter> parameterConverter;
|
|
457
|
+
};
|
|
441
458
|
} // namespace expo
|
|
@@ -74,6 +74,10 @@ std::shared_ptr<FrontendConverter> FrontendConverterProvider::obtainConverter(
|
|
|
74
74
|
return std::make_shared<MapFrontendConverter>(expectedType->getFirstType());
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
if (combinedType == CppType::VALUE_OR_UNDEFINED) {
|
|
78
|
+
return std::make_shared<ValueOrUndefinedFrontendConverter>(expectedType->getFirstType());
|
|
79
|
+
}
|
|
80
|
+
|
|
77
81
|
std::vector<std::shared_ptr<FrontendConverter>> converters;
|
|
78
82
|
auto singleTypes = expectedType->getPossibleTypes();
|
|
79
83
|
size_t size = singleTypes->size();
|
|
@@ -3,6 +3,7 @@ package expo.modules.kotlin.jni
|
|
|
3
3
|
import com.facebook.react.bridge.ReadableArray
|
|
4
4
|
import com.facebook.react.bridge.ReadableMap
|
|
5
5
|
import expo.modules.kotlin.typedarray.TypedArray
|
|
6
|
+
import expo.modules.kotlin.types.ValueOrUndefined
|
|
6
7
|
import kotlin.reflect.KClass
|
|
7
8
|
|
|
8
9
|
private var nextValue = 0
|
|
@@ -34,5 +35,6 @@ enum class CppType(val clazz: KClass<*>, val value: Int = nextValue()) {
|
|
|
34
35
|
SHARED_OBJECT_ID(Int::class),
|
|
35
36
|
JS_FUNCTION(JavaScriptFunction::class),
|
|
36
37
|
ANY(Any::class),
|
|
37
|
-
NULLABLE(Any::class)
|
|
38
|
+
NULLABLE(Any::class),
|
|
39
|
+
VALUE_OR_UNDEFINED(ValueOrUndefined::class)
|
|
38
40
|
}
|
|
@@ -159,6 +159,10 @@ object TypeConverterProviderImpl : TypeConverterProvider {
|
|
|
159
159
|
return JavaScriptFunctionTypeConverter<Any>(type)
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
+
if (ValueOrUndefined::class.java.isAssignableFrom(jClass)) {
|
|
163
|
+
return ValueOrUndefinedTypeConverter(this, type)
|
|
164
|
+
}
|
|
165
|
+
|
|
162
166
|
return handelEither(type, jClass)
|
|
163
167
|
?: throw MissingTypeConverter(type)
|
|
164
168
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
package expo.modules.kotlin.types
|
|
2
|
+
|
|
3
|
+
import expo.modules.core.interfaces.DoNotStrip
|
|
4
|
+
|
|
5
|
+
@DoNotStrip
|
|
6
|
+
sealed interface ValueOrUndefined<T> {
|
|
7
|
+
val isUndefined: Boolean
|
|
8
|
+
get() = this is Undefined
|
|
9
|
+
|
|
10
|
+
val optional: T?
|
|
11
|
+
get() = when (this) {
|
|
12
|
+
is Value -> value
|
|
13
|
+
is Undefined -> null
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
data class Value<T>(val value: T) : ValueOrUndefined<T>
|
|
17
|
+
object Undefined : ValueOrUndefined<Nothing>
|
|
18
|
+
|
|
19
|
+
companion object {
|
|
20
|
+
// helper function that can be used from C++ to get the instance of Undefined
|
|
21
|
+
@JvmStatic
|
|
22
|
+
@DoNotStrip
|
|
23
|
+
fun getUndefined(): Any = Undefined
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
package expo.modules.kotlin.types
|
|
2
|
+
|
|
3
|
+
import expo.modules.kotlin.AppContext
|
|
4
|
+
import expo.modules.kotlin.jni.CppType
|
|
5
|
+
import expo.modules.kotlin.jni.ExpectedType
|
|
6
|
+
import expo.modules.kotlin.jni.SingleType
|
|
7
|
+
import kotlin.reflect.KType
|
|
8
|
+
|
|
9
|
+
class ValueOrUndefinedTypeConverter(
|
|
10
|
+
converterProvider: TypeConverterProvider,
|
|
11
|
+
innerType: KType
|
|
12
|
+
) : TypeConverter<ValueOrUndefined<*>> {
|
|
13
|
+
private val innerTypeConverter = converterProvider.obtainTypeConverter(
|
|
14
|
+
requireNotNull(innerType.arguments.first().type) {
|
|
15
|
+
"The ValueOrUndefined type should contain the argument type."
|
|
16
|
+
}
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
override fun convert(value: Any?, context: AppContext?, forceConversion: Boolean): ValueOrUndefined<*>? {
|
|
20
|
+
return if (value is ValueOrUndefined.Undefined) {
|
|
21
|
+
ValueOrUndefined.Undefined
|
|
22
|
+
} else {
|
|
23
|
+
val converterValue = innerTypeConverter.convert(value, context)
|
|
24
|
+
ValueOrUndefined.Value(converterValue)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
override fun getCppRequiredTypes(): ExpectedType {
|
|
29
|
+
return ExpectedType(
|
|
30
|
+
SingleType(
|
|
31
|
+
CppType.VALUE_OR_UNDEFINED,
|
|
32
|
+
arrayOf(innerTypeConverter.getCppRequiredTypes())
|
|
33
|
+
)
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
override fun isTrivial() = false
|
|
38
|
+
}
|
|
@@ -181,7 +181,7 @@ static std::unordered_map<std::string, expo::ExpoViewComponentDescriptor::Flavor
|
|
|
181
181
|
// when a VirtualView inserted to a standard UIView.
|
|
182
182
|
// We use this call point here for sanity check.
|
|
183
183
|
@throw [NSException exceptionWithName:@"SwiftUIVirtualViewException"
|
|
184
|
-
reason:@"A SwiftUI view is inserted as a child of a standard UIView.
|
|
184
|
+
reason:@"A SwiftUI view is inserted as a child of a standard UIView. Double check that in JSX you have wrapped your component with `<Host>` from '@expo/ui/swift-ui'."
|
|
185
185
|
userInfo:nil];
|
|
186
186
|
return NO;
|
|
187
187
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-modules-core",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.6",
|
|
4
4
|
"description": "The core of Expo Modules architecture",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@testing-library/react-native": "^13.2.0",
|
|
50
|
-
"expo-module-scripts": "^5.0.
|
|
50
|
+
"expo-module-scripts": "^5.0.3"
|
|
51
51
|
},
|
|
52
|
-
"gitHead": "
|
|
52
|
+
"gitHead": "ef0b9ecf9645d3e93587d5ee5030dbfcbf735bbd"
|
|
53
53
|
}
|