expo-modules-core 1.3.2 → 1.4.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 +23 -0
- package/ExpoModulesCore.podspec +26 -5
- package/android/ExpoModulesCorePlugin.gradle +4 -0
- package/android/build.gradle +13 -14
- package/android/src/main/AndroidManifest.xml +1 -2
- package/android/src/main/cpp/ExpoModulesHostObject.cpp +3 -0
- package/android/src/main/cpp/JNIDeallocator.cpp +17 -0
- package/android/src/main/cpp/JNIDeallocator.h +25 -0
- package/android/src/main/cpp/JSIInteropModuleRegistry.cpp +8 -1
- package/android/src/main/cpp/JSIInteropModuleRegistry.h +6 -1
- package/android/src/main/cpp/JavaCallback.cpp +9 -0
- package/android/src/main/cpp/JavaCallback.h +12 -2
- package/android/src/main/cpp/JavaScriptFunction.cpp +13 -0
- package/android/src/main/cpp/JavaScriptFunction.h +7 -1
- package/android/src/main/cpp/JavaScriptModuleObject.cpp +2 -1
- package/android/src/main/cpp/JavaScriptObject.cpp +17 -2
- package/android/src/main/cpp/JavaScriptObject.h +10 -3
- package/android/src/main/cpp/JavaScriptRuntime.cpp +5 -4
- package/android/src/main/cpp/JavaScriptRuntime.h +5 -3
- package/android/src/main/cpp/JavaScriptTypedArray.cpp +14 -0
- package/android/src/main/cpp/JavaScriptTypedArray.h +6 -0
- package/android/src/main/cpp/JavaScriptValue.cpp +32 -4
- package/android/src/main/cpp/JavaScriptValue.h +10 -3
- package/android/src/main/cpp/MethodMetadata.cpp +1 -1
- package/android/src/main/cpp/types/FrontendConverter.cpp +8 -4
- package/android/src/main/java/expo/modules/core/interfaces/ReactActivityHandler.java +14 -0
- package/android/src/main/java/expo/modules/kotlin/AppContext.kt +4 -1
- package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +7 -3
- package/android/src/main/java/expo/modules/kotlin/ModuleRegistry.kt +19 -12
- package/android/src/main/java/expo/modules/kotlin/devtools/ExpoNetworkInspectOkHttpInterceptors.kt +70 -0
- package/android/src/main/java/expo/modules/kotlin/devtools/ExpoRequestCdpInterceptor.kt +72 -0
- package/android/src/main/java/expo/modules/kotlin/devtools/OkHttpHeadersExtension.kt +18 -0
- package/android/src/main/java/expo/modules/kotlin/devtools/cdp/CdpNetworkTypes.kt +257 -0
- package/android/src/main/java/expo/modules/kotlin/jni/JNIDeallocator.kt +24 -15
- package/android/src/main/java/expo/modules/kotlin/jni/JSIInteropModuleRegistry.kt +8 -1
- package/android/src/main/java/expo/modules/kotlin/jni/JavaCallback.kt +0 -4
- package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptFunction.kt +0 -4
- package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptModuleObject.kt +5 -2
- package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptObject.kt +0 -5
- package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptValue.kt +0 -4
- package/android/src/main/java/expo/modules/kotlin/objects/ObjectDefinitionBuilder.kt +1 -1
- package/android/src/main/java/expo/modules/kotlin/types/ColorTypeConverter.kt +3 -0
- package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +1 -2
- package/android-annotation/build.gradle +2 -2
- package/android-annotation-processor/build.gradle +2 -2
- package/ios/JSI/EXJSIInstaller.h +2 -2
- package/ios/JSI/EXJSIInstaller.mm +6 -6
- package/ios/JSI/EXJavaScriptRuntime.h +0 -6
- package/ios/JSI/EXJavaScriptRuntime.mm +0 -23
- package/ios/RCTComponentData+Privates.h +17 -0
- package/ios/RCTComponentData+Privates.m +15 -0
- package/ios/Swift/AppContext.swift +20 -11
- package/ios/Swift/DevTools/CdpNetworkTypes.swift +163 -0
- package/ios/Swift/DevTools/ExpoRequestCdpInterceptor.swift +71 -0
- package/ios/Swift/DevTools/ExpoRequestInterceptorProtocol.swift +183 -0
- package/ios/Swift/DevTools/URLRequest+httpBodyData.swift +43 -0
- package/ios/Swift/ExpoRuntime.swift +28 -0
- package/ios/Swift/Modules/CoreModule.swift +7 -0
- package/ios/Swift/SharedObjects/SharedRef.swift +12 -0
- package/ios/Swift/Views/ComponentData.swift +1 -1
- package/ios/Tests/CoreModuleSpec.swift +27 -0
- package/ios/Tests/ExpoRequestCdpInterceptorSpec.swift +165 -0
- package/ios/Tests/SharedRefSpec.swift +60 -0
- package/package.json +2 -2
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
// Copyright 2015-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
package expo.modules.kotlin.devtools.cdp
|
|
4
|
+
|
|
5
|
+
import expo.modules.kotlin.devtools.ExpoNetworkInspectOkHttpNetworkInterceptor
|
|
6
|
+
import expo.modules.kotlin.devtools.toSingleMap
|
|
7
|
+
import okio.Buffer
|
|
8
|
+
import org.json.JSONObject
|
|
9
|
+
import java.math.BigDecimal
|
|
10
|
+
|
|
11
|
+
//region Types
|
|
12
|
+
|
|
13
|
+
typealias Headers = Map<String, String>
|
|
14
|
+
typealias MonotonicTime = BigDecimal
|
|
15
|
+
typealias RequestId = String
|
|
16
|
+
typealias TimeSinceEpoch = BigDecimal
|
|
17
|
+
|
|
18
|
+
enum class ResourceType(val value: String) {
|
|
19
|
+
IMAGE("Image"),
|
|
20
|
+
MEDIA("Media"),
|
|
21
|
+
FONT("Font"),
|
|
22
|
+
SCRIPT("Script"),
|
|
23
|
+
FETCH("Fetch"),
|
|
24
|
+
OTHER("Other")
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface JsonSerializable {
|
|
28
|
+
fun toJSONObject(): JSONObject
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
data class ConnectTiming(val requestTime: MonotonicTime) : JsonSerializable {
|
|
32
|
+
override fun toJSONObject(): JSONObject {
|
|
33
|
+
return JSONObject().apply {
|
|
34
|
+
put("requestTime", requestTime)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
data class Request(
|
|
40
|
+
val url: String,
|
|
41
|
+
val method: String,
|
|
42
|
+
val headers: Headers,
|
|
43
|
+
val postData: String?
|
|
44
|
+
) : JsonSerializable {
|
|
45
|
+
constructor(request: okhttp3.Request) : this(
|
|
46
|
+
url = request.url.toString(),
|
|
47
|
+
method = request.method,
|
|
48
|
+
headers = request.headers.toSingleMap(),
|
|
49
|
+
postData = request.body?.let {
|
|
50
|
+
if (it.contentLength() < ExpoNetworkInspectOkHttpNetworkInterceptor.MAX_BODY_SIZE) {
|
|
51
|
+
val buffer = Buffer()
|
|
52
|
+
it.writeTo(buffer)
|
|
53
|
+
return@let buffer.readUtf8(buffer.size.coerceAtMost(ExpoNetworkInspectOkHttpNetworkInterceptor.MAX_BODY_SIZE))
|
|
54
|
+
} else return@let null
|
|
55
|
+
}
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
override fun toJSONObject(): JSONObject {
|
|
59
|
+
return JSONObject().apply {
|
|
60
|
+
put("url", url)
|
|
61
|
+
put("method", method)
|
|
62
|
+
put("headers", JSONObject(headers))
|
|
63
|
+
postData?.let {
|
|
64
|
+
put("postData", postData)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
data class Response(
|
|
71
|
+
val url: String,
|
|
72
|
+
val status: Int,
|
|
73
|
+
val statusText: String,
|
|
74
|
+
val headers: Headers,
|
|
75
|
+
val mimeType: String,
|
|
76
|
+
val encodedDataLength: Long
|
|
77
|
+
) : JsonSerializable {
|
|
78
|
+
constructor(response: okhttp3.Response) : this(
|
|
79
|
+
url = response.request.url.toString(),
|
|
80
|
+
status = response.code,
|
|
81
|
+
statusText = response.message,
|
|
82
|
+
headers = response.headers.toSingleMap(),
|
|
83
|
+
mimeType = response.header("Content-Type", "") ?: "",
|
|
84
|
+
encodedDataLength = response.body?.contentLength() ?: 0,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
override fun toJSONObject(): JSONObject {
|
|
88
|
+
return JSONObject().apply {
|
|
89
|
+
put("url", url)
|
|
90
|
+
put("status", status)
|
|
91
|
+
put("statusText", statusText)
|
|
92
|
+
put("headers", JSONObject(headers))
|
|
93
|
+
put("mimeType", mimeType)
|
|
94
|
+
put("encodedDataLength", encodedDataLength)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
//endregion Types
|
|
100
|
+
|
|
101
|
+
//region Events
|
|
102
|
+
|
|
103
|
+
data class RequestWillBeSentParams(
|
|
104
|
+
val requestId: RequestId,
|
|
105
|
+
val loaderId: String = "",
|
|
106
|
+
val documentURL: String = "mobile",
|
|
107
|
+
val request: Request,
|
|
108
|
+
val timestamp: MonotonicTime,
|
|
109
|
+
val wallTime: TimeSinceEpoch,
|
|
110
|
+
val initiator: Map<String, String> = mapOf("type" to "script"),
|
|
111
|
+
val redirectHasExtraInfo: Boolean,
|
|
112
|
+
val redirectResponse: Response?,
|
|
113
|
+
val referrerPolicy: String = "no-referrer",
|
|
114
|
+
val type: ResourceType,
|
|
115
|
+
) : JsonSerializable {
|
|
116
|
+
constructor(now: BigDecimal, requestId: RequestId, request: okhttp3.Request, redirectResponse: okhttp3.Response?) : this(
|
|
117
|
+
requestId = requestId,
|
|
118
|
+
request = Request(request),
|
|
119
|
+
timestamp = now,
|
|
120
|
+
wallTime = now,
|
|
121
|
+
redirectHasExtraInfo = redirectResponse != null,
|
|
122
|
+
redirectResponse = redirectResponse?.let { Response(it) },
|
|
123
|
+
type = ResourceType.FETCH,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
override fun toJSONObject(): JSONObject {
|
|
127
|
+
return JSONObject().apply {
|
|
128
|
+
put("requestId", requestId)
|
|
129
|
+
put("loaderId", loaderId)
|
|
130
|
+
put("documentURL", documentURL)
|
|
131
|
+
put("request", request.toJSONObject())
|
|
132
|
+
put("timestamp", timestamp)
|
|
133
|
+
put("wallTime", wallTime)
|
|
134
|
+
put("initiator", JSONObject(initiator))
|
|
135
|
+
put("redirectHasExtraInfo", redirectHasExtraInfo)
|
|
136
|
+
redirectResponse?.let {
|
|
137
|
+
put("redirectResponse", it.toJSONObject())
|
|
138
|
+
}
|
|
139
|
+
put("referrerPolicy", referrerPolicy)
|
|
140
|
+
put("type", type.value)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
data class RequestWillBeSentExtraInfoParams(
|
|
146
|
+
val requestId: RequestId,
|
|
147
|
+
val associatedCookies: Map<String, String> = emptyMap(),
|
|
148
|
+
val headers: Headers,
|
|
149
|
+
val connectTiming: ConnectTiming,
|
|
150
|
+
) : JsonSerializable {
|
|
151
|
+
constructor(now: BigDecimal, requestId: RequestId, request: okhttp3.Request) : this(
|
|
152
|
+
requestId = requestId,
|
|
153
|
+
headers = request.headers.toSingleMap(),
|
|
154
|
+
connectTiming = ConnectTiming(now),
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
override fun toJSONObject(): JSONObject {
|
|
158
|
+
return JSONObject().apply {
|
|
159
|
+
put("requestId", requestId)
|
|
160
|
+
put("associatedCookies", JSONObject(associatedCookies))
|
|
161
|
+
put("headers", JSONObject(headers))
|
|
162
|
+
put("connectTiming", connectTiming.toJSONObject())
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
data class ResponseReceivedParams(
|
|
168
|
+
val requestId: RequestId,
|
|
169
|
+
val loaderId: String = "",
|
|
170
|
+
val timestamp: MonotonicTime,
|
|
171
|
+
val type: ResourceType,
|
|
172
|
+
val response: Response,
|
|
173
|
+
val hasExtraInfo: Boolean = false,
|
|
174
|
+
) : JsonSerializable {
|
|
175
|
+
constructor(now: BigDecimal, requestId: RequestId, request: okhttp3.Request, repsonse: okhttp3.Response) : this(
|
|
176
|
+
requestId = requestId,
|
|
177
|
+
timestamp = now,
|
|
178
|
+
type = ResourceType.FETCH,
|
|
179
|
+
response = Response(repsonse),
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
override fun toJSONObject(): JSONObject {
|
|
183
|
+
return JSONObject().apply {
|
|
184
|
+
put("requestId", requestId)
|
|
185
|
+
put("loaderId", loaderId)
|
|
186
|
+
put("timestamp", timestamp)
|
|
187
|
+
put("type", type.value)
|
|
188
|
+
put("response", response.toJSONObject())
|
|
189
|
+
put("hasExtraInfo", hasExtraInfo)
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
data class LoadingFinishedParams(
|
|
195
|
+
val requestId: RequestId,
|
|
196
|
+
val timestamp: MonotonicTime,
|
|
197
|
+
val encodedDataLength: Long,
|
|
198
|
+
) : JsonSerializable {
|
|
199
|
+
constructor(now: BigDecimal, requestId: RequestId, request: okhttp3.Request, repsonse: okhttp3.Response) : this(
|
|
200
|
+
requestId = requestId,
|
|
201
|
+
timestamp = now,
|
|
202
|
+
encodedDataLength = repsonse.body?.contentLength() ?: 0,
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
override fun toJSONObject(): JSONObject {
|
|
206
|
+
return JSONObject().apply {
|
|
207
|
+
put("requestId", requestId)
|
|
208
|
+
put("timestamp", timestamp)
|
|
209
|
+
put("encodedDataLength", encodedDataLength)
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
data class ExpoReceivedResponseBodyParams(
|
|
215
|
+
val requestId: RequestId,
|
|
216
|
+
var body: String,
|
|
217
|
+
var base64Encoded: Boolean,
|
|
218
|
+
) : JsonSerializable {
|
|
219
|
+
constructor(now: BigDecimal, requestId: RequestId, request: okhttp3.Request, response: okhttp3.Response) : this(
|
|
220
|
+
requestId = requestId,
|
|
221
|
+
body = "",
|
|
222
|
+
base64Encoded = false,
|
|
223
|
+
) {
|
|
224
|
+
val contentLength = response.body?.contentLength() ?: 0
|
|
225
|
+
check(contentLength >= 0 && contentLength <= ExpoNetworkInspectOkHttpNetworkInterceptor.MAX_BODY_SIZE)
|
|
226
|
+
val rawBody = response.peekBody(ExpoNetworkInspectOkHttpNetworkInterceptor.MAX_BODY_SIZE)
|
|
227
|
+
val contentType = rawBody.contentType()
|
|
228
|
+
val isText = contentType?.type == "text" || (contentType?.type == "application" && contentType.subtype == "json")
|
|
229
|
+
val bodyString = if (isText) rawBody.string() else rawBody.source().readByteString().base64()
|
|
230
|
+
|
|
231
|
+
this.body = bodyString
|
|
232
|
+
this.base64Encoded = !isText
|
|
233
|
+
}
|
|
234
|
+
override fun toJSONObject(): JSONObject {
|
|
235
|
+
return JSONObject().apply {
|
|
236
|
+
put("requestId", requestId)
|
|
237
|
+
put("body", body)
|
|
238
|
+
put("base64Encoded", base64Encoded)
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
//endregion Events
|
|
244
|
+
|
|
245
|
+
typealias EventParams = JsonSerializable
|
|
246
|
+
|
|
247
|
+
data class Event(
|
|
248
|
+
val method: String,
|
|
249
|
+
val params: EventParams
|
|
250
|
+
) {
|
|
251
|
+
fun toJson(): String {
|
|
252
|
+
return JSONObject().apply {
|
|
253
|
+
put("method", method)
|
|
254
|
+
put("params", params.toJSONObject())
|
|
255
|
+
}.toString()
|
|
256
|
+
}
|
|
257
|
+
}
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
package expo.modules.kotlin.jni
|
|
2
2
|
|
|
3
|
+
import expo.modules.core.interfaces.DoNotStrip
|
|
3
4
|
import java.lang.ref.PhantomReference
|
|
4
5
|
import java.lang.ref.ReferenceQueue
|
|
5
6
|
import java.lang.ref.WeakReference
|
|
6
7
|
|
|
8
|
+
@DoNotStrip
|
|
7
9
|
interface Destructible {
|
|
8
10
|
fun deallocate()
|
|
9
11
|
}
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
@DoNotStrip
|
|
14
|
+
class JNIDeallocator(private val shouldCreateDestructorThread: Boolean = true) {
|
|
12
15
|
/**
|
|
13
16
|
* A [PhantomReference] queue managed by JVM
|
|
14
17
|
*/
|
|
@@ -23,23 +26,27 @@ object JNIDeallocator {
|
|
|
23
26
|
* A thread that clears your registry when an object has been garbage collected
|
|
24
27
|
* to not store invalid references to every created object.
|
|
25
28
|
*/
|
|
26
|
-
private val destructorThread =
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
29
|
+
private val destructorThread = if (shouldCreateDestructorThread) {
|
|
30
|
+
object : Thread("Expo JNI deallocator") {
|
|
31
|
+
override fun run() {
|
|
32
|
+
while (!isInterrupted) {
|
|
33
|
+
try {
|
|
34
|
+
// Referent of PhantomReference were garbage collected so we can remove it from our registry.
|
|
35
|
+
// Note that we don't have to call `deallocate` method - it was called [com.facebook.jni.HybridData].
|
|
36
|
+
val current = referenceQueue.remove()
|
|
37
|
+
synchronized(this) {
|
|
38
|
+
destructorMap.remove(current)
|
|
39
|
+
}
|
|
40
|
+
} catch (e: InterruptedException) {
|
|
41
|
+
return
|
|
35
42
|
}
|
|
36
|
-
} catch (e: InterruptedException) {
|
|
37
|
-
// Continue. This thread should never be terminated.
|
|
38
43
|
}
|
|
39
44
|
}
|
|
45
|
+
}.also {
|
|
46
|
+
it.start()
|
|
40
47
|
}
|
|
41
|
-
}
|
|
42
|
-
|
|
48
|
+
} else {
|
|
49
|
+
null
|
|
43
50
|
}
|
|
44
51
|
|
|
45
52
|
/**
|
|
@@ -47,7 +54,8 @@ object JNIDeallocator {
|
|
|
47
54
|
* That reference will be deallocated when [JNIDeallocator.deallocate] is called or
|
|
48
55
|
* when the reference won't be reachable by the GC.
|
|
49
56
|
*/
|
|
50
|
-
|
|
57
|
+
@DoNotStrip
|
|
58
|
+
fun addReference(destructible: Destructible): Unit = synchronized(this) {
|
|
51
59
|
val weakRef = WeakReference(destructible)
|
|
52
60
|
val phantomRef = PhantomReference(destructible, referenceQueue)
|
|
53
61
|
destructorMap[phantomRef] = weakRef
|
|
@@ -61,6 +69,7 @@ object JNIDeallocator {
|
|
|
61
69
|
it.get()?.deallocate()
|
|
62
70
|
}
|
|
63
71
|
destructorMap.clear()
|
|
72
|
+
destructorThread?.interrupt()
|
|
64
73
|
}
|
|
65
74
|
|
|
66
75
|
/**
|
|
@@ -31,6 +31,7 @@ class JSIInteropModuleRegistry(appContext: AppContext) : Destructible {
|
|
|
31
31
|
*/
|
|
32
32
|
external fun installJSI(
|
|
33
33
|
jsRuntimePointer: Long,
|
|
34
|
+
jniDeallocator: JNIDeallocator,
|
|
34
35
|
jsInvokerHolder: CallInvokerHolderImpl,
|
|
35
36
|
nativeInvokerHolder: CallInvokerHolderImpl
|
|
36
37
|
)
|
|
@@ -38,7 +39,13 @@ class JSIInteropModuleRegistry(appContext: AppContext) : Destructible {
|
|
|
38
39
|
/**
|
|
39
40
|
* Initializes the test runtime. Shouldn't be used in the production.
|
|
40
41
|
*/
|
|
41
|
-
external fun installJSIForTests(
|
|
42
|
+
external fun installJSIForTests(
|
|
43
|
+
jniDeallocator: JNIDeallocator,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
fun installJSIForTests() = installJSIForTests(
|
|
47
|
+
JNIDeallocator(shouldCreateDestructorThread = false)
|
|
48
|
+
)
|
|
42
49
|
|
|
43
50
|
/**
|
|
44
51
|
* Evaluates given JavaScript source code.
|
|
@@ -9,10 +9,6 @@ import expo.modules.kotlin.exception.UnexpectedException
|
|
|
9
9
|
@Suppress("KotlinJniMissingFunction")
|
|
10
10
|
@DoNotStrip
|
|
11
11
|
class JavaCallback @DoNotStrip internal constructor(@DoNotStrip private val mHybridData: HybridData) : Destructible {
|
|
12
|
-
init {
|
|
13
|
-
JNIDeallocator.addReference(this)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
12
|
operator fun invoke(result: Any?) {
|
|
17
13
|
if (result == null) {
|
|
18
14
|
invoke()
|
|
@@ -11,10 +11,6 @@ import kotlin.reflect.typeOf
|
|
|
11
11
|
@Suppress("KotlinJniMissingFunction")
|
|
12
12
|
@DoNotStrip
|
|
13
13
|
class JavaScriptFunction<ReturnType : Any?> @DoNotStrip private constructor(@DoNotStrip private val mHybridData: HybridData) : Destructible {
|
|
14
|
-
init {
|
|
15
|
-
JNIDeallocator.addReference(this)
|
|
16
|
-
}
|
|
17
|
-
|
|
18
14
|
@PublishedApi
|
|
19
15
|
internal var returnType: KType? = null
|
|
20
16
|
|
|
@@ -16,7 +16,10 @@ import expo.modules.kotlin.objects.ObjectDefinitionData
|
|
|
16
16
|
*/
|
|
17
17
|
@Suppress("KotlinJniMissingFunction")
|
|
18
18
|
@DoNotStrip
|
|
19
|
-
class JavaScriptModuleObject(
|
|
19
|
+
class JavaScriptModuleObject(
|
|
20
|
+
jniDeallocator: JNIDeallocator,
|
|
21
|
+
val name: String
|
|
22
|
+
) : Destructible {
|
|
20
23
|
// Has to be called "mHybridData" - fbjni uses it via reflection
|
|
21
24
|
@DoNotStrip
|
|
22
25
|
private val mHybridData = initHybrid()
|
|
@@ -24,7 +27,7 @@ class JavaScriptModuleObject(val name: String) : Destructible {
|
|
|
24
27
|
private external fun initHybrid(): HybridData
|
|
25
28
|
|
|
26
29
|
init {
|
|
27
|
-
|
|
30
|
+
jniDeallocator.addReference(this)
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
fun initUsingObjectDefinition(appContext: AppContext, definition: ObjectDefinitionData) = apply {
|
|
@@ -10,11 +10,6 @@ import expo.modules.core.interfaces.DoNotStrip
|
|
|
10
10
|
@Suppress("KotlinJniMissingFunction")
|
|
11
11
|
@DoNotStrip
|
|
12
12
|
open class JavaScriptObject @DoNotStrip internal constructor(@DoNotStrip private val mHybridData: HybridData) : Destructible {
|
|
13
|
-
init {
|
|
14
|
-
@Suppress("LeakingThis")
|
|
15
|
-
JNIDeallocator.addReference(this)
|
|
16
|
-
}
|
|
17
|
-
|
|
18
13
|
/**
|
|
19
14
|
* The property descriptor options for the property being defined or modified.
|
|
20
15
|
*/
|
|
@@ -11,10 +11,6 @@ import kotlin.reflect.typeOf
|
|
|
11
11
|
@Suppress("KotlinJniMissingFunction")
|
|
12
12
|
@DoNotStrip
|
|
13
13
|
class JavaScriptValue @DoNotStrip private constructor(@DoNotStrip private val mHybridData: HybridData) : Destructible {
|
|
14
|
-
init {
|
|
15
|
-
JNIDeallocator.addReference(this)
|
|
16
|
-
}
|
|
17
|
-
|
|
18
14
|
fun isValid() = mHybridData.isValid
|
|
19
15
|
external fun kind(): String
|
|
20
16
|
|
|
@@ -361,7 +361,7 @@ inline fun ModuleDefinitionBuilder.Object(block: ObjectDefinitionBuilder.() -> U
|
|
|
361
361
|
|
|
362
362
|
inline fun Module.Object(block: ObjectDefinitionBuilder.() -> Unit): JavaScriptModuleObject {
|
|
363
363
|
val objectData = ObjectDefinitionBuilder().also(block).buildObject()
|
|
364
|
-
return JavaScriptModuleObject("[Anonymous Object]")
|
|
364
|
+
return JavaScriptModuleObject(appContext.jniDeallocator, "[Anonymous Object]")
|
|
365
365
|
.apply {
|
|
366
366
|
val constants = objectData.constantsProvider()
|
|
367
367
|
val convertedConstants = Arguments.makeNativeMap(constants)
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
package expo.modules.kotlin.types
|
|
2
2
|
|
|
3
3
|
import android.graphics.Color
|
|
4
|
+
import android.os.Build
|
|
5
|
+
import androidx.annotation.RequiresApi
|
|
4
6
|
import com.facebook.react.bridge.Dynamic
|
|
5
7
|
import com.facebook.react.bridge.ReadableType
|
|
6
8
|
import expo.modules.kotlin.exception.UnexpectedException
|
|
@@ -166,6 +168,7 @@ private val namedColors = mapOf(
|
|
|
166
168
|
value.map { it.toFloat() / 255f }
|
|
167
169
|
}
|
|
168
170
|
|
|
171
|
+
@RequiresApi(Build.VERSION_CODES.O)
|
|
169
172
|
class ColorTypeConverter(
|
|
170
173
|
isOptional: Boolean
|
|
171
174
|
) : DynamicAwareTypeConverters<Color>(isOptional) {
|
|
@@ -272,8 +272,6 @@ object TypeConverterProviderImpl : TypeConverterProvider {
|
|
|
272
272
|
BigUint64Array::class.createType(nullable = isOptional) to BigUint64ArrayTypeConverter(isOptional),
|
|
273
273
|
TypedArray::class.createType(nullable = isOptional) to TypedArrayTypeConverter(isOptional),
|
|
274
274
|
|
|
275
|
-
Color::class.createType(nullable = isOptional) to ColorTypeConverter(isOptional),
|
|
276
|
-
|
|
277
275
|
URL::class.createType(nullable = isOptional) to URLTypConverter(isOptional),
|
|
278
276
|
Uri::class.createType(nullable = isOptional) to UriTypeConverter(isOptional),
|
|
279
277
|
URI::class.createType(nullable = isOptional) to JavaURITypeConverter(isOptional),
|
|
@@ -286,6 +284,7 @@ object TypeConverterProviderImpl : TypeConverterProvider {
|
|
|
286
284
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
|
287
285
|
return converters + mapOf(
|
|
288
286
|
Path::class.createType(nullable = isOptional) to PathTypeConverter(isOptional),
|
|
287
|
+
Color::class.createType(nullable = isOptional) to ColorTypeConverter(isOptional),
|
|
289
288
|
)
|
|
290
289
|
}
|
|
291
290
|
|
package/ios/JSI/EXJSIInstaller.h
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
// Swift classes need forward-declaration in the headers.
|
|
6
6
|
@class EXAppContext;
|
|
7
|
-
@class
|
|
7
|
+
@class ExpoRuntime;
|
|
8
8
|
|
|
9
9
|
@interface EXJavaScriptRuntimeManager : NSObject
|
|
10
10
|
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
Gets the JS runtime from the given bridge. May return `nil` when
|
|
13
13
|
the runtime is not available yet or the remote debugging is enabled.
|
|
14
14
|
*/
|
|
15
|
-
+ (nullable
|
|
15
|
+
+ (nullable ExpoRuntime *)runtimeFromBridge:(nonnull RCTBridge *)bridge NS_SWIFT_NAME(runtime(fromBridge:));
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
Installs ExpoModules host object in the runtime of the given app context.
|
|
@@ -27,15 +27,15 @@ static NSString *modulesHostObjectLegacyPropertyName = @"ExpoModules";
|
|
|
27
27
|
|
|
28
28
|
@implementation EXJavaScriptRuntimeManager
|
|
29
29
|
|
|
30
|
-
+ (nullable
|
|
30
|
+
+ (nullable ExpoRuntime *)runtimeFromBridge:(nonnull RCTBridge *)bridge
|
|
31
31
|
{
|
|
32
32
|
jsi::Runtime *jsiRuntime = [bridge respondsToSelector:@selector(runtime)] ? reinterpret_cast<jsi::Runtime *>(bridge.runtime) : nullptr;
|
|
33
|
-
return jsiRuntime ? [[
|
|
33
|
+
return jsiRuntime ? [[ExpoRuntime alloc] initWithRuntime:jsiRuntime callInvoker:bridge.jsCallInvoker] : nil;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
+ (BOOL)installExpoModulesHostObject:(nonnull EXAppContext *)appContext
|
|
37
37
|
{
|
|
38
|
-
|
|
38
|
+
ExpoRuntime *runtime = [appContext _runtime];
|
|
39
39
|
|
|
40
40
|
// The runtime may be unavailable, e.g. remote debugger is enabled or it hasn't been set yet.
|
|
41
41
|
if (!runtime) {
|
|
@@ -43,9 +43,9 @@ static NSString *modulesHostObjectLegacyPropertyName = @"ExpoModules";
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
EXJavaScriptObject *global = [runtime global];
|
|
46
|
-
EXJavaScriptObject *
|
|
46
|
+
EXJavaScriptObject *coreObject = [runtime coreObject];
|
|
47
47
|
|
|
48
|
-
if ([
|
|
48
|
+
if ([coreObject hasProperty:modulesHostObjectPropertyName]) {
|
|
49
49
|
return false;
|
|
50
50
|
}
|
|
51
51
|
|
|
@@ -53,7 +53,7 @@ static NSString *modulesHostObjectLegacyPropertyName = @"ExpoModules";
|
|
|
53
53
|
EXJavaScriptObject *modulesHostObject = [runtime createHostObject:modulesHostObjectPtr];
|
|
54
54
|
|
|
55
55
|
// Define the `global.expo.modules` object as a non-configurable, read-only and enumerable property.
|
|
56
|
-
[
|
|
56
|
+
[coreObject defineProperty:modulesHostObjectPropertyName
|
|
57
57
|
value:modulesHostObject
|
|
58
58
|
options:EXJavaScriptObjectPropertyDescriptorEnumerable];
|
|
59
59
|
|
|
@@ -66,12 +66,6 @@ NS_SWIFT_NAME(JavaScriptRuntime)
|
|
|
66
66
|
*/
|
|
67
67
|
- (nonnull EXJavaScriptObject *)global;
|
|
68
68
|
|
|
69
|
-
/**
|
|
70
|
-
The main object of the Expo runtime that is used to scope native Expo-specific functionalities.
|
|
71
|
-
It gets installed into the runtime as the `global.expo` object.
|
|
72
|
-
*/
|
|
73
|
-
- (nonnull EXJavaScriptObject *)mainObject;
|
|
74
|
-
|
|
75
69
|
/**
|
|
76
70
|
Creates a new object for use in Swift.
|
|
77
71
|
*/
|
|
@@ -20,16 +20,9 @@
|
|
|
20
20
|
#import <ExpoModulesCore/EXJSIConversions.h>
|
|
21
21
|
#import <ExpoModulesCore/Swift.h>
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
Property name of the main object in the Expo JS runtime.
|
|
26
|
-
*/
|
|
27
|
-
static NSString *mainObjectPropertyName = @"expo";
|
|
28
|
-
|
|
29
23
|
@implementation EXJavaScriptRuntime {
|
|
30
24
|
std::shared_ptr<jsi::Runtime> _runtime;
|
|
31
25
|
std::shared_ptr<react::CallInvoker> _jsCallInvoker;
|
|
32
|
-
EXJavaScriptObject *_mainObject;
|
|
33
26
|
}
|
|
34
27
|
|
|
35
28
|
/**
|
|
@@ -46,7 +39,6 @@ static NSString *mainObjectPropertyName = @"expo";
|
|
|
46
39
|
_runtime = jsc::makeJSCRuntime();
|
|
47
40
|
#endif
|
|
48
41
|
_jsCallInvoker = nil;
|
|
49
|
-
[self initializeMainObject];
|
|
50
42
|
}
|
|
51
43
|
return self;
|
|
52
44
|
}
|
|
@@ -60,7 +52,6 @@ static NSString *mainObjectPropertyName = @"expo";
|
|
|
60
52
|
// See explanation for constructor (8): https://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr
|
|
61
53
|
_runtime = std::shared_ptr<jsi::Runtime>(std::shared_ptr<jsi::Runtime>(), runtime);
|
|
62
54
|
_jsCallInvoker = callInvoker;
|
|
63
|
-
[self initializeMainObject];
|
|
64
55
|
}
|
|
65
56
|
return self;
|
|
66
57
|
}
|
|
@@ -93,11 +84,6 @@ static NSString *mainObjectPropertyName = @"expo";
|
|
|
93
84
|
return [[EXJavaScriptObject alloc] initWith:jsGlobalPtr runtime:self];
|
|
94
85
|
}
|
|
95
86
|
|
|
96
|
-
- (nonnull EXJavaScriptObject *)mainObject
|
|
97
|
-
{
|
|
98
|
-
return _mainObject;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
87
|
- (nonnull EXJavaScriptObject *)createSyncFunction:(nonnull NSString *)name
|
|
102
88
|
argsCount:(NSInteger)argsCount
|
|
103
89
|
block:(nonnull JSSyncFunctionBlock)block
|
|
@@ -195,15 +181,6 @@ static NSString *mainObjectPropertyName = @"expo";
|
|
|
195
181
|
|
|
196
182
|
#pragma mark - Private
|
|
197
183
|
|
|
198
|
-
- (void)initializeMainObject
|
|
199
|
-
{
|
|
200
|
-
if (!_mainObject) {
|
|
201
|
-
// Add the main object to the runtime (`global.expo`).
|
|
202
|
-
_mainObject = [self createObject];
|
|
203
|
-
[[self global] defineProperty:mainObjectPropertyName value:_mainObject options:EXJavaScriptObjectPropertyDescriptorEnumerable];
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
184
|
- (nonnull EXJavaScriptObject *)createHostFunction:(nonnull NSString *)name
|
|
208
185
|
argsCount:(NSInteger)argsCount
|
|
209
186
|
block:(nonnull JSHostFunctionBlock)block
|
|
@@ -10,3 +10,20 @@ typedef void (^RCTPropBlockAlias)(id<RCTComponent> _Nonnull view, id _Nullable j
|
|
|
10
10
|
- (nonnull RCTPropBlockAlias)createPropBlock:(nonnull NSString *)name isShadowView:(BOOL)isShadowView;
|
|
11
11
|
|
|
12
12
|
@end
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
This is a compatible adapter for Swift `ComponentData` to access react-native's `RCTComponentData`.
|
|
16
|
+
When running in react-native new architecture mode, the `eventDispatcher` is actually null.
|
|
17
|
+
however the`RCTComponentData` still expects it's nonnull because of the `NS_ASSUME_NONNULL_BEGIN`
|
|
18
|
+
https://github.com/facebook/react-native/blob/ea4724b37c9f78bd33daab547d6cc4f8b7f7dd81/packages/react-native/React/Views/RCTComponentData.h#L19-L35.
|
|
19
|
+
Swift will have a runtime exception from the implicitly unwrapping.
|
|
20
|
+
This compatible adapter basically allows the `eventDispatcher` to be nullable.
|
|
21
|
+
TODO: We should propose the fix to upstream and remove this adapter when dropping SDK 49.
|
|
22
|
+
*/
|
|
23
|
+
@interface RCTComponentDataSwiftAdapter : RCTComponentData
|
|
24
|
+
|
|
25
|
+
- (nonnull instancetype)initWithManagerClass:(nonnull Class)managerClass
|
|
26
|
+
bridge:(nonnull RCTBridge *)bridge
|
|
27
|
+
eventDispatcher:(nullable id<RCTEventDispatcherProtocol>)eventDispatcher;
|
|
28
|
+
|
|
29
|
+
@end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Copyright 2021-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
#import <ExpoModulesCore/RCTComponentData+Privates.h>
|
|
4
|
+
#import <React/RCTComponentData.h>
|
|
5
|
+
|
|
6
|
+
@implementation RCTComponentDataSwiftAdapter
|
|
7
|
+
|
|
8
|
+
- (nonnull instancetype)initWithManagerClass:(nonnull Class)managerClass
|
|
9
|
+
bridge:(nonnull RCTBridge *)bridge
|
|
10
|
+
eventDispatcher:(nullable id<RCTEventDispatcherProtocol>)eventDispatcher
|
|
11
|
+
{
|
|
12
|
+
return [super initWithManagerClass:managerClass bridge:bridge eventDispatcher:nil];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@end
|