expo-modules-core 3.0.19 → 3.0.20
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 +7 -0
- package/android/build.gradle +2 -2
- package/build/hooks/useReleasingSharedObject.d.ts.map +1 -1
- package/ios/JSI/EXJSIConversions.h +2 -0
- package/ios/JSI/EXJSIConversions.mm +9 -0
- package/ios/Tests/FunctionSpec.swift +67 -4
- package/package.json +2 -2
- package/src/hooks/useReleasingSharedObject.ts +5 -3
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,13 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 3.0.20 — 2025-10-01
|
|
14
|
+
|
|
15
|
+
### 🐛 Bug fixes
|
|
16
|
+
|
|
17
|
+
- [iOS] Fix NSURL to JSIString conversion returning nil. ([#39567](https://github.com/expo/expo/pull/39567) by [@behenate](https://github.com/behenate))
|
|
18
|
+
- Fix SharedObject created with `useReleasingSharedObject` getting destroyed after a fast refresh caused by a change in its dependencies. ([#39753](https://github.com/expo/expo/pull/39753) by [@behenate](https://github.com/behenate))
|
|
19
|
+
|
|
13
20
|
## 3.0.19 — 2025-10-01
|
|
14
21
|
|
|
15
22
|
### 💡 Others
|
package/android/build.gradle
CHANGED
|
@@ -29,7 +29,7 @@ if (shouldIncludeCompose) {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
group = 'host.exp.exponent'
|
|
32
|
-
version = '3.0.
|
|
32
|
+
version = '3.0.20'
|
|
33
33
|
|
|
34
34
|
def isExpoModulesCoreTests = {
|
|
35
35
|
Gradle gradle = getGradle()
|
|
@@ -79,7 +79,7 @@ android {
|
|
|
79
79
|
defaultConfig {
|
|
80
80
|
consumerProguardFiles 'proguard-rules.pro'
|
|
81
81
|
versionCode 1
|
|
82
|
-
versionName "3.0.
|
|
82
|
+
versionName "3.0.20"
|
|
83
83
|
buildConfigField "String", "EXPO_MODULES_CORE_VERSION", "\"${versionName}\""
|
|
84
84
|
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled.toString()
|
|
85
85
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useReleasingSharedObject.d.ts","sourceRoot":"","sources":["../../src/hooks/useReleasingSharedObject.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAA8B,MAAM,OAAO,CAAC;AAEnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAEpE;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,aAAa,SAAS,YAAY,EACzE,OAAO,EAAE,MAAM,aAAa,EAC5B,YAAY,EAAE,cAAc,GAC3B,aAAa,
|
|
1
|
+
{"version":3,"file":"useReleasingSharedObject.d.ts","sourceRoot":"","sources":["../../src/hooks/useReleasingSharedObject.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAA8B,MAAM,OAAO,CAAC;AAEnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAEpE;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,aAAa,SAAS,YAAY,EACzE,OAAO,EAAE,MAAM,aAAa,EAC5B,YAAY,EAAE,cAAc,GAC3B,aAAa,CA0Cf"}
|
|
@@ -24,6 +24,8 @@ namespace expo
|
|
|
24
24
|
|
|
25
25
|
jsi::String convertNSStringToJSIString(jsi::Runtime &runtime, NSString *value);
|
|
26
26
|
|
|
27
|
+
jsi::String convertNSURLToJSIString(jsi::Runtime &runtime, NSURL *value);
|
|
28
|
+
|
|
27
29
|
jsi::Object convertNSDictionaryToJSIObject(jsi::Runtime &runtime, NSDictionary *value);
|
|
28
30
|
|
|
29
31
|
jsi::Array convertNSArrayToJSIArray(jsi::Runtime &runtime, NSArray *value);
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
#import <ExpoModulesCore/EXJavaScriptRuntime.h>
|
|
10
10
|
#import <ExpoModulesCore/EXJavaScriptSharedObjectBinding.h>
|
|
11
11
|
#import <ExpoModulesCore/EXStringUtils.h>
|
|
12
|
+
#import <Foundation/NSURL.h>
|
|
12
13
|
|
|
13
14
|
namespace expo {
|
|
14
15
|
|
|
@@ -41,6 +42,12 @@ jsi::String convertNSStringToJSIString(jsi::Runtime &runtime, NSString *value)
|
|
|
41
42
|
#endif
|
|
42
43
|
}
|
|
43
44
|
|
|
45
|
+
jsi::String convertNSURLToJSIString(jsi::Runtime &runtime, NSURL *value)
|
|
46
|
+
{
|
|
47
|
+
NSString *stringValue = [value absoluteString];
|
|
48
|
+
return convertNSStringToJSIString(runtime, stringValue);
|
|
49
|
+
}
|
|
50
|
+
|
|
44
51
|
jsi::Object convertNSDictionaryToJSIObject(jsi::Runtime &runtime, NSDictionary *value)
|
|
45
52
|
{
|
|
46
53
|
jsi::Object result = jsi::Object(runtime);
|
|
@@ -107,6 +114,8 @@ jsi::Value convertObjCObjectToJSIValue(jsi::Runtime &runtime, id value)
|
|
|
107
114
|
return convertNSArrayToJSIArray(runtime, (NSArray *)value);
|
|
108
115
|
} else if ([value isKindOfClass:[NSData class]]) {
|
|
109
116
|
return createUint8Array(runtime, (NSData *)value);
|
|
117
|
+
} else if ([value isKindOfClass:[NSURL class]]) {
|
|
118
|
+
return convertNSURLToJSIString(runtime, (NSURL *)value);
|
|
110
119
|
} else if (value == (id)kCFNull) {
|
|
111
120
|
return jsi::Value::null();
|
|
112
121
|
}
|
|
@@ -245,6 +245,17 @@ class FunctionSpec: ExpoSpec {
|
|
|
245
245
|
@Field var property: String = "expo"
|
|
246
246
|
}
|
|
247
247
|
|
|
248
|
+
struct TestURLRecord: Record {
|
|
249
|
+
static let defaultURLString = "https://expo.dev"
|
|
250
|
+
static let defaultURL = URL(string: defaultURLString)!
|
|
251
|
+
|
|
252
|
+
@Field var url: URL = defaultURL
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
afterEach {
|
|
256
|
+
try runtime.eval("globalThis.result = undefined")
|
|
257
|
+
}
|
|
258
|
+
|
|
248
259
|
beforeSuite {
|
|
249
260
|
appContext.moduleRegistry.register(holder: mockModuleHolder(appContext) {
|
|
250
261
|
Name("TestModule")
|
|
@@ -286,10 +297,18 @@ class FunctionSpec: ExpoSpec {
|
|
|
286
297
|
return "\(f.property)"
|
|
287
298
|
}
|
|
288
299
|
|
|
300
|
+
Function("withURL") {
|
|
301
|
+
return TestURLRecord.defaultURL
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
Function("withNestedURL") {
|
|
305
|
+
return TestURLRecord()
|
|
306
|
+
}
|
|
307
|
+
|
|
289
308
|
Function("withOptionalRecord") { (f: TestRecord?) in
|
|
290
309
|
return "\(f?.property ?? "no value")"
|
|
291
310
|
}
|
|
292
|
-
|
|
311
|
+
|
|
293
312
|
Function("withSharedObject") {
|
|
294
313
|
return SharedString("Test")
|
|
295
314
|
}
|
|
@@ -305,7 +324,15 @@ class FunctionSpec: ExpoSpec {
|
|
|
305
324
|
AsyncFunction("withSharedObjectPromise") { (p: Promise) in
|
|
306
325
|
p.resolve(SharedString("Test with Promise"))
|
|
307
326
|
}
|
|
308
|
-
|
|
327
|
+
|
|
328
|
+
AsyncFunction("withURLAsync") {
|
|
329
|
+
return TestURLRecord.defaultURL
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
AsyncFunction("withNestedURLAsync") {
|
|
333
|
+
return TestURLRecord()
|
|
334
|
+
}
|
|
335
|
+
|
|
309
336
|
Class("Shared", SharedString.self) {
|
|
310
337
|
Property("value") { shared in
|
|
311
338
|
return shared.ref
|
|
@@ -360,7 +387,43 @@ class FunctionSpec: ExpoSpec {
|
|
|
360
387
|
it("accepts optional record") {
|
|
361
388
|
expect(try runtime.eval("expo.modules.TestModule.withOptionalRecord({property: \"123\"})").asString()) == "123"
|
|
362
389
|
}
|
|
363
|
-
|
|
390
|
+
|
|
391
|
+
it("returns URL (sync)") {
|
|
392
|
+
let result = try runtime.eval("globalThis.result = expo.modules.TestModule.withURL()")
|
|
393
|
+
expect(result.kind) == .string
|
|
394
|
+
expect(result.getString()) == TestURLRecord.defaultURLString
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
it("returns URL (async)") {
|
|
398
|
+
try runtime.eval("expo.modules.TestModule.withURLAsync().then((result) => { globalThis.result = result; })")
|
|
399
|
+
expect(safeBoolEval("!!globalThis.result")).toEventually(beTrue(), timeout: .milliseconds(2000))
|
|
400
|
+
|
|
401
|
+
let urlValue = try runtime.eval("url = globalThis.result")
|
|
402
|
+
expect(urlValue.kind) == .string
|
|
403
|
+
expect(urlValue.getString()) == TestURLRecord.defaultURLString
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
it("returns a record wit url (sync)") {
|
|
407
|
+
let object = try runtime.eval("globalThis.result = expo.modules.TestModule.withNestedURL()")
|
|
408
|
+
expect(object.kind) == .object
|
|
409
|
+
expect(object.getObject().hasProperty("url")) == true
|
|
410
|
+
expect(object.getObject().getProperty("url").getString()) == TestURLRecord.defaultURLString
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
it("returns a record with url (async)") {
|
|
414
|
+
try runtime.eval("expo.modules.TestModule.withNestedURLAsync().then((result) => { globalThis.result = result; })")
|
|
415
|
+
|
|
416
|
+
expect(safeBoolEval("!!globalThis.result.url")).toEventually(beTrue(), timeout: .milliseconds(2000))
|
|
417
|
+
|
|
418
|
+
let object = try runtime.eval("object = globalThis.result")
|
|
419
|
+
expect(object.kind) == .object
|
|
420
|
+
expect(object.getObject().hasProperty("url")) == true
|
|
421
|
+
|
|
422
|
+
let urlValue = try runtime.eval("object.url")
|
|
423
|
+
expect(urlValue.kind) == .string
|
|
424
|
+
expect(urlValue.getString()) == TestURLRecord.defaultURLString
|
|
425
|
+
}
|
|
426
|
+
|
|
364
427
|
it("returns a SharedObject (sync)") {
|
|
365
428
|
let object = try runtime.eval("expo.modules.TestModule.withSharedObject()")
|
|
366
429
|
|
|
@@ -385,7 +448,7 @@ class FunctionSpec: ExpoSpec {
|
|
|
385
448
|
expect(result.kind) == .string
|
|
386
449
|
expect(result.getString()) == "Test"
|
|
387
450
|
}
|
|
388
|
-
|
|
451
|
+
|
|
389
452
|
it("returns an Array of SharedObjects (async)") {
|
|
390
453
|
try runtime
|
|
391
454
|
.eval(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-modules-core",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.20",
|
|
4
4
|
"description": "The core of Expo Modules architecture",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -65,5 +65,5 @@
|
|
|
65
65
|
"@testing-library/react-native": "^13.2.0",
|
|
66
66
|
"expo-module-scripts": "^5.0.7"
|
|
67
67
|
},
|
|
68
|
-
"gitHead": "
|
|
68
|
+
"gitHead": "73d9bc0ee4f1e28cfda349dc36ee53d16fad0c5d"
|
|
69
69
|
}
|
|
@@ -26,18 +26,20 @@ export function useReleasingSharedObject<TSharedObject extends SharedObject>(
|
|
|
26
26
|
dependencies.every((value, index) => value === previousDependencies.current[index]);
|
|
27
27
|
|
|
28
28
|
// If the dependencies have changed, release the previous object and create a new one, otherwise this has been called
|
|
29
|
-
// because of
|
|
29
|
+
// because of an unrelated fast refresh, and we don't want to release the object.
|
|
30
30
|
if (!newObject || !dependenciesAreEqual) {
|
|
31
31
|
objectRef.current?.release();
|
|
32
32
|
newObject = factory();
|
|
33
33
|
objectRef.current = newObject;
|
|
34
34
|
previousDependencies.current = dependencies;
|
|
35
|
-
} else {
|
|
36
|
-
isFastRefresh.current = true;
|
|
37
35
|
}
|
|
38
36
|
return newObject;
|
|
39
37
|
}, dependencies);
|
|
40
38
|
|
|
39
|
+
useMemo(() => {
|
|
40
|
+
isFastRefresh.current = true;
|
|
41
|
+
}, []);
|
|
42
|
+
|
|
41
43
|
useEffect(() => {
|
|
42
44
|
isFastRefresh.current = false;
|
|
43
45
|
|