Simple JS in Node.js
J2V8 support to run Node.js and the JVM in a single process.
import com.eclipsesource.v8.NodeJS;
public class JavaClass {
final NodeJS nodeJS = NodeJS.createNodeJS();
}
But I got exception when start Node.js.
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.hsy.wrapper, PID: 32371
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.hsy.wrapper/com.hsy.wrapper.MainActivity}: java.lang.UnsupportedOperationException: StartNodeJS Not Supported.
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: java.lang.UnsupportedOperationException: StartNodeJS Not Supported.
at com.eclipsesource.v8.V8._startNodeJS(Native Method)
at com.eclipsesource.v8.V8.createNodeRuntime(V8.java:1013)
at com.eclipsesource.v8.NodeJS.createNodeJS(NodeJS.java:101)
at com.eclipsesource.v8.NodeJS.createNodeJS(NodeJS.java:48)
at com.hsy.wrapper.JavaClass.NodeJS.createNodeJS(JavaClass.java:4)
The author of J2V8 said that "The node wrappers are not available on Android" at GitHub issue #216. Someone said that "You need to recompile the JNI source code with-D NODE_COMPATIBLE=1
option." According to Arnold Schrijver's try, I do not want to rebuild the J2V8 source code by myself. I would like to package the JavaScript programs and NPM (Node Package Manager) modules to single JavaScript file.
How to use NodeJS in Android using J2V8
create Node.js project
I have to prepare the Node.js project and install NPM modules.
$ mkdir nodejsProject
$ cd nodejsProject/
$ npm init
$ npm install lodash webpack --save
$ mkdir dist
$ mkdir src
I got package.json
which is looks like below:
{
"name": "nodejsproject",
"scripts": {
"build": "./node_modules/.bin/webpack --config webpack.config.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
......
"dependencies": {
"lodash": "^4.17.4",
"webpack": "^3.6.0"
}
}
Write JavaScript program with lodash
library.
/src/simple.js
import _ from 'lodash';
export function getString() {
return _.join(['Hello, ', 'World'], ' ');
};
package the program and module
Write config of webpack
module in /webpack.config.js
.
const path = require('path');
const webpack = require('webpack');
module.exports = {
entry: './src/simple.js',
output: {
library: 'libraryName',
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
Use webpack
to package JavaScript program and Node.js module.
$ npm run build
> [email protected] build /Users/yen/Desktop/nodejsProject
> webpack --config webpack.config.js
Hash: 5f0bb84951ae289f2552
Version: webpack 3.6.0
Time: 358ms
Asset Size Chunks Chunk Names
bundle.js 544 kB 0 [emitted] [big] main
[0] ./src/simple.js 100 bytes {0} [built]
[2] (webpack)/buildin/global.js 509 bytes {0} [built]
[3] (webpack)/buildin/module.js 517 bytes {0} [built]
+ 1 hidden module
The file structure of Node.js project should look like below:
$ tree
.
├── dist
│ └── bundle.js
├── package.json
├── src
│ └── simple.js
└── webpack.config.js
2 directories, 4 files
first try
Put /dist/bundle.js
to Android Studio project in/src/main/assets/simple.js
var libraryName =
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
......
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony export (immutable) */ __webpack_exports__["getString"] = getString;
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_lodash__ = __webpack_require__(1);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_lodash___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_lodash__);
function getString() {
return __WEBPACK_IMPORTED_MODULE_0_lodash___default.a.join(['Hello, ', 'World'], ' ');
};
......
/***/ })
/******/ ]);
Call the JavaScript function in Java. com.eclipsesource.v8.V8Object;
public class JavaClass {
......
public void exeJavaScript() {
String jsContent = readFromAsset("simple.js");
V8 runtime = V8.createV8Runtime();
runtime.executeVoidScript(jsContent);
V8Object library = runtime.getObject("libraryName");
Log.d("Test", library.executeStringFunction("getString", null));
myClass.release();
runtime.release();
}
}
It is not work. I got SyntaxError
.
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.hsy.wrapper, PID: 20119
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.hsy.wrapper/com.hsy.wrapper.MainActivity}: undefined:1: SyntaxError: Unexpected end of input
var libraryName =/******/ (function(modules) ......
D/Error: ERR: exClass=com.eclipsesource.v8.V8ScriptCompilationException
D/Error: ERR: exMsg=undefined:1: SyntaxError: Unexpected end of input
D/Error: ERR: file=V8.java
D/Error: ERR: class=com.eclipsesource.v8.V8
D/Error: ERR: method=_executeVoidScript line=-2
D/Error: ERR: TOTAL BYTES WRITTEN: 2111296
results
I think the newline code is suspect. I found the online minify tool to deal with this problem.
The minified JavaScript is looks like below:
var libraryName=(function(modules){var installedModules={};function __webpack_require__(moduleId){if(installedModules[moduleId]){return installedModules[moduleId].exports;/******/}
var module=installedModules[moduleId]={i:moduleId,l:!1,exports:{}/******/};modules[moduleId].call(module.exports,module,module.exports,__webpack_require__);module.l=!0;return module.exports;/******/}
__webpack_require__.m=modules;__webpack_require__.c=installedModules;__webpack_require__.d=function(exports,name,getter){if(!__webpack_require__.o(exports,name)){Object.defineProperty(exports,name,{configurable:!1,enumerable:!0,get:getter});/******/}/******/};__webpack_require__.n=function(module){var getter=module&&module.__esModule?function getDefault(){return module['default']}:function getModuleExports(){return module};__webpack_require__.d(getter,'a',getter);return getter;/******/};__webpack_require__.o=function(object,property){return Object.prototype.hasOwnProperty.call(object,property)};__webpack_require__.p="";return __webpack_require__(__webpack_require__.s=0);/******/})([(function(module,__webpack_exports__,__webpack_require__){"use strict";Object.defineProperty(__webpack_exports__,"__esModule",{value:!0});__webpack_exports__.getString=getString;var __WEBPACK_IMPORTED_MODULE_0_lodash__=__webpack_require__(1);var __WEBPACK_IMPORTED_MODULE_0_lodash___default=__webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_lodash__);function getString(){return __WEBPACK_IMPORTED_MODULE_0_lodash___default.a.join(['Hello, ','World'],' ')};
......
module.exports=g;/***/}),(function(module,exports){module.exports=function(module){if(!module.webpackPolyfill){module.deprecate=function(){};module.paths=[];if(!module.children)module.children=[];Object.defineProperty(module,"loaded",{enumerable:!0,get:function(){return module.l}});Object.defineProperty(module,"id",{enumerable:!0,get:function(){return module.i}});module.webpackPolyfill=1}
return module};/***/})])
Result in LogCat is:
09-22 02:45:19.096 20310-20310/? D/Test: Hello, World