@capawesome/capacitor-nodejs 0.0.1

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.
Files changed (50) hide show
  1. package/Package.swift +42 -0
  2. package/README.md +443 -0
  3. package/android/CMakeLists.txt +32 -0
  4. package/android/build.gradle +123 -0
  5. package/android/src/main/AndroidManifest.xml +2 -0
  6. package/android/src/main/cpp/native-lib.cpp +192 -0
  7. package/android/src/main/java/io/capawesome/capacitorjs/plugins/nodejs/Nodejs.java +256 -0
  8. package/android/src/main/java/io/capawesome/capacitorjs/plugins/nodejs/NodejsConfig.java +30 -0
  9. package/android/src/main/java/io/capawesome/capacitorjs/plugins/nodejs/NodejsPlugin.java +159 -0
  10. package/android/src/main/java/io/capawesome/capacitorjs/plugins/nodejs/classes/CustomException.java +20 -0
  11. package/android/src/main/java/io/capawesome/capacitorjs/plugins/nodejs/classes/CustomExceptions.java +23 -0
  12. package/android/src/main/java/io/capawesome/capacitorjs/plugins/nodejs/classes/events/MessageEvent.java +27 -0
  13. package/android/src/main/java/io/capawesome/capacitorjs/plugins/nodejs/classes/options/SendOptions.java +48 -0
  14. package/android/src/main/java/io/capawesome/capacitorjs/plugins/nodejs/classes/options/StartOptions.java +81 -0
  15. package/android/src/main/java/io/capawesome/capacitorjs/plugins/nodejs/classes/results/IsReadyResult.java +22 -0
  16. package/android/src/main/java/io/capawesome/capacitorjs/plugins/nodejs/interfaces/Callback.java +5 -0
  17. package/android/src/main/java/io/capawesome/capacitorjs/plugins/nodejs/interfaces/EmptyCallback.java +5 -0
  18. package/android/src/main/java/io/capawesome/capacitorjs/plugins/nodejs/interfaces/NonEmptyResultCallback.java +7 -0
  19. package/android/src/main/java/io/capawesome/capacitorjs/plugins/nodejs/interfaces/Result.java +7 -0
  20. package/android/src/main/res/.gitkeep +0 -0
  21. package/dist/docs.json +432 -0
  22. package/dist/esm/definitions.d.ts +214 -0
  23. package/dist/esm/definitions.js +38 -0
  24. package/dist/esm/definitions.js.map +1 -0
  25. package/dist/esm/index.d.ts +4 -0
  26. package/dist/esm/index.js +7 -0
  27. package/dist/esm/index.js.map +1 -0
  28. package/dist/esm/web.d.ts +8 -0
  29. package/dist/esm/web.js +16 -0
  30. package/dist/esm/web.js.map +1 -0
  31. package/dist/plugin.cjs.js +68 -0
  32. package/dist/plugin.cjs.js.map +1 -0
  33. package/dist/plugin.js +71 -0
  34. package/dist/plugin.js.map +1 -0
  35. package/ios/Plugin/Assets/builtin_modules/bridge/index.js +205 -0
  36. package/ios/Plugin/Classes/Events/MessageEvent.swift +19 -0
  37. package/ios/Plugin/Classes/Options/SendOptions.swift +19 -0
  38. package/ios/Plugin/Classes/Options/StartOptions.swift +32 -0
  39. package/ios/Plugin/Classes/Results/IsReadyResult.swift +16 -0
  40. package/ios/Plugin/Enums/CustomError.swift +46 -0
  41. package/ios/Plugin/Nodejs.swift +148 -0
  42. package/ios/Plugin/NodejsConfig.swift +6 -0
  43. package/ios/Plugin/NodejsPlugin.swift +102 -0
  44. package/ios/Plugin/Protocols/Result.swift +6 -0
  45. package/ios/PluginNative/NodeRunner.mm +221 -0
  46. package/ios/PluginNative/bridge.cpp +225 -0
  47. package/ios/PluginNative/bridge.h +15 -0
  48. package/ios/PluginNative/include/NodeRunner.h +12 -0
  49. package/package.json +93 -0
  50. package/scripts/postinstall.js +109 -0
