➡ A full-fledged Node.js runtime for Capacitor apps.
ℹ️ This project uses the Node.js for Mobile Apps toolkit to add NodeJS support in Android and IOS
⚠ In early development ⚠
- Note: The project is still very unstable, if you have any problems or suggestions it would be nice if you create an issue.
- Only the Android platform is currently supported.
- When the project is stable it will be published on NPM.
- Features like IOS- and Electron- support or a command to update the NodeJS runtime will be added in the future.
You've to use Capacitor v3. This project isn't compatible with lower versions of Capacitor.
npm install hampoelz/capacitor-nodejs
npx cap sync
The starting point of the NodeJS integration is a package.json
file.
So we need to go into the webdir (For Angular, this is www
, React is build
, and Vue is dist
. If you don’t know right now, you can check this value in the capacitor.config.ts
.) and create a package.json
file:
{
"name": "capacitor-node-project",
"version": "1.0.0",
"description": "node part of the project",
"main": "main.js",
"author": "hampoelz",
"license": "MIT"
}
The main script of the NodeJS integration is defined in the package.json
file, in this case main.js
. The NodeJS apis and modules can then be accessed from there. Therefore we also have to create a main.js
file inside the Capacitor webdir.
The main script main.js
could look like this:
const { channel } = require('bridge');
channel.addListener('msg-from-capacitor', message => {
console.log('[node] Message from Capacitor code: ' + message);
channel.send("msg-from-nodejs", "Replying to this message: " + message, "And optionally add further args");
});
After that, our project structure should look something like this:
my-capacitor-app/
+-- android
+-- node_modules
+-- www (capacitor webdir)
| +-- css
| +-- js
| +-- index.html
| +-- main.js (nodejs main file, defined in package.json)
| +-- manifest.json
| +-- package.json (nodejs start point)
+-- .gitignore
+-- capacitor.config.json
+-- package-lock.json
+-- package.json
+-- README.md
Now in our Capacitor app we can send messages from the NodeJS layer and wait for them:
import { NodeJS } from 'capacitor-nodejs';
NodeJS.addListener('msg-from-nodejs', event => {
document.body.innerHTML = `<p>First argument: ${event.args[0]}<br>Second argument: ${event.args[1]}</p>`
console.log(event);
});
NodeJS.send({
eventName: "msg-from-capacitor",
args: [ "Hello from Capacitor!" ]
});
We can customize the NodeJS project directory. By default it is in the root of the Capacitor webdir. But it can be changed in the capacitor.config.json
file so that the Capacitor- and the NodeJS- project are more separated.
{
"plugins": {
"NodeJS": {
"nodeDir": "nodejs"
}
}
}
For example, if we change it to nodejs
, we've to create a nodejs
directory inside the Capacitor webdir and move the files package.json
and main.js
to the newly created directory. Then our project structure should look something like this:
my-capacitor-app/
+-- android
+-- node_modules
+-- www
| +-- css
| +-- js
| +-- nodejs (our new node directory)
| | +-- main.js
| | +-- package.json
| +-- index.html
| +-- manifest.json
+-- .gitignore
+-- capacitor.config.json
+-- package-lock.json
+-- package.json
+-- README.md
+-- ...
Node modules can be added to the project using npm. The Node modules have to be installed in the NodeJS project folder in which we created the package.json
file.
Go to the NodeJS project folder and proceed with the installation of the Node modules you want to add to your Node.js project.
Sync and rebuild your Capacitor project so that the newly added Node modules are added to the application.
On Android, the plugin extracts the project files and the Node modules from the APK assets in order to make them available to the Node.js for Mobile Apps engine. They are extracted from the APK and copied to a working folder (context.getFilesDir().getAbsolutePath() + "/public/<nodeDir>"
-> <nodeDir>
is the NodeJS project folder configured in the capacitor.config.json
file. If there is no configuration, the <nodeDir>
can be omitted in the path) when the application is launched for the first time or a new version of the application has been installed.
⚠️ WarningGiven the project folder will be overwritten after each application update, it should not be used for persistent data storage.
You may want to add a gitignore file to ignore unnecessary files. To do this, create a new file named .gitignore
in the NodeJS project folder and copy the contents of github.com/github/gitignore/blob/master/Node.gitignore into it.
The channel
module is an Event Emitter. It provides a few methods so you can send messages from the NodeJS process to the capacitor layer. You can also receive replies from the capacitor layer.
It has the following method to listen for events and send messages:
eventName
Stringlistener
Function...args
any[]
Listens to eventName
, when a new message arrives listener
would be called with
listener(args...)
.
eventName
Stringlistener
Function...args
any[]
Adds a one time listener
function for the event. This listener
is invoked
only the next time a message is sent to eventName
, after which it is removed.
eventName
Stringlistener
Function...args
any[]
Alias for channel.on(eventName, listener)
.
eventName
Stringlistener
Function...args
any[]
Removes the specified listener
from the listener array for the specified
eventName
.
eventName
String
Removes all listeners, or those of the specified eventName
.
eventName
String...args
any[]
Send a message to the capacitor layer via eventName
, along with
arguments. Arguments will be serialized with JSON.
The NodeJS
module is the API you use in your Capacitor app. It provides a few methods so you can send messages from the NodeJS layer and wait for them.
send(options: MessageOptions) => Promise<{ value: boolean; }>
Send a message to the NodeJS process.
Param | Type |
---|---|
options |
MessageOptions |
Returns: Promise<{ value: boolean; }>
Since: 1.0.0
addListener(eventName: string, listenerFunc: ChannelListener) => Promise<PluginListenerHandle> & PluginListenerHandle
Listens to eventName
, when a new message arrives listenerFunc
from the NodeJS process would be called with listenerFunc(event)
.
Param | Type |
---|---|
eventName |
string |
listenerFunc |
ChannelListener |
Returns: Promise<PluginListenerHandle> & PluginListenerHandle
Since: 1.0.0
Options to send a message to the NodeJS process via eventName
, along with
arguments. Arguments will be serialized with JSON.
Prop | Type | Description | Since |
---|---|---|---|
eventName |
string |
The name of the event being send to | 1.0.0 |
args |
Array<any> |
Array of arguments to send | 1.0.0 |
Prop | Type | Description |
---|---|---|
length |
number |
Gets or sets the length of the array. This is a number one higher than the highest index in the array. |
Method | Signature | Description |
---|---|---|
toString | () => string | Returns a string representation of an array. |
toLocaleString | () => string | Returns a string representation of an array. The elements are converted to string using their toLocalString methods. |
pop | () => T | undefined | Removes the last element from an array and returns it. If the array is empty, undefined is returned and the array is not modified. |
push | (...items: T[]) => number | Appends new elements to the end of an array, and returns the new length of the array. |
concat | (...items: ConcatArray<T>[]) => T[] | Combines two or more arrays. This method returns a new array without modifying any existing arrays. |
concat | (...items: (T | ConcatArray<T>)[]) => T[] | Combines two or more arrays. This method returns a new array without modifying any existing arrays. |
join | (separator?: string | undefined) => string | Adds all the elements of an array into a string, separated by the specified separator string. |
reverse | () => T[] | Reverses the elements in an array in place. This method mutates the array and returns a reference to the same array. |
shift | () => T | undefined | Removes the first element from an array and returns it. If the array is empty, undefined is returned and the array is not modified. |
slice | (start?: number | undefined, end?: number | undefined) => T[] | Returns a copy of a section of an array. For both start and end, a negative index can be used to indicate an offset from the end of the array. For example, -2 refers to the second to last element of the array. |
sort | (compareFn?: ((a: T, b: T) => number) | undefined) => this | Sorts an array in place. This method mutates the array and returns a reference to the same array. |
splice | (start: number, deleteCount?: number | undefined) => T[] | Removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted elements. |
splice | (start: number, deleteCount: number, ...items: T[]) => T[] | Removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted elements. |
unshift | (...items: T[]) => number | Inserts new elements at the start of an array, and returns the new length of the array. |
indexOf | (searchElement: T, fromIndex?: number | undefined) => number | Returns the index of the first occurrence of a value in an array, or -1 if it is not present. |
lastIndexOf | (searchElement: T, fromIndex?: number | undefined) => number | Returns the index of the last occurrence of a specified value in an array, or -1 if it is not present. |
every | <S extends T>(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any) => this is S[] | Determines whether all the members of an array satisfy the specified test. |
every | (predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any) => boolean | Determines whether all the members of an array satisfy the specified test. |
some | (predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any) => boolean | Determines whether the specified callback function returns true for any element of an array. |
forEach | (callbackfn: (value: T, index: number, array: T[]) => void, thisArg?: any) => void | Performs the specified action for each element in an array. |
map | <U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any) => U[] | Calls a defined callback function on each element of an array, and returns an array that contains the results. |
filter | <S extends T>(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any) => S[] | Returns the elements of an array that meet the condition specified in a callback function. |
filter | (predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any) => T[] | Returns the elements of an array that meet the condition specified in a callback function. |
reduce | (callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T) => T | Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. |
reduce | (callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T) => T | |
reduce | <U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U) => U | Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. |
reduceRight | (callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T) => T | Calls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. |
reduceRight | (callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T) => T | |
reduceRight | <U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U) => U | Calls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. |
Prop | Type |
---|---|
length |
number |
Method | Signature |
---|---|
join | (separator?: string | undefined) => string |
slice | (start?: number | undefined, end?: number | undefined) => T[] |
Prop | Type |
---|---|
remove |
() => Promise<void> |
The event object when a message from the NodeJS process arrives.
Prop | Type | Description | Since |
---|---|---|---|
args |
Array<any> |
Received array of arguments | 1.0.0 |
The callback function when listen to messages from the NodeJS process.
(event: ChannelListenerEvent): void