@depup/react-native-worklets 0.11.3-depup.0 → 0.12.1-depup.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/Common/cpp/worklets/AnimationFrameQueue/AnimationFrameBatchinator.cpp +6 -3
- package/Common/cpp/worklets/Compat/StableApi.cpp +4 -0
- package/Common/cpp/worklets/Compat/StableApi.h +3 -1
- package/Common/cpp/worklets/NativeModules/JSIWorkletsModuleProxy.cpp +26 -43
- package/Common/cpp/worklets/RunLoop/AsyncQueueImpl.cpp +32 -0
- package/Common/cpp/worklets/RunLoop/EventLoop.cpp +16 -7
- package/Common/cpp/worklets/RunLoop/EventLoop.h +4 -2
- package/Common/cpp/worklets/SharedItems/MemoryManager.cpp +2 -2
- package/Common/cpp/worklets/SharedItems/Serializable.h +14 -16
- package/Common/cpp/worklets/Tools/UIScheduler.cpp +10 -0
- package/Common/cpp/worklets/Tools/UIScheduler.h +3 -0
- package/Common/cpp/worklets/Tools/WorkletsJSIUtils.h +23 -0
- package/Common/cpp/worklets/WorkletRuntime/RuntimeManager.cpp +7 -4
- package/Common/cpp/worklets/WorkletRuntime/RuntimeManager.h +2 -1
- package/Common/cpp/worklets/WorkletRuntime/WorkletRuntime.cpp +60 -88
- package/Common/cpp/worklets/WorkletRuntime/WorkletRuntime.h +335 -122
- package/README.md +2 -2
- package/android/build.gradle.kts +20 -6
- package/android/src/main/cpp/worklets/android/AndroidUIScheduler.cpp +10 -8
- package/android/src/main/cpp/worklets/android/JScriptBufferWrapper.cpp +2 -11
- package/android/src/main/cpp/worklets/android/JScriptBufferWrapper.h +1 -4
- package/android/src/main/java/com/swmansion/worklets/AndroidUIScheduler.kt +3 -0
- package/android/src/main/java/com/swmansion/worklets/ScriptBufferWrapper.kt +87 -43
- package/android/src/networking/com/swmansion/worklets/WorkletsModule.kt +25 -9
- package/android/src/no-networking/com/swmansion/worklets/WorkletsModule.kt +25 -9
- package/apple/worklets/apple/IOSUIScheduler.h +3 -0
- package/apple/worklets/apple/IOSUIScheduler.mm +6 -1
- package/apple/worklets/apple/ScriptLoader.h +11 -0
- package/apple/worklets/apple/ScriptLoader.mm +124 -0
- package/apple/worklets/apple/WorkletsModule.h +1 -16
- package/apple/worklets/apple/WorkletsModule.mm +4 -16
- package/changes.json +1 -1
- package/compatibility.json +4 -1
- package/lib/module/WorkletsModule/NativeWorklets.native.js +2 -2
- package/lib/module/WorkletsModule/NativeWorklets.native.js.map +1 -1
- package/lib/module/debug/jsVersion.js +1 -1
- package/lib/module/memory/serializable.native.js +59 -21
- package/lib/module/memory/serializable.native.js.map +1 -1
- package/lib/module/mock.js +58 -17
- package/lib/module/mock.js.map +1 -1
- package/lib/module/runLoop/uiRuntime/requestAnimationFrame.js +1 -2
- package/lib/module/runLoop/uiRuntime/requestAnimationFrame.js.map +1 -1
- package/lib/module/runLoop/workletRuntime/taskQueue.js +0 -1
- package/lib/module/runLoop/workletRuntime/taskQueue.js.map +1 -1
- package/lib/module/runtimes.native.js +7 -8
- package/lib/module/runtimes.native.js.map +1 -1
- package/lib/module/threads.js +35 -24
- package/lib/module/threads.js.map +1 -1
- package/lib/typescript/WorkletsModule/NativeWorklets.native.d.ts.map +1 -1
- package/lib/typescript/WorkletsModule/workletsModuleProxy.d.ts +1 -1
- package/lib/typescript/WorkletsModule/workletsModuleProxy.d.ts.map +1 -1
- package/lib/typescript/debug/jsVersion.d.ts +1 -1
- package/lib/typescript/memory/serializable.native.d.ts.map +1 -1
- package/lib/typescript/runLoop/uiRuntime/requestAnimationFrame.d.ts.map +1 -1
- package/lib/typescript/runLoop/workletRuntime/taskQueue.d.ts.map +1 -1
- package/lib/typescript/runtimes.native.d.ts.map +1 -1
- package/lib/typescript/specs/NativeWorkletsModule.d.ts +1 -1
- package/lib/typescript/threads.d.ts.map +1 -1
- package/lib/typescript/types.d.ts +38 -8
- package/lib/typescript/types.d.ts.map +1 -1
- package/package.json +14 -15
- package/plugin/index.js +1625 -1572
- package/src/WorkletsModule/NativeWorklets.native.ts +4 -2
- package/src/WorkletsModule/workletsModuleProxy.ts +2 -1
- package/src/debug/jsVersion.ts +1 -1
- package/src/memory/serializable.native.ts +103 -36
- package/src/mock.ts +85 -23
- package/src/runLoop/uiRuntime/requestAnimationFrame.ts +1 -2
- package/src/runLoop/workletRuntime/taskQueue.ts +0 -1
- package/src/runtimes.native.ts +12 -8
- package/src/threads.ts +38 -26
- package/src/types.ts +42 -8
- package/Common/cpp/worklets/Registries/EventHandlerRegistry.cpp +0 -95
- package/Common/cpp/worklets/Registries/EventHandlerRegistry.h +0 -44
- package/Common/cpp/worklets/Tools/WorkletEventHandler.cpp +0 -34
- package/Common/cpp/worklets/Tools/WorkletEventHandler.h +0 -44
- package/jest/pluginTestUtils.ts +0 -16
|
@@ -25,21 +25,13 @@ jni::local_ref<JScriptBufferWrapper::jhybriddata> JScriptBufferWrapper::initHybr
|
|
|
25
25
|
|
|
26
26
|
jni::local_ref<JScriptBufferWrapper::jhybriddata> JScriptBufferWrapper::initHybridFromFile(
|
|
27
27
|
jni::alias_ref<jhybridobject> jThis, // NOLINT //(performance-unnecessary-value-param)
|
|
28
|
-
const std::string &fileName
|
|
28
|
+
const std::string &fileName,
|
|
29
|
+
const std::string &sourceURL) {
|
|
29
30
|
std::shared_ptr<const ScriptBuffer> script;
|
|
30
31
|
RecoverableError::runRethrowingAsRecoverable<std::system_error>([&fileName, &script]() {
|
|
31
32
|
auto bigString = JSBigFileString::fromPath(fileName);
|
|
32
33
|
script = std::make_shared<ScriptBuffer>(std::move(bigString));
|
|
33
34
|
});
|
|
34
|
-
return makeCxxInstance(std::move(script), fileName);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
jni::local_ref<JScriptBufferWrapper::jhybriddata> JScriptBufferWrapper::initHybridFromString(
|
|
38
|
-
jni::alias_ref<jhybridobject> jThis, // NOLINT //(performance-unnecessary-value-param)
|
|
39
|
-
const std::string &scriptStr,
|
|
40
|
-
const std::string &sourceURL) {
|
|
41
|
-
auto bigString = std::make_shared<JSBigStdString>(scriptStr);
|
|
42
|
-
auto script = std::make_shared<ScriptBuffer>(std::move(bigString));
|
|
43
35
|
return makeCxxInstance(std::move(script), sourceURL);
|
|
44
36
|
}
|
|
45
37
|
|
|
@@ -60,7 +52,6 @@ void JScriptBufferWrapper::registerNatives() {
|
|
|
60
52
|
registerHybrid({
|
|
61
53
|
makeNativeMethod("initHybridFromAssets", JScriptBufferWrapper::initHybridFromAssets),
|
|
62
54
|
makeNativeMethod("initHybridFromFile", JScriptBufferWrapper::initHybridFromFile),
|
|
63
|
-
makeNativeMethod("initHybridFromString", JScriptBufferWrapper::initHybridFromString),
|
|
64
55
|
});
|
|
65
56
|
}
|
|
66
57
|
} // namespace worklets
|
|
@@ -31,11 +31,8 @@ class JScriptBufferWrapper : public jni::HybridClass<JScriptBufferWrapper> {
|
|
|
31
31
|
jni::alias_ref<jhybridobject> jThis,
|
|
32
32
|
jni::alias_ref<JAssetManager::javaobject> assetManager,
|
|
33
33
|
const std::string &assetURL);
|
|
34
|
-
static jni::local_ref<JScriptBufferWrapper::jhybriddata> initHybridFromFile(
|
|
35
|
-
jni::alias_ref<jhybridobject> jThis,
|
|
36
|
-
const std::string &fileName);
|
|
37
34
|
static jni::local_ref<JScriptBufferWrapper::jhybriddata>
|
|
38
|
-
|
|
35
|
+
initHybridFromFile(jni::alias_ref<jhybridobject> jThis, const std::string &fileName, const std::string &sourceURL);
|
|
39
36
|
|
|
40
37
|
friend HybridBase;
|
|
41
38
|
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
package com.swmansion.worklets
|
|
2
2
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
|
+
import android.content.Context
|
|
4
5
|
import android.content.res.AssetManager
|
|
5
|
-
import android.os.Build
|
|
6
6
|
import com.facebook.jni.HybridData
|
|
7
7
|
import com.facebook.proguard.annotations.DoNotStrip
|
|
8
8
|
import com.facebook.proguard.annotations.DoNotStripAny
|
|
9
|
+
import com.facebook.react.ReactApplication
|
|
10
|
+
import org.json.JSONException
|
|
11
|
+
import org.json.JSONObject
|
|
12
|
+
import java.io.File
|
|
9
13
|
import java.io.IOException
|
|
10
|
-
import java.io.InputStream
|
|
11
14
|
import java.net.HttpURLConnection
|
|
12
15
|
import java.net.URL
|
|
13
16
|
import java.nio.charset.StandardCharsets
|
|
@@ -17,13 +20,18 @@ import java.nio.charset.StandardCharsets
|
|
|
17
20
|
@SuppressLint("MissingNativeLoadLibrary")
|
|
18
21
|
@DoNotStripAny
|
|
19
22
|
class ScriptBufferWrapper(
|
|
20
|
-
uri: String
|
|
21
|
-
|
|
23
|
+
uri: String?,
|
|
24
|
+
context: Context,
|
|
22
25
|
) {
|
|
23
26
|
@field:DoNotStrip
|
|
24
27
|
private val mHybridData: HybridData
|
|
25
28
|
|
|
26
29
|
init {
|
|
30
|
+
checkNotNull(uri) {
|
|
31
|
+
"[Worklets] No script URL provided. Make sure the packager is running or you have " +
|
|
32
|
+
"embedded a JS bundle in your application bundle."
|
|
33
|
+
}
|
|
34
|
+
|
|
27
35
|
val filePrefix = "file://"
|
|
28
36
|
val absPathPrefix = "/"
|
|
29
37
|
val assetsPrefix = "assets://"
|
|
@@ -32,23 +40,20 @@ class ScriptBufferWrapper(
|
|
|
32
40
|
when {
|
|
33
41
|
uri.startsWith(filePrefix) -> {
|
|
34
42
|
val fileName = uri.substring(filePrefix.length)
|
|
35
|
-
initHybridFromFile(fileName)
|
|
43
|
+
initHybridFromFile(fileName, fileName)
|
|
36
44
|
}
|
|
37
45
|
uri.startsWith(assetsPrefix) -> {
|
|
38
46
|
val assetURL = uri.substring(assetsPrefix.length)
|
|
39
|
-
initHybridFromAssets(
|
|
47
|
+
initHybridFromAssets(context.assets, assetURL)
|
|
40
48
|
}
|
|
41
49
|
uri.startsWith(absPathPrefix) -> {
|
|
42
|
-
initHybridFromFile(uri)
|
|
50
|
+
initHybridFromFile(uri, uri)
|
|
43
51
|
}
|
|
44
52
|
else -> {
|
|
45
|
-
val
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
throw RuntimeException(e)
|
|
50
|
-
}
|
|
51
|
-
initHybridFromString(scriptContent, uri)
|
|
53
|
+
val bundleFile =
|
|
54
|
+
reactNativeDownloadedBundleFile(context)
|
|
55
|
+
?: File(context.cacheDir, DEV_BUNDLE_FILE_NAME).also { downloadScriptToFile(uri, it) }
|
|
56
|
+
initHybridFromFile(bundleFile.absolutePath, uri)
|
|
52
57
|
}
|
|
53
58
|
}
|
|
54
59
|
}
|
|
@@ -58,45 +63,84 @@ class ScriptBufferWrapper(
|
|
|
58
63
|
assetURL: String,
|
|
59
64
|
): HybridData
|
|
60
65
|
|
|
61
|
-
private external fun initHybridFromFile(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
script: String,
|
|
65
|
-
url: String,
|
|
66
|
+
private external fun initHybridFromFile(
|
|
67
|
+
fileName: String,
|
|
68
|
+
sourceURL: String,
|
|
66
69
|
): HybridData
|
|
67
70
|
|
|
68
71
|
companion object {
|
|
69
|
-
private
|
|
70
|
-
|
|
71
|
-
val connection = scriptUrl.openConnection() as HttpURLConnection
|
|
72
|
-
try {
|
|
73
|
-
val content: ByteArray
|
|
72
|
+
private const val DEV_BUNDLE_FILE_NAME = "WorkletsDevBundle.js"
|
|
73
|
+
private const val CONNECT_TIMEOUT_MS = 5_000
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
75
|
+
private fun reactNativeDownloadedBundleFile(context: Context): File? {
|
|
76
|
+
val reactApplication = context.applicationContext as? ReactApplication ?: return null
|
|
77
|
+
val bundlePath =
|
|
78
|
+
reactApplication.reactHost
|
|
79
|
+
?.devSupportManager
|
|
80
|
+
?.downloadedJSBundleFile ?: return null
|
|
81
|
+
return File(bundlePath).takeIf { it.exists() }
|
|
82
|
+
}
|
|
80
83
|
|
|
81
|
-
|
|
84
|
+
private fun downloadScriptToFile(
|
|
85
|
+
url: String,
|
|
86
|
+
outputFile: File,
|
|
87
|
+
) {
|
|
88
|
+
val connection = URL(url).openConnection() as HttpURLConnection
|
|
89
|
+
connection.connectTimeout = CONNECT_TIMEOUT_MS
|
|
90
|
+
try {
|
|
91
|
+
val statusCode =
|
|
92
|
+
try {
|
|
93
|
+
connection.responseCode
|
|
94
|
+
} catch (e: IOException) {
|
|
95
|
+
throw RuntimeException("[Worklets] Could not connect to development server.\n", e)
|
|
96
|
+
}
|
|
97
|
+
if (statusCode != 200) {
|
|
98
|
+
throw RuntimeException(serverErrorMessage(url, statusCode, connection))
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
val tmpFile = File(outputFile.path + ".tmp")
|
|
102
|
+
connection.inputStream.use { input ->
|
|
103
|
+
tmpFile.outputStream().use { output -> input.copyTo(output) }
|
|
104
|
+
}
|
|
105
|
+
if (!tmpFile.renameTo(outputFile)) {
|
|
106
|
+
throw IOException("Couldn't rename $tmpFile to $outputFile")
|
|
107
|
+
}
|
|
108
|
+
} catch (e: IOException) {
|
|
109
|
+
throw RuntimeException(
|
|
110
|
+
"[Worklets] Failed to store worklets bundle from URL $url: ${e.message}",
|
|
111
|
+
e,
|
|
112
|
+
)
|
|
113
|
+
}
|
|
82
114
|
} finally {
|
|
83
115
|
connection.disconnect()
|
|
84
116
|
}
|
|
85
117
|
}
|
|
86
118
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
119
|
+
private fun serverErrorMessage(
|
|
120
|
+
url: String,
|
|
121
|
+
statusCode: Int,
|
|
122
|
+
connection: HttpURLConnection,
|
|
123
|
+
): String {
|
|
124
|
+
val body = connection.errorStream?.use { String(it.readBytes(), StandardCharsets.UTF_8) }
|
|
125
|
+
val metroMessage = parseMetroError(body)
|
|
126
|
+
if (metroMessage != null) {
|
|
127
|
+
return "[Worklets] $metroMessage"
|
|
128
|
+
}
|
|
129
|
+
return "[Worklets] The development server returned response error code: $statusCode\n\n" +
|
|
130
|
+
"URL: $url\n\n" +
|
|
131
|
+
"Body:\n$body"
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
private fun parseMetroError(body: String?): String? {
|
|
135
|
+
if (body.isNullOrEmpty()) {
|
|
136
|
+
return null
|
|
137
|
+
}
|
|
138
|
+
return try {
|
|
139
|
+
val json = JSONObject(body)
|
|
140
|
+
val fileName = json.getString("filename").substringAfterLast('/')
|
|
141
|
+
"${json.getString("message")}\n at $fileName:${json.getInt("lineNumber")}:${json.getInt("column")}"
|
|
142
|
+
} catch (e: JSONException) {
|
|
143
|
+
null
|
|
100
144
|
}
|
|
101
145
|
}
|
|
102
146
|
}
|
|
@@ -14,7 +14,6 @@ import com.facebook.react.turbomodule.core.CallInvokerHolderImpl
|
|
|
14
14
|
import com.facebook.soloader.SoLoader
|
|
15
15
|
import com.swmansion.worklets.runloop.AnimationFrameCallback
|
|
16
16
|
import com.swmansion.worklets.runloop.AnimationFrameQueue
|
|
17
|
-
import java.util.concurrent.atomic.AtomicBoolean
|
|
18
17
|
|
|
19
18
|
@Suppress("KotlinJniMissingFunction")
|
|
20
19
|
@ReactModule(name = WorkletsModule.NAME)
|
|
@@ -50,7 +49,8 @@ class WorkletsModule(
|
|
|
50
49
|
* Invalidating concurrently could be fatal. It shouldn't happen in a normal flow, but it doesn't
|
|
51
50
|
* cost us much to add synchronization for extra safety.
|
|
52
51
|
*/
|
|
53
|
-
private val
|
|
52
|
+
private val mInvalidationLock = Any()
|
|
53
|
+
private var mInvalidated = false
|
|
54
54
|
|
|
55
55
|
@OptIn(FrameworkAPI::class)
|
|
56
56
|
private external fun initHybrid(
|
|
@@ -71,11 +71,9 @@ class WorkletsModule(
|
|
|
71
71
|
val jsContext = checkNotNull(context.javaScriptContextHolder).get()
|
|
72
72
|
val jsCallInvokerHolder = context.jsCallInvokerHolder as CallInvokerHolderImpl
|
|
73
73
|
|
|
74
|
-
val sourceURL = context.sourceURL
|
|
75
|
-
|
|
76
74
|
val scriptBufferWrapper: ScriptBufferWrapper? =
|
|
77
75
|
if (bundleModeEnabled) {
|
|
78
|
-
ScriptBufferWrapper(sourceURL
|
|
76
|
+
ScriptBufferWrapper(context.sourceURL, context)
|
|
79
77
|
} else {
|
|
80
78
|
null
|
|
81
79
|
}
|
|
@@ -161,9 +159,17 @@ class WorkletsModule(
|
|
|
161
159
|
return mSlowAnimationsEnabled
|
|
162
160
|
}
|
|
163
161
|
|
|
162
|
+
override fun initialize() {
|
|
163
|
+
reactApplicationContext.addLifecycleEventListener(this)
|
|
164
|
+
}
|
|
165
|
+
|
|
164
166
|
override fun invalidate() {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
+
synchronized(mInvalidationLock) {
|
|
168
|
+
if (mInvalidated) {
|
|
169
|
+
return
|
|
170
|
+
}
|
|
171
|
+
mInvalidated = true
|
|
172
|
+
reactApplicationContext.removeLifecycleEventListener(this)
|
|
167
173
|
}
|
|
168
174
|
if (mHybridData != null && mHybridData!!.isValid) {
|
|
169
175
|
invalidateCpp()
|
|
@@ -176,11 +182,21 @@ class WorkletsModule(
|
|
|
176
182
|
private external fun startCpp()
|
|
177
183
|
|
|
178
184
|
override fun onHostResume() {
|
|
179
|
-
|
|
185
|
+
synchronized(mInvalidationLock) {
|
|
186
|
+
if (mInvalidated) {
|
|
187
|
+
return
|
|
188
|
+
}
|
|
189
|
+
mAnimationFrameQueue.resume()
|
|
190
|
+
}
|
|
180
191
|
}
|
|
181
192
|
|
|
182
193
|
override fun onHostPause() {
|
|
183
|
-
|
|
194
|
+
synchronized(mInvalidationLock) {
|
|
195
|
+
if (mInvalidated) {
|
|
196
|
+
return
|
|
197
|
+
}
|
|
198
|
+
mAnimationFrameQueue.pause()
|
|
199
|
+
}
|
|
184
200
|
}
|
|
185
201
|
|
|
186
202
|
override fun onHostDestroy() {}
|
|
@@ -11,7 +11,6 @@ import com.facebook.react.turbomodule.core.CallInvokerHolderImpl
|
|
|
11
11
|
import com.facebook.soloader.SoLoader
|
|
12
12
|
import com.swmansion.worklets.runloop.AnimationFrameCallback
|
|
13
13
|
import com.swmansion.worklets.runloop.AnimationFrameQueue
|
|
14
|
-
import java.util.concurrent.atomic.AtomicBoolean
|
|
15
14
|
|
|
16
15
|
@Suppress("KotlinJniMissingFunction")
|
|
17
16
|
@ReactModule(name = WorkletsModule.NAME)
|
|
@@ -46,7 +45,8 @@ class WorkletsModule(
|
|
|
46
45
|
* Invalidating concurrently could be fatal. It shouldn't happen in a normal flow, but it doesn't
|
|
47
46
|
* cost us much to add synchronization for extra safety.
|
|
48
47
|
*/
|
|
49
|
-
private val
|
|
48
|
+
private val mInvalidationLock = Any()
|
|
49
|
+
private var mInvalidated = false
|
|
50
50
|
|
|
51
51
|
@OptIn(FrameworkAPI::class)
|
|
52
52
|
private external fun initHybrid(
|
|
@@ -67,11 +67,9 @@ class WorkletsModule(
|
|
|
67
67
|
val jsContext = checkNotNull(context.javaScriptContextHolder).get()
|
|
68
68
|
val jsCallInvokerHolder = context.jsCallInvokerHolder as CallInvokerHolderImpl
|
|
69
69
|
|
|
70
|
-
val sourceURL = context.sourceURL
|
|
71
|
-
|
|
72
70
|
val scriptBufferWrapper: ScriptBufferWrapper? =
|
|
73
71
|
if (bundleModeEnabled) {
|
|
74
|
-
ScriptBufferWrapper(sourceURL
|
|
72
|
+
ScriptBufferWrapper(context.sourceURL, context)
|
|
75
73
|
} else {
|
|
76
74
|
null
|
|
77
75
|
}
|
|
@@ -117,9 +115,17 @@ class WorkletsModule(
|
|
|
117
115
|
return mSlowAnimationsEnabled
|
|
118
116
|
}
|
|
119
117
|
|
|
118
|
+
override fun initialize() {
|
|
119
|
+
reactApplicationContext.addLifecycleEventListener(this)
|
|
120
|
+
}
|
|
121
|
+
|
|
120
122
|
override fun invalidate() {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
+
synchronized(mInvalidationLock) {
|
|
124
|
+
if (mInvalidated) {
|
|
125
|
+
return
|
|
126
|
+
}
|
|
127
|
+
mInvalidated = true
|
|
128
|
+
reactApplicationContext.removeLifecycleEventListener(this)
|
|
123
129
|
}
|
|
124
130
|
if (mHybridData != null && mHybridData!!.isValid) {
|
|
125
131
|
invalidateCpp()
|
|
@@ -132,11 +138,21 @@ class WorkletsModule(
|
|
|
132
138
|
private external fun startCpp()
|
|
133
139
|
|
|
134
140
|
override fun onHostResume() {
|
|
135
|
-
|
|
141
|
+
synchronized(mInvalidationLock) {
|
|
142
|
+
if (mInvalidated) {
|
|
143
|
+
return
|
|
144
|
+
}
|
|
145
|
+
mAnimationFrameQueue.resume()
|
|
146
|
+
}
|
|
136
147
|
}
|
|
137
148
|
|
|
138
149
|
override fun onHostPause() {
|
|
139
|
-
|
|
150
|
+
synchronized(mInvalidationLock) {
|
|
151
|
+
if (mInvalidated) {
|
|
152
|
+
return
|
|
153
|
+
}
|
|
154
|
+
mAnimationFrameQueue.pause()
|
|
155
|
+
}
|
|
140
156
|
}
|
|
141
157
|
|
|
142
158
|
override fun onHostDestroy() {}
|
|
@@ -9,6 +9,9 @@ using namespace worklets;
|
|
|
9
9
|
class IOSUIScheduler : public UIScheduler, public std::enable_shared_from_this<IOSUIScheduler> {
|
|
10
10
|
public:
|
|
11
11
|
void scheduleOnUI(std::function<void()> job) override;
|
|
12
|
+
|
|
13
|
+
protected:
|
|
14
|
+
bool queryIsOnUIThread() const override;
|
|
12
15
|
};
|
|
13
16
|
|
|
14
17
|
} // namespace worklets
|
|
@@ -5,9 +5,14 @@ namespace worklets {
|
|
|
5
5
|
using namespace facebook;
|
|
6
6
|
using namespace react;
|
|
7
7
|
|
|
8
|
+
bool IOSUIScheduler::queryIsOnUIThread() const
|
|
9
|
+
{
|
|
10
|
+
return [NSThread isMainThread];
|
|
11
|
+
}
|
|
12
|
+
|
|
8
13
|
void IOSUIScheduler::scheduleOnUI(std::function<void()> job)
|
|
9
14
|
{
|
|
10
|
-
if (
|
|
15
|
+
if (isOnUIThread()) {
|
|
11
16
|
job();
|
|
12
17
|
return;
|
|
13
18
|
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
#import <worklets/apple/ScriptLoader.h>
|
|
2
|
+
|
|
3
|
+
namespace worklets {
|
|
4
|
+
namespace {
|
|
5
|
+
|
|
6
|
+
class NSDataScript : public JSBigString {
|
|
7
|
+
public:
|
|
8
|
+
explicit NSDataScript(NSData *data) : data_(data), size_([data length]) {}
|
|
9
|
+
|
|
10
|
+
bool isAscii() const override
|
|
11
|
+
{
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const char *c_str() const override
|
|
16
|
+
{
|
|
17
|
+
return static_cast<const char *>(data_.bytes);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
size_t size() const override
|
|
21
|
+
{
|
|
22
|
+
return size_;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
private:
|
|
26
|
+
NSData *data_;
|
|
27
|
+
size_t size_;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
NSData *loadScriptFromFile(NSURL *url)
|
|
31
|
+
{
|
|
32
|
+
NSError *error;
|
|
33
|
+
NSData *data = [NSData dataWithContentsOfFile:url.path options:NSDataReadingMappedIfSafe error:&error];
|
|
34
|
+
|
|
35
|
+
if (data == nil) [[unlikely]] {
|
|
36
|
+
NSString *errorMsg = [NSString stringWithFormat:@"[Worklets] Failed to load worklets bundle from file %@: %@",
|
|
37
|
+
url.path,
|
|
38
|
+
error.localizedDescription];
|
|
39
|
+
NSLog(@"%@", errorMsg);
|
|
40
|
+
throw std::runtime_error([errorMsg UTF8String]);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return data;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
NSData *downloadScript(NSURL *url)
|
|
47
|
+
{
|
|
48
|
+
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
|
49
|
+
__block NSData *data = nil;
|
|
50
|
+
__block NSURLResponse *response = nil;
|
|
51
|
+
__block NSError *error = nil;
|
|
52
|
+
|
|
53
|
+
NSURLSessionDataTask *task = [[NSURLSession sharedSession]
|
|
54
|
+
dataTaskWithURL:url
|
|
55
|
+
completionHandler:^(NSData *taskData, NSURLResponse *taskResponse, NSError *taskError) {
|
|
56
|
+
data = taskData;
|
|
57
|
+
response = taskResponse;
|
|
58
|
+
error = taskError;
|
|
59
|
+
dispatch_semaphore_signal(semaphore);
|
|
60
|
+
}];
|
|
61
|
+
[task resume];
|
|
62
|
+
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
|
63
|
+
|
|
64
|
+
if (error != nil) [[unlikely]] {
|
|
65
|
+
NSString *errorMsg;
|
|
66
|
+
if ([error.domain isEqualToString:NSURLErrorDomain]) {
|
|
67
|
+
errorMsg = @"[Worklets] Could not connect to development server.\n";
|
|
68
|
+
} else {
|
|
69
|
+
errorMsg = [NSString stringWithFormat:@"[Worklets] Failed to load worklets bundle from URL %@: %@",
|
|
70
|
+
url,
|
|
71
|
+
error.localizedDescription];
|
|
72
|
+
}
|
|
73
|
+
NSLog(@"%@", errorMsg);
|
|
74
|
+
throw std::runtime_error([errorMsg UTF8String]);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
NSInteger statusCode =
|
|
78
|
+
[response isKindOfClass:[NSHTTPURLResponse class]] ? [(NSHTTPURLResponse *)response statusCode] : 200;
|
|
79
|
+
if (statusCode != 200) [[unlikely]] {
|
|
80
|
+
NSString *description = nil;
|
|
81
|
+
NSDictionary *jsonError = data != nil ? [NSJSONSerialization JSONObjectWithData:data options:0 error:nil] : nil;
|
|
82
|
+
if ([jsonError isKindOfClass:[NSDictionary class]] && [jsonError[@"message"] isKindOfClass:[NSString class]] &&
|
|
83
|
+
[jsonError[@"message"] length] > 0) {
|
|
84
|
+
description = jsonError[@"message"];
|
|
85
|
+
} else {
|
|
86
|
+
description = [NSString stringWithFormat:@"Received status code %ld while fetching the bundle", (long)statusCode];
|
|
87
|
+
}
|
|
88
|
+
NSString *errorMsg =
|
|
89
|
+
[NSString stringWithFormat:@"[Worklets] Failed to load worklets bundle from URL %@: %@", url, description];
|
|
90
|
+
NSLog(@"%@", errorMsg);
|
|
91
|
+
throw std::runtime_error([errorMsg UTF8String]);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
NSString *mimeType = response.MIMEType;
|
|
95
|
+
if (![mimeType isEqualToString:@"application/javascript"] && ![mimeType isEqualToString:@"text/javascript"])
|
|
96
|
+
[[unlikely]] {
|
|
97
|
+
NSString *errorMsg = [NSString
|
|
98
|
+
stringWithFormat:
|
|
99
|
+
@"[Worklets] Expected MIME-Type of the worklets bundle to be 'application/javascript' or 'text/javascript', but got '%@'",
|
|
100
|
+
mimeType];
|
|
101
|
+
NSLog(@"%@", errorMsg);
|
|
102
|
+
throw std::runtime_error([errorMsg UTF8String]);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return data;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
} // namespace
|
|
109
|
+
|
|
110
|
+
std::shared_ptr<const ScriptBuffer> getScript(NSURL *url)
|
|
111
|
+
{
|
|
112
|
+
if (url == nil) [[unlikely]] {
|
|
113
|
+
NSString *errorMsg =
|
|
114
|
+
@"[Worklets] No script URL provided. Make sure the packager is running or you have embedded a "
|
|
115
|
+
@"JS bundle in your application bundle.";
|
|
116
|
+
NSLog(@"%@", errorMsg);
|
|
117
|
+
throw std::runtime_error([errorMsg UTF8String]);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
NSData *data = url.isFileURL ? loadScriptFromFile(url) : downloadScript(url);
|
|
121
|
+
return std::make_shared<const ScriptBuffer>(std::make_shared<const NSDataScript>(data));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
} // namespace worklets
|
|
@@ -6,22 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
#import <worklets/NativeModules/WorkletsModuleProxy.h>
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
// Bundle mode
|
|
11
|
-
#import <React/NSBigStringBuffer.h>
|
|
12
|
-
#import <React/RCTBundleConsumer.h>
|
|
13
|
-
#endif // __has_include(<React/RCTBundleConsumer.h>)
|
|
14
|
-
|
|
15
|
-
@interface WorkletsModule : RCTEventEmitter <
|
|
16
|
-
NativeWorkletsModuleSpec,
|
|
17
|
-
RCTCallInvokerModule,
|
|
18
|
-
RCTInvalidating
|
|
19
|
-
#if __has_include(<React/RCTBundleConsumer.h>)
|
|
20
|
-
// Bundle mode
|
|
21
|
-
,
|
|
22
|
-
RCTBundleConsumer
|
|
23
|
-
#endif // __has_include(<React/RCTBundleConsumer.h>)
|
|
24
|
-
>
|
|
9
|
+
@interface WorkletsModule : RCTEventEmitter <NativeWorkletsModuleSpec, RCTCallInvokerModule, RCTInvalidating>
|
|
25
10
|
|
|
26
11
|
- (std::shared_ptr<worklets::WorkletsModuleProxy>)getWorkletsModuleProxy;
|
|
27
12
|
|
|
@@ -7,8 +7,11 @@
|
|
|
7
7
|
#import <worklets/apple/AssertJavaScriptQueue.h>
|
|
8
8
|
#import <worklets/apple/AssertTurboModuleManagerQueue.h>
|
|
9
9
|
#import <worklets/apple/IOSUIScheduler.h>
|
|
10
|
+
#import <worklets/apple/ScriptLoader.h>
|
|
10
11
|
#import <worklets/apple/WorkletsModule.h>
|
|
11
12
|
|
|
13
|
+
#import <Foundation/Foundation.h>
|
|
14
|
+
|
|
12
15
|
#import <React/RCTBridge+Private.h>
|
|
13
16
|
#import <React/RCTCallInvoker.h>
|
|
14
17
|
|
|
@@ -64,7 +67,7 @@ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(installTurboModule : (BOOL)bundleModeEnab
|
|
|
64
67
|
|
|
65
68
|
if (bundleModeEnabled) {
|
|
66
69
|
NSURL *url = bundleManager_.bundleURL;
|
|
67
|
-
script =
|
|
70
|
+
script = getScript(url);
|
|
68
71
|
sourceURL = [[url absoluteString] UTF8String];
|
|
69
72
|
}
|
|
70
73
|
|
|
@@ -127,21 +130,6 @@ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(toggleSlowAnimationsOnUIRuntime)
|
|
|
127
130
|
return std::make_shared<facebook::react::NativeWorkletsModuleSpecJSI>(params);
|
|
128
131
|
}
|
|
129
132
|
|
|
130
|
-
- (std::shared_ptr<const ScriptBuffer>)getScript:(NSURL *)url
|
|
131
|
-
{
|
|
132
|
-
NSData *data = [NSData dataWithContentsOfURL:url];
|
|
133
|
-
|
|
134
|
-
if (!data) [[unlikely]] {
|
|
135
|
-
NSString *errorMsg = [NSString stringWithFormat:@"[Worklets] Failed to load worklets bundle from URL: %@", url];
|
|
136
|
-
NSLog(@"%@", errorMsg);
|
|
137
|
-
throw std::runtime_error([errorMsg UTF8String]);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
auto str = std::string(reinterpret_cast<const char *>([data bytes]), [data length]);
|
|
141
|
-
auto bigString = std::make_shared<const JSBigStdString>(str);
|
|
142
|
-
return std::make_shared<const ScriptBuffer>(bigString);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
133
|
- (std::shared_ptr<RuntimeBindings>)getRuntimeBindings:(jsi::Runtime &)rnRuntime
|
|
146
134
|
bundleModeEnabled:(BOOL)bundleModeEnabled
|
|
147
135
|
{
|
package/changes.json
CHANGED
package/compatibility.json
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"nightly": {
|
|
3
|
-
"react-native": ["0.83", "0.84", "0.85", "0.86"]
|
|
3
|
+
"react-native": ["0.83", "0.84", "0.85", "0.86", "0.87"]
|
|
4
|
+
},
|
|
5
|
+
"0.12.x": {
|
|
6
|
+
"react-native": ["0.83", "0.84", "0.85", "0.86", "0.87"]
|
|
4
7
|
},
|
|
5
8
|
"0.11.x": {
|
|
6
9
|
"react-native": ["0.83", "0.84", "0.85", "0.86"]
|
|
@@ -124,8 +124,8 @@ See https://docs.swmansion.com/react-native-worklets/docs/guides/troubleshooting
|
|
|
124
124
|
runOnUISync(worklet, scheduleStack) {
|
|
125
125
|
return this.#workletsModuleProxy.runOnUISync(worklet, scheduleStack);
|
|
126
126
|
}
|
|
127
|
-
createWorkletRuntime(name, initializer, useDefaultQueue, customQueue, enableEventLoop) {
|
|
128
|
-
return this.#workletsModuleProxy.createWorkletRuntime(name, initializer, useDefaultQueue, customQueue, enableEventLoop);
|
|
127
|
+
createWorkletRuntime(name, initializer, useDefaultQueue, customQueue, enableEventLoop, enableLocking) {
|
|
128
|
+
return this.#workletsModuleProxy.createWorkletRuntime(name, initializer, useDefaultQueue, customQueue, enableEventLoop, enableLocking);
|
|
129
129
|
}
|
|
130
130
|
scheduleOnRuntime(workletRuntime, serializableWorklet, scheduleStack) {
|
|
131
131
|
return this.#workletsModuleProxy.scheduleOnRuntime(workletRuntime, serializableWorklet, scheduleStack);
|