package/Package.swift ADDED
@@ -0,0 +1,42 @@
1
+ // swift-tools-version: 5.9
2
+ import PackageDescription
3
+
4
+ let package = Package(
5
+ name: "CapawesomeCapacitorNodejs",
6
+ platforms: [.iOS(.v15)],
7
+ products: [
8
+ .library(
9
+ name: "CapawesomeCapacitorNodejs",
10
+ targets: ["NodejsPlugin"])
11
+ ],
12
+ dependencies: [
13
+ .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.0.0")
14
+ ],
15
+ targets: [
16
+ .binaryTarget(
17
+ name: "NodeMobile",
18
+ path: "ios/libnode/NodeMobile.xcframework"),
19
+ .target(
20
+ name: "NodejsPluginNative",
21
+ dependencies: ["NodeMobile"],
22
+ path: "ios/PluginNative",
23
+ publicHeadersPath: "include",
24
+ cxxSettings: [
25
+ .headerSearchPath("../libnode/include/node")
26
+ ]),
27
+ .target(
28
+ name: "NodejsPlugin",
29
+ dependencies: [
30
+ .product(name: "Capacitor", package: "capacitor-swift-pm"),
31
+ .product(name: "Cordova", package: "capacitor-swift-pm"),
32
+ "NodejsPluginNative"
33
+ ],
34
+ path: "ios/Plugin",
35
+ resources: [.copy("Assets/builtin_modules")]),
36
+ .testTarget(
37
+ name: "NodejsPluginTests",
38
+ dependencies: ["NodejsPlugin"],
39
+ path: "ios/PluginTests")
40
+ ],
41
+ cxxLanguageStandard: .gnucxx17
42
+ )
package/README.md ADDED
@@ -0,0 +1,443 @@
1
+ # @capawesome/capacitor-nodejs
2
+
3
+ Capacitor plugin for running [Node.js](https://nodejs.org/) in mobile apps.[^1][^2]
4
+
5
+ <div class="capawesome-z29o10a">
6
+ <a href="https://cloud.capawesome.io/" target="_blank">
7
+ <img alt="Deliver Live Updates to your Capacitor app with Capawesome Cloud" src="https://cloud.capawesome.io/assets/banners/cloud-build-and-deploy-capacitor-apps.png?t=1" />
8
+ </a>
9
+ </div>
10
+
11
+ ## Features
12
+
13
+ We are proud to offer one of the most complete and feature-rich Capacitor plugins for running Node.js in mobile apps. Here are some of the key features:
14
+
15
+ - 🖥️ **Cross-platform**: Supports Android and iOS.
16
+ - 🚀 **Node.js runtime**: Embeds a complete Node.js runtime based on [Node.js for Mobile Apps](https://github.com/nodejs-mobile/nodejs-mobile).
17
+ - 🧵 **Background thread**: Runs the Node.js engine on a dedicated background thread to avoid blocking the UI.
18
+ - 🔁 **Bidirectional communication**: Event-based message passing between the Capacitor app and the Node.js runtime.
19
+ - 📦 **npm ecosystem**: Use npm packages that are not browser-compatible and rely on Node.js core modules.
20
+ - 🛠️ **Configurable**: Start the Node.js runtime automatically or manually with custom arguments, environment variables and script.
21
+ - 🔁 **Up-to-date**: Always supports the latest Capacitor version.
22
+
23
+ Missing a feature? Just [open an issue](https://github.com/capawesome-team/capacitor-plugins/issues) and we'll take a look!
24
+
25
+ ## Newsletter
26
+
27
+ Stay up to date with the latest news and updates about the Capawesome, Capacitor, and Ionic ecosystem by subscribing to our [Capawesome Newsletter](https://cloud.capawesome.io/newsletter/).
28
+
29
+ ## Compatibility
30
+
31
+ | Plugin Version | Capacitor Version | Status |
32
+ | -------------- | ----------------- | -------------- |
33
+ | 0.0.x | >=8.x.x | Active support |
34
+
35
+ ## Installation
36
+
37
+ You can use our **AI-Assisted Setup** to install the plugin.
38
+ Add the [Capawesome Skills](https://github.com/capawesome-team/skills) to your AI tool using the following command:
39
+
40
+ ```bash
41
+ npx skills add capawesome-team/skills --skill capacitor-plugins
42
+ ```
43
+
44
+ Then use the following prompt:
45
+
46
+ ```
47
+ Use the `capacitor-plugins` skill from `capawesome-team/skills` to install the `@capawesome/capacitor-nodejs` plugin in my project.
48
+ ```
49
+
50
+ If you prefer **Manual Setup**, install the plugin by running the following commands and follow the platform-specific instructions below:
51
+
52
+ ```bash
53
+ npm install @capawesome/capacitor-nodejs
54
+ npx cap sync
55
+ ```
56
+
57
+ **Attention**: This plugin embeds the [Node.js for Mobile Apps](https://github.com/nodejs-mobile/nodejs-mobile) runtime binaries. The binaries are not included in the npm package but downloaded on demand: the Android binaries are downloaded by the Gradle build and the iOS binaries are downloaded during `npm install` (only on macOS). Set the `CAPACITOR_NODEJS_SKIP_DOWNLOAD` environment variable to `1` to skip the iOS download.
58
+
59
+ ### Android
60
+
61
+ #### Variables
62
+
63
+ If needed, you can define the following project variables in your app's `variables.gradle` file to change the default version of the runtime:
64
+
65
+ - `$nodejsMobileVersion` version of the Node.js for Mobile Apps runtime (default: `18.20.4-capawesome.1`, a [16 KB page size compatible build](https://github.com/capawesome-team/nodejs-mobile/releases))
66
+ - `$nodejsMobileAndroidUrl` download URL of the Android runtime binaries (default: GitHub release of `$nodejsMobileVersion`)
67
+ - `$nodejsMobileAndroidSha256` SHA-256 checksum of the Android runtime binaries download (default: checksum of `$nodejsMobileVersion`)
68
+
69
+ ### iOS
70
+
71
+ This plugin currently only supports **Swift Package Manager**. CocoaPods is not supported.
72
+
73
+ If you install dependencies with disabled lifecycle scripts (e.g. `npm install --ignore-scripts`), the iOS runtime binaries are not downloaded automatically. In this case, run the download script manually before building your app:
74
+
75
+ ```bash
76
+ node node_modules/@capawesome/capacitor-nodejs/scripts/postinstall.js
77
+ ```
78
+
79
+ ## Configuration
80
+
81
+ <docgen-config>
82
+ <!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
83
+
84
+ | Prop | Type | Description | Default | Since |
85
+ | --------------- | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- | ----- |
86
+ | **`nodeDir`** | <code>string</code> | The directory of the Node.js project, relative to the Capacitor `webDir`. Only available on Android and iOS. | <code>'nodejs'</code> | 0.0.1 |
87
+ | **`startMode`** | <code>'manual' \| 'auto'</code> | The start mode of the Node.js runtime. If set to `auto`, the Node.js runtime starts automatically when the app is launched. If set to `manual`, the Node.js runtime must be started manually using the `start(...)` method. Only available on Android and iOS. | <code>'auto'</code> | 0.0.1 |
88
+
89
+ ### Examples
90
+
91
+ In `capacitor.config.json`:
92
+
93
+ ```json
94
+ {
95
+ "plugins": {
96
+ "Nodejs": {
97
+ "nodeDir": 'custom-nodejs',
98
+ "startMode": 'manual'
99
+ }
100
+ }
101
+ }
102
+ ```
103
+
104
+ In `capacitor.config.ts`:
105
+
106
+ ```ts
107
+ /// <reference types="@capawesome/capacitor-nodejs" />
108
+
109
+ import { CapacitorConfig } from '@capacitor/cli';
110
+
111
+ const config: CapacitorConfig = {
112
+ plugins: {
113
+ Nodejs: {
114
+ nodeDir: 'custom-nodejs',
115
+ startMode: 'manual',
116
+ },
117
+ },
118
+ };
119
+
120
+ export default config;
121
+ ```
122
+
123
+ </docgen-config>
124
+
125
+ ## Demo
126
+
127
+ A working example can be found [here](https://github.com/capawesome-team/capacitor-plugins/tree/main/packages/nodejs/example).
128
+
129
+ ## Usage
130
+
131
+ The plugin runs the Node.js project located in the `nodejs` directory (see the `nodeDir` configuration option) inside your Capacitor `webDir`. Make sure your web build outputs the Node.js project to this directory, for example by placing it in the `public` directory of your web project:
132
+
133
+ ```
134
+ my-app
135
+ ├── capacitor.config.json // webDir: 'dist'
136
+ └── src
137
+ └── public
138
+ └── nodejs
139
+ ├── package.json
140
+ └── index.js
141
+ ```
142
+
143
+ The `package.json` file of the Node.js project defines the script file to run in the `main` field:
144
+
145
+ ```json
146
+ {
147
+ "name": "nodejs-project",
148
+ "version": "1.0.0",
149
+ "main": "index.js"
150
+ }
151
+ ```
152
+
153
+ Inside the script file (`index.js` in this example), the built-in `bridge` module provides the communication channel to the Capacitor app:
154
+
155
+ ```js
156
+ const { app, channel } = require('bridge');
157
+
158
+ // Receive messages from the Capacitor app.
159
+ channel.on('my-event', (...args) => {
160
+ // Send messages to the Capacitor app.
161
+ channel.post('my-response', 'Hello from Node.js!');
162
+ });
163
+
164
+ // Get a writable directory for persistent file storage.
165
+ const dataDir = app.datadir();
166
+
167
+ // Listen for app lifecycle events.
168
+ app.on('pause', pauseLock => {
169
+ pauseLock.release();
170
+ });
171
+ app.on('resume', () => {});
172
+ ```
173
+
174
+ **Attention**: The Node.js project directory may be overwritten during app updates. Store persistent data in the directory returned by `app.datadir()`.
175
+
176
+ In your Capacitor app, you can then use the plugin to start the Node.js runtime and exchange messages with it:
177
+
178
+ ```typescript
179
+ import { Nodejs } from '@capawesome/capacitor-nodejs';
180
+
181
+ const isReady = async () => {
182
+ const { ready } = await Nodejs.isReady();
183
+ return ready;
184
+ };
185
+
186
+ const send = async () => {
187
+ await Nodejs.send({
188
+ eventName: 'my-event',
189
+ args: ['Hello from Capacitor!'],
190
+ });
191
+ };
192
+
193
+ const start = async () => {
194
+ // Only available if the `startMode` configuration option is set to `manual`.
195
+ await Nodejs.start({
196
+ args: ['--option', 'value'],
197
+ env: { MY_ENV_VAR: 'value' },
198
+ script: 'custom-main.js',
199
+ });
200
+ };
201
+
202
+ const addReadyListener = async () => {
203
+ await Nodejs.addListener('ready', () => {
204
+ console.log('The Node.js runtime is ready.');
205
+ });
206
+ };
207
+
208
+ const addMessageListener = async () => {
209
+ await Nodejs.addListener('message', event => {
210
+ console.log('Received message:', event.eventName, event.args);
211
+ });
212
+ };
213
+ ```
214
+
215
+ To use npm packages, run `npm install --omit=dev` inside the Node.js project directory before building your web project. It's recommended to bundle the Node.js project into a single file (e.g. with [esbuild](https://esbuild.github.io/)) to improve the startup time.
216
+
217
+ ## API
218
+
219
+ <docgen-index>
220
+
221
+ * [`isReady()`](#isready)
222
+ * [`send(...)`](#send)
223
+ * [`start(...)`](#start)
224
+ * [`addListener('message', ...)`](#addlistenermessage-)
225
+ * [`addListener('ready', ...)`](#addlistenerready-)
226
+ * [`removeAllListeners()`](#removealllisteners)
227
+ * [Interfaces](#interfaces)
228
+ * [Type Aliases](#type-aliases)
229
+
230
+ </docgen-index>
231
+
232
+ <docgen-api>
233
+ <!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
234
+
235
+ ### isReady()
236
+
237
+ ```typescript
238
+ isReady() => Promise<IsReadyResult>
239
+ ```
240
+
241
+ Check if the Node.js runtime is ready to receive messages.
242
+
243
+ The Node.js runtime is considered ready as soon as the Node.js project
244
+ has required the `bridge` module.
245
+
246
+ Only available on Android and iOS.
247
+
248
+ **Returns:** <code>Promise&lt;<a href="#isreadyresult">IsReadyResult</a>&gt;</code>
249
+
250
+ **Since:** 0.0.1
251
+
252
+ --------------------
253
+
254
+
255
+ ### send(...)
256
+
257
+ ```typescript
258
+ send(options: SendOptions) => Promise<void>
259
+ ```
260
+
261
+ Send a message to the Node.js runtime.
262
+
263
+ This method is only available when the Node.js runtime is ready.
264
+ Use the `isReady()` method or the `ready` event to check if the
265
+ Node.js runtime is ready.
266
+
267
+ Only available on Android and iOS.
268
+
269
+ | Param | Type |
270
+ | ------------- | --------------------------------------------------- |
271
+ | **`options`** | <code><a href="#sendoptions">SendOptions</a></code> |
272
+
273
+ **Since:** 0.0.1
274
+
275
+ --------------------
276
+
277
+
278
+ ### start(...)
279
+
280
+ ```typescript
281
+ start(options?: StartOptions | undefined) => Promise<void>
282
+ ```
283
+
284
+ Start the Node.js runtime manually.
285
+
286
+ This method is only available if the `startMode` configuration option
287
+ is set to `manual`.
288
+
289
+ **Attention**: The Node.js runtime can only be started once per app
290
+ launch. Stopping and restarting the Node.js runtime is not supported.
291
+
292
+ Only available on Android and iOS.
293
+
294
+ | Param | Type |
295
+ | ------------- | ----------------------------------------------------- |
296
+ | **`options`** | <code><a href="#startoptions">StartOptions</a></code> |
297
+
298
+ **Since:** 0.0.1
299
+
300
+ --------------------
301
+
302
+
303
+ ### addListener('message', ...)
304
+
305
+ ```typescript
306
+ addListener(eventName: 'message', listenerFunc: (event: MessageEvent) => void) => Promise<PluginListenerHandle>
307
+ ```
308
+
309
+ Called when a message is received from the Node.js runtime.
310
+
311
+ Only available on Android and iOS.
312
+
313
+ | Param | Type |
314
+ | ------------------ | ------------------------------------------------------------------------- |
315
+ | **`eventName`** | <code>'message'</code> |
316
+ | **`listenerFunc`** | <code>(event: <a href="#messageevent">MessageEvent</a>) =&gt; void</code> |
317
+
318
+ **Returns:** <code>Promise&lt;<a href="#pluginlistenerhandle">PluginListenerHandle</a>&gt;</code>
319
+
320
+ **Since:** 0.0.1
321
+
322
+ --------------------
323
+
324
+
325
+ ### addListener('ready', ...)
326
+
327
+ ```typescript
328
+ addListener(eventName: 'ready', listenerFunc: () => void) => Promise<PluginListenerHandle>
329
+ ```
330
+
331
+ Called when the Node.js runtime is ready to receive messages.
332
+
333
+ Only available on Android and iOS.
334
+
335
+ | Param | Type |
336
+ | ------------------ | -------------------------- |
337
+ | **`eventName`** | <code>'ready'</code> |
338
+ | **`listenerFunc`** | <code>() =&gt; void</code> |
339
+
340
+ **Returns:** <code>Promise&lt;<a href="#pluginlistenerhandle">PluginListenerHandle</a>&gt;</code>
341
+
342
+ **Since:** 0.0.1
343
+
344
+ --------------------
345
+
346
+
347
+ ### removeAllListeners()
348
+
349
+ ```typescript
350
+ removeAllListeners() => Promise<void>
351
+ ```
352
+
353
+ Remove all listeners for this plugin.
354
+
355
+ **Since:** 0.0.1
356
+
357
+ --------------------
358
+
359
+
360
+ ### Interfaces
361
+
362
+
363
+ #### IsReadyResult
364
+
365
+ | Prop | Type | Description | Since |
366
+ | ----------- | -------------------- | ---------------------------------------------------------------- | ----- |
367
+ | **`ready`** | <code>boolean</code> | Whether or not the Node.js runtime is ready to receive messages. | 0.0.1 |
368
+
369
+
370
+ #### SendOptions
371
+
372
+ | Prop | Type | Description | Since |
373
+ | --------------- | ------------------------- | ----------------------------------------------------- | ----- |
374
+ | **`args`** | <code>MessageArg[]</code> | The arguments to send to the Node.js runtime. | 0.0.1 |
375
+ | **`eventName`** | <code>string</code> | The name of the event to send to the Node.js runtime. | 0.0.1 |
376
+
377
+
378
+ #### StartOptions
379
+
380
+ | Prop | Type | Description | Default | Since |
381
+ | ------------ | --------------------------------------- | ------------------------------------------------------------------------------ | -------------------------------------------------------------------------------- | ----- |
382
+ | **`args`** | <code>string[]</code> | The arguments to pass to the Node.js process. | | 0.0.1 |
383
+ | **`env`** | <code>{ [key: string]: string; }</code> | The environment variables to set for the Node.js process. | | 0.0.1 |
384
+ | **`script`** | <code>string</code> | The path of the script file to run, relative to the Node.js project directory. | <code>The `main` field of the `package.json` file of the Node.js project.</code> | 0.0.1 |
385
+
386
+
387
+ #### PluginListenerHandle
388
+
389
+ | Prop | Type |
390
+ | ------------ | ----------------------------------------- |
391
+ | **`remove`** | <code>() =&gt; Promise&lt;void&gt;</code> |
392
+
393
+
394
+ #### MessageEvent
395
+
396
+ | Prop | Type | Description | Since |
397
+ | --------------- | ------------------------- | -------------------------------------------------------- | ----- |
398
+ | **`args`** | <code>MessageArg[]</code> | The arguments received from the Node.js runtime. | 0.0.1 |
399
+ | **`eventName`** | <code>string</code> | The name of the event received from the Node.js runtime. | 0.0.1 |
400
+
401
+
402
+ ### Type Aliases
403
+
404
+
405
+ #### MessageArg
406
+
407
+ A single argument of a message that is exchanged with the Node.js runtime.
408
+
409
+ <code>string | number | boolean</code>
410
+
411
+ </docgen-api>
412
+
413
+ ## Limitations
414
+
415
+ The underlying [Node.js for Mobile Apps](https://github.com/nodejs-mobile/nodejs-mobile) runtime has some limitations that you should be aware of:
416
+
417
+ - **Single instance**: The Node.js runtime can only be started once per app launch. Stopping and restarting the runtime is not supported.
418
+ - **No child processes**: The `child_process` module is not supported on mobile platforms.
419
+ - **No JIT on iOS**: On iOS, the JavaScript engine runs in interpreter-only mode (no JIT compilation), which results in slower JavaScript execution compared to Android.
420
+ - **App size**: Embedding the Node.js runtime increases the app size by several tens of megabytes per CPU architecture.
421
+ - **Native addons**: Node.js native addons are only supported on Android if they are provided as prebuilds (see [`node-gyp-build`](https://github.com/prebuild/node-gyp-build)) for the target architectures.
422
+ - **`process.exit()`**: Calling `process.exit()` is not allowed by the Apple App Store guidelines.
423
+
424
+ ## FAQ
425
+
426
+ ### Which Node.js version is supported?
427
+
428
+ The plugin currently runs Node.js `18.20.4`, the latest version available from [Node.js for Mobile Apps](https://github.com/nodejs-mobile/nodejs-mobile). Support for newer Node.js versions requires self-built runtime binaries for mobile platforms, which we are evaluating.
429
+
430
+ ### Why is there no `stop()` method?
431
+
432
+ The underlying runtime only supports a single Node.js instance per app launch and provides no API to stop or restart it. A `stop()` method would therefore leave the app in a state where Node.js could never be started again until the app is restarted. If you need to stop work in the Node.js runtime, send a message (e.g. a `shutdown` event) and let your Node.js code stop its servers and timers. The idle runtime consumes negligible resources.
433
+
434
+ ## Changelog
435
+
436
+ See [CHANGELOG.md](https://github.com/capawesome-team/capacitor-plugins/blob/main/packages/nodejs/CHANGELOG.md).
437
+
438
+ ## License
439
+
440
+ See [LICENSE](https://github.com/capawesome-team/capacitor-plugins/blob/main/packages/nodejs/LICENSE).
441
+
442
+ [^1]: This project is not affiliated with, endorsed by, sponsored by, or approved by the OpenJS Foundation or any of their affiliates or subsidiaries.
443
+ [^2]: `Node.js` is a registered trademark of the OpenJS Foundation.
@@ -0,0 +1,32 @@
1
+ cmake_minimum_required(VERSION 3.22.1)
2
+
3
+ project(capacitor-nodejs)
4
+
5
+ if(NOT DEFINED LIBNODE_DIR)
6
+ message(FATAL_ERROR "LIBNODE_DIR must be defined.")
7
+ endif()
8
+
9
+ add_library(capacitor-nodejs
10
+ SHARED
11
+ src/main/cpp/native-lib.cpp
12
+ ../ios/PluginNative/bridge.cpp)
13
+
14
+ include_directories(${LIBNODE_DIR}/include/node)
15
+ include_directories(../ios/PluginNative)
16
+
17
+ add_library(libnode
18
+ SHARED
19
+ IMPORTED)
20
+
21
+ set_target_properties(libnode
22
+ PROPERTIES IMPORTED_LOCATION
23
+ ${LIBNODE_DIR}/bin/${ANDROID_ABI}/libnode.so)
24
+
25
+ find_library(log-lib log)
26
+
27
+ # Support devices with a 16 KB page size.
28
+ target_link_options(capacitor-nodejs PRIVATE "-Wl,-z,max-page-size=16384")
29
+
30
+ target_link_libraries(capacitor-nodejs
31
+ libnode
32
+ ${log-lib})
@@ -0,0 +1,123 @@
1
+ ext {
2
+ junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
3
+ androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.1'
4
+ androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.3.0'
5
+ androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.7.0'
6
+ nodejsMobileVersion = project.hasProperty('nodejsMobileVersion') ? rootProject.ext.nodejsMobileVersion : '18.20.4-capawesome.1'
7
+ nodejsMobileAndroidUrl = project.hasProperty('nodejsMobileAndroidUrl')
8
+ ? rootProject.ext.nodejsMobileAndroidUrl
9
+ : "https://github.com/capawesome-team/nodejs-mobile/releases/download/v${nodejsMobileVersion}/nodejs-mobile-v${nodejsMobileVersion}-android.zip"
10
+ nodejsMobileAndroidSha256 = project.hasProperty('nodejsMobileAndroidSha256')
11
+ ? rootProject.ext.nodejsMobileAndroidSha256
12
+ : '1b3c7979c81aec89a7f51b29af1f4875a5d637727ad6e2c392cdf2e127715da9'
13
+ }
14
+
15
+ def libnodeCacheDir = new File(gradle.gradleUserHomeDir, 'caches/capawesome-capacitor-nodejs')
16
+ def libnodeDir = new File(libnodeCacheDir, "nodejs-mobile-v${nodejsMobileVersion}-android")
17
+
18
+ tasks.register('downloadLibnode') {
19
+ def cacheDir = libnodeCacheDir
20
+ def zipFile = new File(cacheDir, "nodejs-mobile-v${nodejsMobileVersion}-android.zip")
21
+ doLast {
22
+ def expectedSha256 = nodejsMobileAndroidSha256
23
+ def calculateSha256 = { file ->
24
+ def digest = java.security.MessageDigest.getInstance('SHA-256')
25
+ file.eachByte(1024 * 1024) { buffer, length -> digest.update(buffer, 0, length) }
26
+ digest.digest().collect { String.format('%02x', it) }.join()
27
+ }
28
+ if (!zipFile.exists() || (expectedSha256 && calculateSha256(zipFile) != expectedSha256)) {
29
+ cacheDir.mkdirs()
30
+ logger.lifecycle("Downloading Node.js for Mobile Apps from ${nodejsMobileAndroidUrl}...")
31
+ new URL(nodejsMobileAndroidUrl).withInputStream { input -> zipFile.withOutputStream { output -> output << input } }
32
+ }
33
+ if (expectedSha256) {
34
+ def actualSha256 = calculateSha256(zipFile)
35
+ if (actualSha256 != expectedSha256) {
36
+ zipFile.delete()
37
+ throw new GradleException("Checksum verification failed for ${zipFile.name}. Expected ${expectedSha256} but got ${actualSha256}.")
38
+ }
39
+ }
40
+ if (!new File(libnodeDir, 'include').exists()) {
41
+ copy {
42
+ from zipTree(zipFile)
43
+ into libnodeDir
44
+ }
45
+ }
46
+ }
47
+ }
48
+
49
+ tasks.whenTaskAdded { task ->
50
+ if (task.name.startsWith('configureCMake') || task.name.startsWith('buildCMake') || task.name.startsWith('externalNativeBuild')) {
51
+ task.dependsOn('downloadLibnode')
52
+ }
53
+ }
54
+
55
+ buildscript {
56
+ repositories {
57
+ google()
58
+ mavenCentral()
59
+ }
60
+ dependencies {
61
+ classpath 'com.android.tools.build:gradle:8.13.0'
62
+ }
63
+ }
64
+
65
+ apply plugin: 'com.android.library'
66
+
67
+ android {
68
+ namespace = "io.capawesome.capacitorjs.plugins.nodejs"
69
+ compileSdk = project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 36
70
+ defaultConfig {
71
+ minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 24
72
+ targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 36
73
+ versionCode 1
74
+ versionName "1.0"
75
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
76
+ externalNativeBuild {
77
+ cmake {
78
+ arguments "-DLIBNODE_DIR=${libnodeDir.absolutePath}", "-DANDROID_STL=c++_shared"
79
+ }
80
+ }
81
+ ndk {
82
+ abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86_64'
83
+ }
84
+ }
85
+ externalNativeBuild {
86
+ cmake {
87
+ path 'CMakeLists.txt'
88
+ }
89
+ }
90
+ sourceSets {
91
+ main {
92
+ assets.srcDirs += '../ios/Plugin/Assets'
93
+ }
94
+ }
95
+ buildTypes {
96
+ release {
97
+ minifyEnabled false
98
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
99
+ }
100
+ }
101
+ lintOptions {
102
+ abortOnError = false
103
+ }
104
+ compileOptions {
105
+ sourceCompatibility JavaVersion.VERSION_21
106
+ targetCompatibility JavaVersion.VERSION_21
107
+ }
108
+ }
109
+
110
+ repositories {
111
+ google()
112
+ mavenCentral()
113
+ }
114
+
115
+
116
+ dependencies {
117
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
118
+ implementation project(':capacitor-android')
119
+ implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
120
+ testImplementation "junit:junit:$junitVersion"
121
+ androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
122
+ androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
123
+ }
@@ -0,0 +1,2 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ </manifest>