expo-modules-core 1.2.1 β 1.2.3
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 +14 -0
- package/android/build.gradle +2 -2
- package/android/src/main/java/expo/modules/kotlin/views/ViewDefinitionBuilder.kt +26 -2
- package/ios/AppDelegates/EXAppDelegateWrapper.mm +1 -1
- package/ios/Swift/Arguments/Convertibles.swift +4 -5
- package/ios/Swift/Utilities.swift +32 -0
- package/ios/Tests/ConvertiblesSpec.swift +86 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,20 @@
|
|
|
10
10
|
|
|
11
11
|
### π‘ Others
|
|
12
12
|
|
|
13
|
+
## 1.2.3 β 2023-02-21
|
|
14
|
+
|
|
15
|
+
### π Bug fixes
|
|
16
|
+
|
|
17
|
+
- [iOS] Fixed URI with encoded `#` getting cut off. ([#21326](https://github.com/expo/expo/pull/21326) by [@lukmccall](https://github.com/lukmccall))
|
|
18
|
+
- [Android] Fail gracefully when the view cannot be constructed due to the missing activity. ([#21328](https://github.com/expo/expo/pull/21328) by [@lukmccall](https://github.com/lukmccall))
|
|
19
|
+
|
|
20
|
+
## 1.2.2 β 2023-02-14
|
|
21
|
+
|
|
22
|
+
### π Bug fixes
|
|
23
|
+
|
|
24
|
+
- [iOS] Fixed convertible implementation for `URL` type to support unencoded UTF8 urls and file paths. ([#21139](https://github.com/expo/expo/pull/21139) by [@tsapeta](https://github.com/tsapeta))
|
|
25
|
+
- Fixed AppDelegateSubscriber broken when running on iOS dynamic framework or static framework mode. ([#21206](https://github.com/expo/expo/pull/21206) by [@kudo](https://github.com/kudo))
|
|
26
|
+
|
|
13
27
|
## 1.2.1 β 2023-02-09
|
|
14
28
|
|
|
15
29
|
### π Bug fixes
|
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.2.
|
|
9
|
+
version = '1.2.3'
|
|
10
10
|
|
|
11
11
|
buildscript {
|
|
12
12
|
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
|
|
@@ -173,7 +173,7 @@ android {
|
|
|
173
173
|
targetSdkVersion safeExtGet("targetSdkVersion", 33)
|
|
174
174
|
consumerProguardFiles 'proguard-rules.pro'
|
|
175
175
|
versionCode 1
|
|
176
|
-
versionName "1.2.
|
|
176
|
+
versionName "1.2.3"
|
|
177
177
|
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled.toString()
|
|
178
178
|
|
|
179
179
|
testInstrumentationRunner "expo.modules.TestRunner"
|
|
@@ -4,9 +4,12 @@
|
|
|
4
4
|
package expo.modules.kotlin.views
|
|
5
5
|
|
|
6
6
|
import android.content.Context
|
|
7
|
+
import android.util.Log
|
|
7
8
|
import android.view.View
|
|
8
9
|
import android.view.ViewGroup
|
|
9
10
|
import expo.modules.kotlin.AppContext
|
|
11
|
+
import expo.modules.kotlin.exception.CodedException
|
|
12
|
+
import expo.modules.kotlin.exception.UnexpectedException
|
|
10
13
|
import expo.modules.kotlin.modules.DefinitionMarker
|
|
11
14
|
import expo.modules.kotlin.types.toAnyType
|
|
12
15
|
import kotlin.reflect.KClass
|
|
@@ -147,7 +150,11 @@ class ViewDefinitionBuilder<T : View>(@PublishedApi internal val viewType: KClas
|
|
|
147
150
|
|
|
148
151
|
// Backward compatibility
|
|
149
152
|
if (args.size == 1) {
|
|
150
|
-
return@viewFactory
|
|
153
|
+
return@viewFactory try {
|
|
154
|
+
primaryConstructor.call(context)
|
|
155
|
+
} catch (e: Throwable) {
|
|
156
|
+
handleFailureDuringViewCreation(context, appContext, e)
|
|
157
|
+
}
|
|
151
158
|
}
|
|
152
159
|
|
|
153
160
|
val secondArgType = args[1].type
|
|
@@ -159,7 +166,24 @@ class ViewDefinitionBuilder<T : View>(@PublishedApi internal val viewType: KClas
|
|
|
159
166
|
throw IllegalStateException("Android view has more constructor arguments than expected.")
|
|
160
167
|
}
|
|
161
168
|
|
|
162
|
-
return@viewFactory
|
|
169
|
+
return@viewFactory try {
|
|
170
|
+
primaryConstructor.call(context, appContext)
|
|
171
|
+
} catch (e: Throwable) {
|
|
172
|
+
handleFailureDuringViewCreation(context, appContext, e)
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
private fun handleFailureDuringViewCreation(context: Context, appContext: AppContext, e: Throwable): View {
|
|
177
|
+
Log.e("ExpoModulesCore", "Couldn't create view of type $viewType", e)
|
|
178
|
+
|
|
179
|
+
appContext.errorManager?.reportExceptionToLogBox(
|
|
180
|
+
if (e is CodedException) {
|
|
181
|
+
e
|
|
182
|
+
} else {
|
|
183
|
+
UnexpectedException(e)
|
|
184
|
+
}
|
|
185
|
+
)
|
|
186
|
+
return View(context)
|
|
163
187
|
}
|
|
164
188
|
|
|
165
189
|
private fun getPrimaryConstructor(): KFunction<T>? {
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
return _expoAppDelegate;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
#if __has_include(<React-RCTAppDelegate/RCTAppDelegate.h>)
|
|
45
|
+
#if __has_include(<React-RCTAppDelegate/RCTAppDelegate.h>) || __has_include(<React_RCTAppDelegate/RCTAppDelegate.h>)
|
|
46
46
|
|
|
47
47
|
- (UIView *)findRootView:(UIApplication *)application
|
|
48
48
|
{
|
|
@@ -13,11 +13,10 @@ import CoreGraphics
|
|
|
13
13
|
|
|
14
14
|
extension URL: Convertible {
|
|
15
15
|
public static func convert(from value: Any?) throws -> Self {
|
|
16
|
-
if let
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
|
|
20
|
-
return url.scheme != nil ? url : URL(fileURLWithPath: uri)
|
|
16
|
+
if let value = value as? String, let encodedValue = percentEncodeUrlString(value), let url = URL(string: encodedValue) {
|
|
17
|
+
// If it has no scheme, we assume it was the file path which needs to be recreated to be recognized as the file url.
|
|
18
|
+
// Notice that it uses the decoded value as the file path doesn't have to be percent-encoded.
|
|
19
|
+
return url.scheme != nil ? url : URL(fileURLWithPath: value)
|
|
21
20
|
}
|
|
22
21
|
throw Conversions.ConvertingException<URL>(value)
|
|
23
22
|
}
|
|
@@ -26,3 +26,35 @@ internal func toNSError(_ error: Error) -> NSError {
|
|
|
26
26
|
}
|
|
27
27
|
return error as NSError
|
|
28
28
|
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
Makes sure the url string is percent encoded. If the given string is already encoded, it's decoded first.
|
|
32
|
+
Note that it encodes only characters that are not allowed in the url query and '#' that indicates the fragment part.
|
|
33
|
+
*/
|
|
34
|
+
internal func percentEncodeUrlString(_ url: String) -> String? {
|
|
35
|
+
// URL contains '#' so it has a fragment part.
|
|
36
|
+
// We know that because that is the only allowed use case of the undecoded '#' symbol inside of the URL.
|
|
37
|
+
if url.contains("#") {
|
|
38
|
+
let urlParts = url.split(separator: "#")
|
|
39
|
+
|
|
40
|
+
// Encodes the url without the fragment part. It'll leave the fragment part untounched.
|
|
41
|
+
guard let parsed = percentEncodeUrlStringWithoutFragment(String(urlParts[0])) else {
|
|
42
|
+
return nil
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Concatenate encoded path with fragment.
|
|
46
|
+
return parsed + "#" + urlParts[1]
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return percentEncodeUrlStringWithoutFragment(url)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private func percentEncodeUrlStringWithoutFragment(_ url: String) -> String? {
|
|
53
|
+
// The value may come unencoded or already encoded, so first we try to decode it.
|
|
54
|
+
// `removingPercentEncoding` returns nil when the string contains an invalid percent-encoded sequence,
|
|
55
|
+
// but that usually means the value came unencoded, so it falls back to the given string.
|
|
56
|
+
let decodedString = url.removingPercentEncoding ?? url
|
|
57
|
+
|
|
58
|
+
// Do the percent encoding, but note that it may still return nil when it's not possible to encode for some reason.
|
|
59
|
+
return decodedString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)
|
|
60
|
+
}
|
|
@@ -16,6 +16,73 @@ class ConvertiblesSpec: ExpoSpec {
|
|
|
16
16
|
expect(url.absoluteString) == remoteUrlString
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
it("converts from url with unencoded query") {
|
|
20
|
+
let query = "param=π₯"
|
|
21
|
+
let urlString = "https://expo.dev/?\(query)"
|
|
22
|
+
let url = try URL.convert(from: urlString)
|
|
23
|
+
|
|
24
|
+
if #available(iOS 16.0, *) {
|
|
25
|
+
expect(url.query(percentEncoded: true)) == "param=%F0%9F%A5%93"
|
|
26
|
+
expect(url.query(percentEncoded: false)) == query
|
|
27
|
+
}
|
|
28
|
+
expect(url.query) == "param=%F0%9F%A5%93"
|
|
29
|
+
expect(url.absoluteString) == "https://expo.dev/?param=%F0%9F%A5%93"
|
|
30
|
+
expect(url.absoluteString.removingPercentEncoding) == urlString
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
it("converts from url with encoded query") {
|
|
34
|
+
let query = "param=%F0%9F%A5%93"
|
|
35
|
+
let urlString = "https://expo.dev/?\(query)"
|
|
36
|
+
let url = try URL.convert(from: urlString)
|
|
37
|
+
|
|
38
|
+
if #available(iOS 16.0, *) {
|
|
39
|
+
expect(url.query(percentEncoded: true)) == query
|
|
40
|
+
expect(url.query(percentEncoded: false)) == "param=π₯"
|
|
41
|
+
}
|
|
42
|
+
expect(url.query) == query
|
|
43
|
+
expect(url.absoluteString) == urlString
|
|
44
|
+
expect(url.absoluteString.removingPercentEncoding) == "https://expo.dev/?param=π₯"
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
it("converts from url with encoded query containg the anchor") {
|
|
48
|
+
let query = "color=%230000ff"
|
|
49
|
+
let urlString = "https://expo.dev/?\(query)#anchor"
|
|
50
|
+
let url = try URL.convert(from: urlString)
|
|
51
|
+
|
|
52
|
+
expect(url.query) == query
|
|
53
|
+
expect(url.absoluteString) == urlString
|
|
54
|
+
expect(url.absoluteString.removingPercentEncoding) == "https://expo.dev/?color=#0000ff#anchor"
|
|
55
|
+
expect(url.fragment) == "anchor"
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
it("converts from url containing percent character") {
|
|
59
|
+
// The percent character alone requires percent-encoding to `%25`.
|
|
60
|
+
let query = "param=%"
|
|
61
|
+
let urlString = "https://expo.dev/?\(query)"
|
|
62
|
+
let url = try URL.convert(from: urlString)
|
|
63
|
+
|
|
64
|
+
if #available(iOS 16.0, *) {
|
|
65
|
+
expect(url.query(percentEncoded: true)) == "param=%25"
|
|
66
|
+
expect(url.query(percentEncoded: false)) == query
|
|
67
|
+
}
|
|
68
|
+
expect(url.query) == "param=%25"
|
|
69
|
+
expect(url.absoluteString) == "https://expo.dev/?param=%25"
|
|
70
|
+
expect(url.absoluteString.removingPercentEncoding) == urlString
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
it("converts from url containing the anchor") {
|
|
74
|
+
// The hash is not allowed in the query (requires percent-encoding),
|
|
75
|
+
// but we want it to be recognized as the beginning of the fragment,
|
|
76
|
+
// thus it cannot be percent-encoded.
|
|
77
|
+
let query = "param=#expo"
|
|
78
|
+
let urlString = "https://expo.dev/?\(query)"
|
|
79
|
+
let url = try URL.convert(from: urlString)
|
|
80
|
+
|
|
81
|
+
expect(url.query) == "param="
|
|
82
|
+
expect(url.fragment) == "expo"
|
|
83
|
+
expect(url.absoluteString) == urlString
|
|
84
|
+
}
|
|
85
|
+
|
|
19
86
|
it("converts from file url") {
|
|
20
87
|
let fileUrlString = "file:///expo/tmp"
|
|
21
88
|
let url = try URL.convert(from: fileUrlString)
|
|
@@ -29,11 +96,30 @@ class ConvertiblesSpec: ExpoSpec {
|
|
|
29
96
|
let filePath = "/expo/image.png"
|
|
30
97
|
let url = try URL.convert(from: filePath)
|
|
31
98
|
|
|
99
|
+
expect(url.scheme) == "file"
|
|
32
100
|
expect(url.path) == filePath
|
|
33
101
|
expect(url.absoluteString) == "file://\(filePath)"
|
|
34
102
|
expect(url.isFileURL) == true
|
|
35
103
|
}
|
|
36
104
|
|
|
105
|
+
it("converts from file path with UTF8 characters") {
|
|
106
|
+
let filePath = "/δΈζΓ
ΓΓΔ
ΓΕΔΓ±.gif"
|
|
107
|
+
let url = try URL.convert(from: filePath)
|
|
108
|
+
|
|
109
|
+
expect(url.scheme) == "file"
|
|
110
|
+
expect(url.path) == filePath
|
|
111
|
+
expect(url.isFileURL) == true
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
it("converts from file path containing percent character") {
|
|
115
|
+
let filePath = "/%.png"
|
|
116
|
+
let url = try URL.convert(from: filePath)
|
|
117
|
+
|
|
118
|
+
expect(url.scheme) == "file"
|
|
119
|
+
expect(url.path) == filePath
|
|
120
|
+
expect(url.isFileURL) == true
|
|
121
|
+
}
|
|
122
|
+
|
|
37
123
|
it("throws when no string") {
|
|
38
124
|
expect { try URL.convert(from: 29.5) }.to(
|
|
39
125
|
throwError(errorType: Conversions.ConvertingException<URL>.self)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-modules-core",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.3",
|
|
4
4
|
"description": "The core of Expo Modules architecture",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -42,5 +42,5 @@
|
|
|
42
42
|
"@testing-library/react-hooks": "^7.0.1",
|
|
43
43
|
"expo-module-scripts": "^3.0.0"
|
|
44
44
|
},
|
|
45
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "40dcd1732b69f09798a28691f6b17b820a2bbbf5"
|
|
46
46
|
}
|