expo-modules-core 1.11.3 → 1.11.4
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 +5 -0
- package/android/build.gradle +2 -2
- package/android/src/main/cpp/JavaScriptObject.cpp +11 -1
- package/android/src/main/cpp/JavaScriptObject.h +5 -1
- package/android/src/main/cpp/JavaScriptWeakObject.cpp +49 -0
- package/android/src/main/cpp/JavaScriptWeakObject.h +52 -0
- package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptObject.kt +2 -0
- package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptWeakObject.kt +22 -0
- package/android/src/main/java/expo/modules/kotlin/sharedobjects/SharedObject.kt +5 -0
- package/android/src/main/java/expo/modules/kotlin/sharedobjects/SharedObjectRegistry.kt +18 -10
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -10,12 +10,17 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 1.11.4 — 2023-12-21
|
|
14
|
+
|
|
15
|
+
_This version does not introduce any user-facing changes._
|
|
16
|
+
|
|
13
17
|
## 1.11.3 — 2023-12-19
|
|
14
18
|
|
|
15
19
|
### 🐛 Bug fixes
|
|
16
20
|
|
|
17
21
|
- [iOS] Fixed `SharedObjectRegistry` crash for accessing internal data structures from multi-threads. ([#25997](https://github.com/expo/expo/pull/25997) by [@kudo](https://github.com/kudo))
|
|
18
22
|
- Fixed splash screen view flickering in dark mode on iOS. ([#26015](https://github.com/expo/expo/pull/26015), [#26029](https://github.com/expo/expo/pull/26029) by [@kudo](https://github.com/kudo))
|
|
23
|
+
- Fixed `SharedObject` leakage on Android. ([#25995](https://github.com/expo/expo/pull/25995) by [@kudo](https://github.com/kudo))
|
|
19
24
|
|
|
20
25
|
## 1.11.2 — 2023-12-15
|
|
21
26
|
|
package/android/build.gradle
CHANGED
|
@@ -5,7 +5,7 @@ apply plugin: 'kotlin-android'
|
|
|
5
5
|
apply plugin: 'maven-publish'
|
|
6
6
|
|
|
7
7
|
group = 'host.exp.exponent'
|
|
8
|
-
version = '1.11.
|
|
8
|
+
version = '1.11.4'
|
|
9
9
|
|
|
10
10
|
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
|
|
11
11
|
if (expoModulesCorePlugin.exists()) {
|
|
@@ -143,7 +143,7 @@ android {
|
|
|
143
143
|
defaultConfig {
|
|
144
144
|
consumerProguardFiles 'proguard-rules.pro'
|
|
145
145
|
versionCode 1
|
|
146
|
-
versionName "1.11.
|
|
146
|
+
versionName "1.11.4"
|
|
147
147
|
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled.toString()
|
|
148
148
|
|
|
149
149
|
testInstrumentationRunner "expo.modules.TestRunner"
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
#include "JavaScriptValue.h"
|
|
5
5
|
#include "JavaScriptFunction.h"
|
|
6
6
|
#include "JavaScriptRuntime.h"
|
|
7
|
+
#include "JavaScriptWeakObject.h"
|
|
7
8
|
#include "JSITypeConverter.h"
|
|
8
9
|
#include "ObjectDeallocator.h"
|
|
9
10
|
#include "JavaReferencesCache.h"
|
|
@@ -15,6 +16,7 @@ void JavaScriptObject::registerNatives() {
|
|
|
15
16
|
makeNativeMethod("hasProperty", JavaScriptObject::jniHasProperty),
|
|
16
17
|
makeNativeMethod("getProperty", JavaScriptObject::jniGetProperty),
|
|
17
18
|
makeNativeMethod("getPropertyNames", JavaScriptObject::jniGetPropertyNames),
|
|
19
|
+
makeNativeMethod("createWeak", JavaScriptObject::createWeak),
|
|
18
20
|
makeNativeMethod("setBoolProperty", JavaScriptObject::setProperty<bool>),
|
|
19
21
|
makeNativeMethod("setDoubleProperty", JavaScriptObject::setProperty<double>),
|
|
20
22
|
makeNativeMethod("setStringProperty",
|
|
@@ -109,6 +111,14 @@ jni::local_ref<jni::JArrayClass<jstring>> JavaScriptObject::jniGetPropertyNames(
|
|
|
109
111
|
return paredResult;
|
|
110
112
|
}
|
|
111
113
|
|
|
114
|
+
jni::local_ref<jni::HybridClass<JavaScriptWeakObject, Destructible>::javaobject> JavaScriptObject::createWeak() {
|
|
115
|
+
return JavaScriptWeakObject::newInstance(
|
|
116
|
+
runtimeHolder.getModuleRegistry(),
|
|
117
|
+
runtimeHolder,
|
|
118
|
+
get()
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
112
122
|
jni::local_ref<JavaScriptFunction::javaobject> JavaScriptObject::jniAsFunction() {
|
|
113
123
|
auto &jsRuntime = runtimeHolder.getJSRuntime();
|
|
114
124
|
auto jsFuncion = std::make_shared<jsi::Function>(jsObject->asFunction(jsRuntime));
|
|
@@ -167,7 +177,7 @@ void JavaScriptObject::defineNativeDeallocator(
|
|
|
167
177
|
rt,
|
|
168
178
|
jsObject,
|
|
169
179
|
[globalRef = std::move(globalRef)]() mutable {
|
|
170
|
-
auto args = jni::Environment::
|
|
180
|
+
auto args = jni::Environment::ensureCurrentThreadIsAttached()->NewObjectArray(
|
|
171
181
|
0,
|
|
172
182
|
JavaReferencesCache::instance()->getJClass("java/lang/Object").clazz,
|
|
173
183
|
nullptr
|
|
@@ -19,9 +19,11 @@ namespace jni = facebook::jni;
|
|
|
19
19
|
namespace jsi = facebook::jsi;
|
|
20
20
|
|
|
21
21
|
namespace expo {
|
|
22
|
-
class JavaScriptValue;
|
|
23
22
|
|
|
24
23
|
class JavaScriptFunction;
|
|
24
|
+
class JavaScriptValue;
|
|
25
|
+
class JavaScriptWeakObject;
|
|
26
|
+
|
|
25
27
|
|
|
26
28
|
/**
|
|
27
29
|
* Represents any JavaScript object. Its purpose is to exposes `jsi::Object` API back to Kotlin.
|
|
@@ -91,6 +93,8 @@ private:
|
|
|
91
93
|
|
|
92
94
|
jni::local_ref<jni::JArrayClass<jstring>> jniGetPropertyNames();
|
|
93
95
|
|
|
96
|
+
jni::local_ref<jni::HybridClass<JavaScriptWeakObject, Destructible>::javaobject> createWeak();
|
|
97
|
+
|
|
94
98
|
jni::local_ref<jni::HybridClass<JavaScriptFunction, Destructible>::javaobject> jniAsFunction();
|
|
95
99
|
|
|
96
100
|
/**
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// Copyright 2015-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
#include "JavaScriptWeakObject.h"
|
|
4
|
+
#include "JSIInteropModuleRegistry.h"
|
|
5
|
+
|
|
6
|
+
namespace expo {
|
|
7
|
+
|
|
8
|
+
void JavaScriptWeakObject::registerNatives() {
|
|
9
|
+
registerHybrid({
|
|
10
|
+
makeNativeMethod("lock", JavaScriptWeakObject::lock),
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
jni::local_ref<JavaScriptObject::javaobject> JavaScriptWeakObject::lock() {
|
|
15
|
+
jsi::Runtime &rt = _runtimeHolder.getJSRuntime();
|
|
16
|
+
|
|
17
|
+
jsi::Value value = _weakObject->lock(rt);
|
|
18
|
+
if (value.isUndefined()) {
|
|
19
|
+
return nullptr;
|
|
20
|
+
}
|
|
21
|
+
std::shared_ptr<jsi::Object> objectPtr =
|
|
22
|
+
std::make_shared<jsi::Object>(value.asObject(rt));
|
|
23
|
+
if (!objectPtr) {
|
|
24
|
+
return nullptr;
|
|
25
|
+
}
|
|
26
|
+
return JavaScriptObject::newInstance(_runtimeHolder.getModuleRegistry(),
|
|
27
|
+
_runtimeHolder, objectPtr);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
jni::local_ref<jni::HybridClass<JavaScriptWeakObject, Destructible>::javaobject>
|
|
31
|
+
JavaScriptWeakObject::newInstance(
|
|
32
|
+
JSIInteropModuleRegistry *jsiInteropModuleRegistry,
|
|
33
|
+
std::weak_ptr<JavaScriptRuntime> runtime,
|
|
34
|
+
std::shared_ptr<jsi::Object> jsObject) {
|
|
35
|
+
auto weakObject = JavaScriptWeakObject::newObjectCxxArgs(std::move(runtime),
|
|
36
|
+
std::move(jsObject));
|
|
37
|
+
jsiInteropModuleRegistry->jniDeallocator->addReference(weakObject);
|
|
38
|
+
return weakObject;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
JavaScriptWeakObject::JavaScriptWeakObject(
|
|
42
|
+
WeakRuntimeHolder runtime, std::shared_ptr<jsi::Object> jsObject)
|
|
43
|
+
: _runtimeHolder(std::move(runtime)) {
|
|
44
|
+
_runtimeHolder.ensureRuntimeIsValid();
|
|
45
|
+
jsi::Runtime &rt = _runtimeHolder.getJSRuntime();
|
|
46
|
+
_weakObject = std::make_shared<jsi::WeakObject>(rt, *jsObject);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
} // namespace expo
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Copyright 2015-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
#pragma once
|
|
4
|
+
|
|
5
|
+
#include "JNIDeallocator.h"
|
|
6
|
+
#include "JavaScriptObject.h"
|
|
7
|
+
#include "WeakRuntimeHolder.h"
|
|
8
|
+
|
|
9
|
+
#include <fbjni/fbjni.h>
|
|
10
|
+
#include <jsi/jsi.h>
|
|
11
|
+
|
|
12
|
+
#include <memory>
|
|
13
|
+
|
|
14
|
+
namespace jni = facebook::jni;
|
|
15
|
+
namespace jsi = facebook::jsi;
|
|
16
|
+
|
|
17
|
+
namespace expo {
|
|
18
|
+
|
|
19
|
+
class JavaScriptObject;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Represents to a jsi::WeakObject.
|
|
23
|
+
*/
|
|
24
|
+
class JavaScriptWeakObject
|
|
25
|
+
: public jni::HybridClass<JavaScriptWeakObject, Destructible> {
|
|
26
|
+
public:
|
|
27
|
+
static auto constexpr kJavaDescriptor =
|
|
28
|
+
"Lexpo/modules/kotlin/jni/JavaScriptWeakObject;";
|
|
29
|
+
static auto constexpr TAG = "JavaScriptWeakObject";
|
|
30
|
+
|
|
31
|
+
static void registerNatives();
|
|
32
|
+
|
|
33
|
+
static jni::local_ref<
|
|
34
|
+
jni::HybridClass<JavaScriptWeakObject, Destructible>::javaobject>
|
|
35
|
+
newInstance(JSIInteropModuleRegistry *jsiInteropModuleRegistry,
|
|
36
|
+
std::weak_ptr<JavaScriptRuntime> runtime,
|
|
37
|
+
std::shared_ptr<jsi::Object> jsObject);
|
|
38
|
+
|
|
39
|
+
jni::local_ref<JavaScriptObject::javaobject> lock();
|
|
40
|
+
|
|
41
|
+
private:
|
|
42
|
+
JavaScriptWeakObject(WeakRuntimeHolder runtime,
|
|
43
|
+
std::shared_ptr<jsi::Object> jsObject);
|
|
44
|
+
|
|
45
|
+
private:
|
|
46
|
+
friend HybridBase;
|
|
47
|
+
|
|
48
|
+
WeakRuntimeHolder _runtimeHolder;
|
|
49
|
+
std::shared_ptr<jsi::WeakObject> _weakObject;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
} // namespace expo
|
|
@@ -43,6 +43,8 @@ open class JavaScriptObject @DoNotStrip internal constructor(@DoNotStrip private
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
external fun getPropertyNames(): Array<String>
|
|
46
|
+
external fun createWeak(): JavaScriptWeakObject
|
|
47
|
+
|
|
46
48
|
private external fun setBoolProperty(name: String, value: Boolean)
|
|
47
49
|
private external fun setDoubleProperty(name: String, value: Double)
|
|
48
50
|
private external fun setStringProperty(name: String, value: String?)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
package expo.modules.kotlin.jni
|
|
2
|
+
|
|
3
|
+
import com.facebook.jni.HybridData
|
|
4
|
+
import expo.modules.core.interfaces.DoNotStrip
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A Kotlin representation to a jsi::WeakObject
|
|
8
|
+
* Should be used only on the runtime thread.
|
|
9
|
+
*/
|
|
10
|
+
@Suppress("KotlinJniMissingFunction")
|
|
11
|
+
@DoNotStrip
|
|
12
|
+
class JavaScriptWeakObject @DoNotStrip internal constructor(@DoNotStrip private val mHybridData: HybridData) : Destructible {
|
|
13
|
+
@Throws(Throwable::class)
|
|
14
|
+
protected fun finalize() {
|
|
15
|
+
deallocate()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
override fun deallocate() {
|
|
19
|
+
mHybridData.resetNative()
|
|
20
|
+
}
|
|
21
|
+
external fun lock(): JavaScriptObject
|
|
22
|
+
}
|
|
@@ -9,4 +9,9 @@ open class SharedObject {
|
|
|
9
9
|
* When the object is not linked with any JavaScript object, its value is 0.
|
|
10
10
|
*/
|
|
11
11
|
internal var sharedObjectId: SharedObjectId = SharedObjectId(0)
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Called when the shared object being deallocated.
|
|
15
|
+
*/
|
|
16
|
+
open fun deallocate() {}
|
|
12
17
|
}
|
|
@@ -2,6 +2,7 @@ package expo.modules.kotlin.sharedobjects
|
|
|
2
2
|
|
|
3
3
|
import expo.modules.kotlin.AppContext
|
|
4
4
|
import expo.modules.kotlin.jni.JavaScriptObject
|
|
5
|
+
import expo.modules.kotlin.jni.JavaScriptWeakObject
|
|
5
6
|
|
|
6
7
|
@JvmInline
|
|
7
8
|
value class SharedObjectId(val value: Int) {
|
|
@@ -15,8 +16,7 @@ value class SharedObjectId(val value: Int) {
|
|
|
15
16
|
}
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
typealias SharedObjectPair = Pair<SharedObject, JavaScriptObject>
|
|
19
|
+
typealias SharedObjectPair = Pair<SharedObject, JavaScriptWeakObject>
|
|
20
20
|
|
|
21
21
|
const val sharedObjectIdPropertyName = "__expo_shared_object_id__"
|
|
22
22
|
|
|
@@ -25,7 +25,7 @@ class SharedObjectRegistry {
|
|
|
25
25
|
|
|
26
26
|
internal var pairs = mutableMapOf<SharedObjectId, SharedObjectPair>()
|
|
27
27
|
|
|
28
|
-
private fun pullNextId(): SharedObjectId {
|
|
28
|
+
private fun pullNextId(): SharedObjectId = synchronized(this) {
|
|
29
29
|
val current = currentId
|
|
30
30
|
currentId = SharedObjectId(current.value + 1)
|
|
31
31
|
return current
|
|
@@ -40,21 +40,27 @@ class SharedObjectRegistry {
|
|
|
40
40
|
delete(id)
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
val jsWeakObject = js.createWeak()
|
|
44
|
+
synchronized(this) {
|
|
45
|
+
pairs[id] = native to jsWeakObject
|
|
46
|
+
}
|
|
44
47
|
return id
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
internal fun delete(id: SharedObjectId) {
|
|
48
|
-
|
|
51
|
+
val removedObject: SharedObjectPair? = synchronized(this) {
|
|
52
|
+
return@synchronized pairs.remove(id)
|
|
53
|
+
}
|
|
54
|
+
removedObject?.let { (native, js) ->
|
|
49
55
|
native.sharedObjectId = SharedObjectId(0)
|
|
50
|
-
|
|
51
|
-
js.defineProperty(sharedObjectIdPropertyName, 0)
|
|
52
|
-
}
|
|
56
|
+
native.deallocate()
|
|
53
57
|
}
|
|
54
58
|
}
|
|
55
59
|
|
|
56
60
|
internal fun toNativeObject(id: SharedObjectId): SharedObject? {
|
|
57
|
-
return
|
|
61
|
+
return synchronized(this) {
|
|
62
|
+
pairs[id]?.first
|
|
63
|
+
}
|
|
58
64
|
}
|
|
59
65
|
|
|
60
66
|
internal fun toNativeObject(js: JavaScriptObject): SharedObject? {
|
|
@@ -67,6 +73,8 @@ class SharedObjectRegistry {
|
|
|
67
73
|
}
|
|
68
74
|
|
|
69
75
|
internal fun toJavaScriptObject(native: SharedObject): JavaScriptObject? {
|
|
70
|
-
return
|
|
76
|
+
return synchronized(this) {
|
|
77
|
+
pairs[native.sharedObjectId]?.second?.lock()
|
|
78
|
+
}
|
|
71
79
|
}
|
|
72
80
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-modules-core",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.4",
|
|
4
4
|
"description": "The core of Expo Modules architecture",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -44,5 +44,5 @@
|
|
|
44
44
|
"@testing-library/react-hooks": "^7.0.1",
|
|
45
45
|
"expo-module-scripts": "^3.0.0"
|
|
46
46
|
},
|
|
47
|
-
"gitHead": "
|
|
47
|
+
"gitHead": "36402c8b2bc9b63f003c04642d97bf091b35fe16"
|
|
48
48
|
}
|