@rn-org/react-native-thread 0.1.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/LICENSE +20 -0
- package/README.md +440 -0
- package/ReactNativeThread.podspec +20 -0
- package/android/build.gradle +69 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/com/rnorg/reactnativethread/ReactNativeThreadModule.kt +162 -0
- package/android/src/main/java/com/rnorg/reactnativethread/ReactNativeThreadPackage.kt +31 -0
- package/ios/ReactNativeThread.h +6 -0
- package/ios/ReactNativeThread.mm +180 -0
- package/lib/module/NativeReactNativeThread.js +5 -0
- package/lib/module/NativeReactNativeThread.js.map +1 -0
- package/lib/module/babel-plugin.js +71 -0
- package/lib/module/babel-plugin.js.map +1 -0
- package/lib/module/globals.d.js +2 -0
- package/lib/module/globals.d.js.map +1 -0
- package/lib/module/index.js +166 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/NativeReactNativeThread.d.ts +20 -0
- package/lib/typescript/src/NativeReactNativeThread.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +49 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/package.json +179 -0
- package/src/NativeReactNativeThread.ts +24 -0
- package/src/babel-plugin.js +77 -0
- package/src/globals.d.ts +34 -0
- package/src/index.tsx +211 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 sriharsha-rently
|
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
in the Software without restriction, including without limitation the rights
|
|
7
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
furnished to do so, subject to the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
# @rn-org/react-native-thread
|
|
2
|
+
|
|
3
|
+
Run JavaScript on real background threads in React Native — no Workers, no Worklets. Uses **JavaScriptCore** on iOS and **Mozilla Rhino** on Android, each on a dedicated OS-level thread. Built as a New Architecture **TurboModule**.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Contents
|
|
8
|
+
|
|
9
|
+
- [Features](#features)
|
|
10
|
+
- [Requirements](#requirements)
|
|
11
|
+
- [Installation](#installation)
|
|
12
|
+
- [Babel plugin (required for Hermes)](#babel-plugin-required-for-hermes)
|
|
13
|
+
- [Quick start](#quick-start)
|
|
14
|
+
- [API reference](#api-reference)
|
|
15
|
+
- [runOnJS](#runonjs)
|
|
16
|
+
- [runOnNewJS](#runnewjs)
|
|
17
|
+
- [createThread](#createthread)
|
|
18
|
+
- [getThreads](#getthreads)
|
|
19
|
+
- [destroyThread](#destroythread)
|
|
20
|
+
- [onMessage](#onmessage)
|
|
21
|
+
- [ThreadHandle](#threadhandle)
|
|
22
|
+
- [ThreadInfo](#threadinfo)
|
|
23
|
+
- [ThreadTask](#threadtask)
|
|
24
|
+
- [Thread globals](#thread-globals)
|
|
25
|
+
- [postMessage](#postmessage)
|
|
26
|
+
- [console](#console)
|
|
27
|
+
- [Hermes & Babel plugin](#hermes--babel-plugin-deep-dive)
|
|
28
|
+
- [Constraints](#constraints)
|
|
29
|
+
- [Contributing](#contributing)
|
|
30
|
+
- [License](#license)
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Features
|
|
35
|
+
|
|
36
|
+
- **True background threads** — each thread runs its own JS engine on an OS-level thread; the main Hermes/JSC runtime is never blocked.
|
|
37
|
+
- **Unlimited threads** — create as many threads as you need; each is isolated.
|
|
38
|
+
- **Shared thread** (`runOnJS`) — fire-and-forget tasks on a single persistent background thread; no teardown required.
|
|
39
|
+
- **Per-thread message passing** — call `postMessage(data)` from any thread, receive it on the main thread with `onMessage` (callback or `await`).
|
|
40
|
+
- **Parameter injection** — pass a JSON-serialisable value from the main thread into the background function as a typed argument `(args) => { ... }`.
|
|
41
|
+
- **Named threads** — give threads friendly names; list or destroy them by name.
|
|
42
|
+
- **Full `console` support** — `console.log/info/warn/error/debug` work inside threads and appear in Logcat / Xcode logs.
|
|
43
|
+
- **Hermes-safe** — ships a Babel plugin that extracts function source at compile time so Hermes bytecode never breaks serialisation.
|
|
44
|
+
- **New Architecture only** — built on the TurboModule / Codegen pipeline.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Requirements
|
|
49
|
+
|
|
50
|
+
| | Minimum |
|
|
51
|
+
|---|---|
|
|
52
|
+
| React Native | 0.76+ (New Architecture) |
|
|
53
|
+
| iOS | 15.1 |
|
|
54
|
+
| Android | API 24 |
|
|
55
|
+
| Node | 18+ |
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Installation
|
|
60
|
+
|
|
61
|
+
```sh
|
|
62
|
+
npm install @rn-org/react-native-thread
|
|
63
|
+
# or
|
|
64
|
+
yarn add @rn-org/react-native-thread
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**iOS** — run pod install:
|
|
68
|
+
|
|
69
|
+
```sh
|
|
70
|
+
cd ios && pod install
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Android** — the Rhino dependency is declared in the library's `build.gradle`; no extra steps needed.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Babel plugin (required for Hermes)
|
|
78
|
+
|
|
79
|
+
Hermes compiles your JS to bytecode at build time. That means `fn.toString()` at runtime returns a placeholder (`"function () { [bytecode] }"`) instead of source code. The library includes a Babel plugin that extracts arrow-function / function-expression source at **compile time** and replaces it with a string literal before Hermes ever sees it.
|
|
80
|
+
|
|
81
|
+
Add the plugin to your app's `babel.config.js`:
|
|
82
|
+
|
|
83
|
+
```js
|
|
84
|
+
// babel.config.js
|
|
85
|
+
module.exports = {
|
|
86
|
+
presets: ['module:@react-native/babel-preset'],
|
|
87
|
+
plugins: [
|
|
88
|
+
'@rn-org/react-native-thread/babel-plugin',
|
|
89
|
+
// ... your other plugins
|
|
90
|
+
],
|
|
91
|
+
};
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The plugin is a no-op on non-Hermes builds (JSC, V8, etc.).
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Quick start
|
|
99
|
+
|
|
100
|
+
```tsx
|
|
101
|
+
import { runOnJS, createThread, getThreads, destroyThread } from '@rn-org/react-native-thread';
|
|
102
|
+
|
|
103
|
+
// ── 1. Fire and forget on the shared background thread ──────────────────────
|
|
104
|
+
runOnJS((args) => {
|
|
105
|
+
console.log('Limit is', args.limit);
|
|
106
|
+
}, { limit: 42 });
|
|
107
|
+
|
|
108
|
+
// ── 2. Create a named, persistent thread ────────────────────────────────────
|
|
109
|
+
const worker = createThread('MyWorker');
|
|
110
|
+
|
|
111
|
+
// Send work + params
|
|
112
|
+
worker.run(
|
|
113
|
+
(args) => {
|
|
114
|
+
var result = 0;
|
|
115
|
+
for (var i = 0; i < args.limit; i++) result += i;
|
|
116
|
+
postMessage({ sum: result });
|
|
117
|
+
},
|
|
118
|
+
{ limit: 1_000_000 }
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
// Option A — callback
|
|
122
|
+
const unsubscribe = worker.onMessage((data) => {
|
|
123
|
+
console.log('Result from worker:', data);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// Option B — promise (resolves on the next message)
|
|
127
|
+
const data = await worker.onMessage();
|
|
128
|
+
console.log('Result from worker:', data);
|
|
129
|
+
|
|
130
|
+
// ── 3. List all running threads ─────────────────────────────────────────────
|
|
131
|
+
console.log(getThreads());
|
|
132
|
+
// [{ id: 1, name: 'RNOrgThread' }, { id: 2, name: 'MyWorker' }]
|
|
133
|
+
|
|
134
|
+
// ── 4. Clean up ─────────────────────────────────────────────────────────────
|
|
135
|
+
unsubscribe();
|
|
136
|
+
worker.destroy(); // by handle
|
|
137
|
+
destroyThread('MyWorker'); // by name — same effect
|
|
138
|
+
destroyThread(2); // by id — same effect
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## API reference
|
|
144
|
+
|
|
145
|
+
### `runOnJS`
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
function runOnJS(task: ThreadTask, params?: unknown): void
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Runs `task` on the **shared persistent background thread** (named `"RNOrgThread"`). The thread is created on first use and lives for the lifetime of the module. Ideal for fire-and-forget work where you don't need the overhead of managing a dedicated thread.
|
|
152
|
+
|
|
153
|
+
| Parameter | Type | Description |
|
|
154
|
+
|---|---|---|
|
|
155
|
+
| `task` | `ThreadTask` | Function or code string to execute. |
|
|
156
|
+
| `params` | `unknown` | Optional JSON-serialisable value passed as the first argument to the function. |
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
### `runOnNewJS`
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
function runOnNewJS(task: ThreadTask, params?: unknown, name?: string): ThreadHandle
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Creates a **new isolated thread**, immediately runs `task` on it, and returns a `ThreadHandle`. The thread persists until you call `handle.destroy()` or `destroyThread(...)`.
|
|
167
|
+
|
|
168
|
+
| Parameter | Type | Description |
|
|
169
|
+
|---|---|---|
|
|
170
|
+
| `task` | `ThreadTask` | Function or code string to execute. |
|
|
171
|
+
| `params` | `unknown` | Optional value passed as the first argument to the function. |
|
|
172
|
+
| `name` | `string` | Optional display name. Default: `RNThread-<id>`. |
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
### `createThread`
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
function createThread(name?: string): ThreadHandle
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Creates a **new persistent named thread** without immediately running any code. Use the returned `ThreadHandle` to dispatch work at any time.
|
|
183
|
+
|
|
184
|
+
| Parameter | Type | Description |
|
|
185
|
+
|---|---|---|
|
|
186
|
+
| `name` | `string` | Optional display name. Default: `RNThread-<id>`. |
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
### `getThreads`
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
function getThreads(): ThreadInfo[]
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Returns a snapshot of every live thread currently managed by the library, including the `runOnJS` shared thread once it has been started. Threads destroyed via `destroyThread` or `handle.destroy()` are removed from this list immediately.
|
|
197
|
+
|
|
198
|
+
```ts
|
|
199
|
+
const threads = getThreads();
|
|
200
|
+
// [
|
|
201
|
+
// { id: 1, name: 'RNOrgThread' },
|
|
202
|
+
// { id: 2, name: 'MyWorker' },
|
|
203
|
+
// ]
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
### `destroyThread`
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
function destroyThread(idOrName: number | string): void
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Destroys a thread and frees its resources. Accepts either the numeric thread ID or the thread's name. When a name is given, the first matching thread is destroyed.
|
|
215
|
+
|
|
216
|
+
This is the same function called by `ThreadHandle.destroy()`.
|
|
217
|
+
|
|
218
|
+
```ts
|
|
219
|
+
destroyThread('MyWorker'); // by name
|
|
220
|
+
destroyThread(2); // by id
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
In `__DEV__` mode a warning is logged if no matching thread is found.
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
### `onMessage`
|
|
228
|
+
|
|
229
|
+
```ts
|
|
230
|
+
// Callback — fires on every message from any thread
|
|
231
|
+
function onMessage(
|
|
232
|
+
handler: (data: unknown, threadId: number) => void
|
|
233
|
+
): () => void
|
|
234
|
+
|
|
235
|
+
// Promise — resolves once on the next message from any thread
|
|
236
|
+
function onMessage(): Promise<{ data: unknown; threadId: number }>
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Global listener that fires whenever **any** thread calls `postMessage(data)`. Prefer `ThreadHandle.onMessage` if you want messages scoped to a single thread.
|
|
240
|
+
|
|
241
|
+
```ts
|
|
242
|
+
// Callback variant
|
|
243
|
+
const unsub = onMessage((data, threadId) => {
|
|
244
|
+
console.log(`Thread ${threadId} sent:`, data);
|
|
245
|
+
});
|
|
246
|
+
unsub(); // remove listener
|
|
247
|
+
|
|
248
|
+
// Promise variant — awaits the next message from any thread
|
|
249
|
+
const { data, threadId } = await onMessage();
|
|
250
|
+
console.log(`Thread ${threadId} sent:`, data);
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
### `ThreadHandle`
|
|
256
|
+
|
|
257
|
+
Object returned by `createThread` and `runOnNewJS`.
|
|
258
|
+
|
|
259
|
+
```ts
|
|
260
|
+
type ThreadHandle = {
|
|
261
|
+
readonly id: number;
|
|
262
|
+
readonly name: string;
|
|
263
|
+
run(task: ThreadTask, params?: unknown): void;
|
|
264
|
+
/** Callback variant — fires on every message. Returns unsubscribe fn. */
|
|
265
|
+
onMessage(handler: (data: unknown) => void): () => void;
|
|
266
|
+
/** Promise variant — resolves on the next message from this thread. */
|
|
267
|
+
onMessage(): Promise<unknown>;
|
|
268
|
+
destroy(): void;
|
|
269
|
+
};
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
| Member | Description |
|
|
273
|
+
|---|---|
|
|
274
|
+
| `id` | Numeric ID assigned by the native layer. |
|
|
275
|
+
| `name` | Display name provided at creation (or the default `RNThread-<id>`). |
|
|
276
|
+
| `run(task, params?)` | Execute `task` on this thread. `params` is passed as the first argument to the function. Can be called multiple times. |
|
|
277
|
+
| `onMessage(handler)` | Subscribe to `postMessage` output from **this thread only**. Returns an unsubscribe function. |
|
|
278
|
+
| `onMessage()` | Returns a `Promise` that resolves with the next message from **this thread only**, then auto-unsubscribes. |
|
|
279
|
+
| `destroy()` | Shut down the thread and remove it from the registry. Equivalent to calling `destroyThread(handle.id)`. |
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
### `ThreadInfo`
|
|
284
|
+
|
|
285
|
+
```ts
|
|
286
|
+
type ThreadInfo = {
|
|
287
|
+
readonly id: number;
|
|
288
|
+
readonly name: string;
|
|
289
|
+
};
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Returned by `getThreads()`.
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
### `ThreadTask`
|
|
297
|
+
|
|
298
|
+
```ts
|
|
299
|
+
type ThreadTask = ((args?: any) => void) | string;
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Either an arrow function / function expression (transformed by the Babel plugin) or a raw JS code string. When a function is used, `params` is passed as the first argument (`args`).
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
## Thread globals
|
|
307
|
+
|
|
308
|
+
These globals are available inside every thread function:
|
|
309
|
+
|
|
310
|
+
### `postMessage`
|
|
311
|
+
|
|
312
|
+
```ts
|
|
313
|
+
declare function postMessage(data: unknown): void
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
Sends `data` back to the main JS thread. The value is JSON-serialised in the background thread and JSON-parsed before reaching the `onMessage` handler. Must be JSON-serialisable (`object`, `array`, `string`, `number`, `boolean`, or `null`).
|
|
317
|
+
|
|
318
|
+
```ts
|
|
319
|
+
worker.run((args) => {
|
|
320
|
+
postMessage({ status: 'done', value: args.multiply * 2 });
|
|
321
|
+
}, { multiply: 21 });
|
|
322
|
+
|
|
323
|
+
// Callback
|
|
324
|
+
worker.onMessage((data) => {
|
|
325
|
+
console.log(data); // { status: 'done', value: 42 }
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
// Promise
|
|
329
|
+
const data = await worker.onMessage();
|
|
330
|
+
console.log(data); // { status: 'done', value: 42 }
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
### `console`
|
|
336
|
+
|
|
337
|
+
`console.log`, `.info`, `.warn`, `.error`, and `.debug` are all available and route to:
|
|
338
|
+
|
|
339
|
+
- **iOS** — `NSLog`, visible in Xcode / Console.app; tagged `[RNThread-<id>]`.
|
|
340
|
+
- **Android** — `android.util.Log`, visible in Logcat; tagged `RNThread-<id>`.
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
### `__params__`
|
|
345
|
+
|
|
346
|
+
```ts
|
|
347
|
+
declare const __params__: any
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
Injected by the library when you pass a second argument to `run()`, `runOnJS()`, or `runOnNewJS()`. The value is JSON-serialised on the main thread and prepended to the code string as:
|
|
351
|
+
|
|
352
|
+
```js
|
|
353
|
+
var __params__ = <JSON>;
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
Must be JSON-serialisable. If you access `__params__` without passing a value, it will be `undefined`.
|
|
357
|
+
|
|
358
|
+
```ts
|
|
359
|
+
worker.run(
|
|
360
|
+
() => {
|
|
361
|
+
for (var i = 0; i < __params__.iterations; i++) {
|
|
362
|
+
// ...
|
|
363
|
+
}
|
|
364
|
+
postMessage('done');
|
|
365
|
+
},
|
|
366
|
+
{ iterations: 50_000 }
|
|
367
|
+
);
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
## Hermes & Babel plugin deep dive
|
|
373
|
+
|
|
374
|
+
### The problem
|
|
375
|
+
|
|
376
|
+
The Hermes compiler converts your JS bundle to bytecode at build time. Any function whose `.toString()` is called at runtime returns something like:
|
|
377
|
+
|
|
378
|
+
```
|
|
379
|
+
function () { [bytecode] }
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
Because this library must *serialise* functions to strings and send them to a separate JS engine, `.toString()` alone doesn't work under Hermes.
|
|
383
|
+
|
|
384
|
+
### The solution
|
|
385
|
+
|
|
386
|
+
The included Babel plugin runs at **compile time** — before Hermes touches the code — and replaces arrow-function / function-expression arguments to the thread API with string literals containing the original source wrapped as an IIFE:
|
|
387
|
+
|
|
388
|
+
```js
|
|
389
|
+
// Input (your source)
|
|
390
|
+
worker.run((args) => {
|
|
391
|
+
postMessage(args.greeting);
|
|
392
|
+
}, { greeting: 'hello' });
|
|
393
|
+
|
|
394
|
+
// Output (what Hermes compiles)
|
|
395
|
+
worker.run("((args) => {\n postMessage(args.greeting);\n})({\"greeting\":\"hello\"})");
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
The second `params` argument is left untouched; only the first (function) argument is transformed.
|
|
399
|
+
|
|
400
|
+
### Supported call sites
|
|
401
|
+
|
|
402
|
+
| Pattern | Transformed |
|
|
403
|
+
|---|---|
|
|
404
|
+
| `runOnJS(() => { ... })` | Yes |
|
|
405
|
+
| `runOnNewJS(() => { ... })` | Yes |
|
|
406
|
+
| `anyHandle.run(() => { ... })` | Yes |
|
|
407
|
+
| Raw code string `run("...")` | No (already a string) |
|
|
408
|
+
|
|
409
|
+
### Limitations
|
|
410
|
+
|
|
411
|
+
- Thread functions are **self-contained**: they run in an isolated JS engine with no access to the outer closure, imported modules, or the React tree.
|
|
412
|
+
- All values must be passed explicitly via the `args` parameter or `postMessage`.
|
|
413
|
+
- Thread function bodies must be **ASCII-safe**: Rhino (Android) does not support non-ASCII identifier characters in source mode.
|
|
414
|
+
- The `params` value must be **JSON-serialisable**: functions, `undefined`, `Map`, `Set`, etc. are not supported.
|
|
415
|
+
|
|
416
|
+
---
|
|
417
|
+
|
|
418
|
+
## Constraints summary
|
|
419
|
+
|
|
420
|
+
| Constraint | Reason |
|
|
421
|
+
|---|---|
|
|
422
|
+
| Functions are closure-isolated | They run in a completely separate JS engine |
|
|
423
|
+
| `params` must be JSON-serialisable | Serialised and passed as a function argument |
|
|
424
|
+
| `postMessage` payload must be JSON-serialisable | Transported as a JSON string over the bridge |
|
|
425
|
+
| Function body must be ASCII-safe | Rhino parser limitation |
|
|
426
|
+
| New Architecture required | TurboModule / Codegen only; no bridge fallback |
|
|
427
|
+
|
|
428
|
+
---
|
|
429
|
+
|
|
430
|
+
## Contributing
|
|
431
|
+
|
|
432
|
+
- [Development workflow](CONTRIBUTING.md#development-workflow)
|
|
433
|
+
- [Sending a pull request](CONTRIBUTING.md#sending-a-pull-request)
|
|
434
|
+
- [Code of conduct](CODE_OF_CONDUCT.md)
|
|
435
|
+
|
|
436
|
+
---
|
|
437
|
+
|
|
438
|
+
## License
|
|
439
|
+
|
|
440
|
+
MIT
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = "ReactNativeThread"
|
|
7
|
+
s.version = package["version"]
|
|
8
|
+
s.summary = package["description"]
|
|
9
|
+
s.homepage = package["homepage"]
|
|
10
|
+
s.license = package["license"]
|
|
11
|
+
s.authors = package["author"]
|
|
12
|
+
|
|
13
|
+
s.platforms = { :ios => min_ios_version_supported }
|
|
14
|
+
s.source = { :git => "https://github.com/sriharsha-rently/rn-org-react-native-thread.git", :tag => "#{s.version}" }
|
|
15
|
+
|
|
16
|
+
s.source_files = "ios/**/*.{h,m,mm,swift,cpp}"
|
|
17
|
+
s.private_header_files = "ios/**/*.h"
|
|
18
|
+
|
|
19
|
+
install_modules_dependencies(s)
|
|
20
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
buildscript {
|
|
2
|
+
ext.ReactNativeThread = [
|
|
3
|
+
kotlinVersion: "2.0.21",
|
|
4
|
+
minSdkVersion: 24,
|
|
5
|
+
compileSdkVersion: 36,
|
|
6
|
+
targetSdkVersion: 36
|
|
7
|
+
]
|
|
8
|
+
|
|
9
|
+
ext.getExtOrDefault = { prop ->
|
|
10
|
+
if (rootProject.ext.has(prop)) {
|
|
11
|
+
return rootProject.ext.get(prop)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return ReactNativeThread[prop]
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
repositories {
|
|
18
|
+
google()
|
|
19
|
+
mavenCentral()
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
dependencies {
|
|
23
|
+
classpath "com.android.tools.build:gradle:8.7.2"
|
|
24
|
+
// noinspection DifferentKotlinGradleVersion
|
|
25
|
+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
apply plugin: "com.android.library"
|
|
31
|
+
apply plugin: "kotlin-android"
|
|
32
|
+
|
|
33
|
+
apply plugin: "com.facebook.react"
|
|
34
|
+
|
|
35
|
+
android {
|
|
36
|
+
namespace "com.rnorg.reactnativethread"
|
|
37
|
+
|
|
38
|
+
compileSdkVersion getExtOrDefault("compileSdkVersion")
|
|
39
|
+
|
|
40
|
+
defaultConfig {
|
|
41
|
+
minSdkVersion getExtOrDefault("minSdkVersion")
|
|
42
|
+
targetSdkVersion getExtOrDefault("targetSdkVersion")
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
buildFeatures {
|
|
46
|
+
buildConfig true
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
buildTypes {
|
|
50
|
+
release {
|
|
51
|
+
minifyEnabled false
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
lint {
|
|
56
|
+
disable "GradleCompatible"
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
compileOptions {
|
|
60
|
+
sourceCompatibility JavaVersion.VERSION_1_8
|
|
61
|
+
targetCompatibility JavaVersion.VERSION_1_8
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
dependencies {
|
|
66
|
+
implementation "com.facebook.react:react-android"
|
|
67
|
+
// Rhino JS engine – provides a self-contained JS runtime for background threads
|
|
68
|
+
implementation "org.mozilla:rhino:1.7.15"
|
|
69
|
+
}
|