一尘不染

在Android上运行NodeJS的可行选项(2017年8月)

javascript

有很多旧的SO线程处理在Android上运行NodeJS的问题。其中大多数不再可行(JXCore)和/或提供令人困惑,过时,不完整或错误的信息。

因此,我调查了目前(截至2017年8月)似乎可行的方法,并找到了三种可能的候选方法。

要在他们之间做出决定,我想知道:

  • 这些方法之间的主要区别
  • 每种方法的具体优缺点
  • 可能的障碍,挑战和缺点
  • 您知道其他可行的选择吗?

可行的方法是

  1. 运行包[NodeJSJ2V8的V8 JavaScript引擎
  2. 直接使用NodeJS,嵌入为本机库node-on-android
  3. 将React Native与NodeJS应用即服务react-native-node结合

除此之外,我发现了许多相关的有趣资源:

  • NPM直接使用Termux来安装NodeJS而无需生根(不适用于最终用户)
  • LiquidCore-本机移动微型应用程序开发(未经调查,有趣的概念)
  • dna2oslab-具有适用于节点可执行文件的有效NodeJS构建脚本
  • 构建适用于Android的NodeJS具有有用的编译技巧和示例项目的

阅读 1156

收藏
2020-05-01

共1个答案

一尘不染

研究可行的选择

[ 注意 此答案包含原始问题中的发现]

我已经研究了各种选择,这里是一些初步的发现。

0.编译NodeJS

每个选项都使用某种形式的为Android编译的NodeJS。但是要使用任何选项,您可能希望将其编译为不同的Node,Android和体系结构(x86,ARM,ARM64等)版本。

这是有问题的。NodeJS有一个android-configure脚本,但这会导致我尝试过的大多数组合出现错误。我为工作的构建脚本创建了许多github问题。在本期中,收集结果:

总结一下:

  • 共享库构建全部失败(除非在android上进行物理构建,请参见下文)
  • 与NodeJS(libnode.a)静态链接的J2V8 libj2v8.so适用于7.x直至7.9.0
  • 7.x版的“构建为节点”可执行文件(使用dna2oslab构建脚本)

@mafintosh使用了一种有趣的解决方法:使用Termux将Node传输到设备并在那里进行编译(需要大量的空间和时间,但是可以工作)。

1.运行包含NodeJS J2V8的V8
JavaScript引擎

J2V8是V8的一组Java绑定。J2V8专注于性能以及与V8的紧密集成。[…]强制在JS和Java代码之间使用更静态的类型系统,但由于未创建中间对象,因此还提高了性能。[…]

构建J2V8需要同时构建本机部分和Java库(.jar /
.aar文件)。为了构建本机部分,我们首先将node.js构建为一个库,然后将J2V8静态链接到该库。[…]

对于交叉编译,J2V8使用Docker(Android,Linux,Windows)和Vagrant(macos)。

特点

  • 用功能更强大的v8替换JavaScriptCore引擎(使用NodeJS)
  • 通过添加的J2V8 JNI / Java层支持多线程(线程/工作者)
    • 每个线程都可以拥有自己的隔离V8实例
  • 2路js到Java桥(从脚本调用Java,反之亦然)
  • 2路集成错误/异常处理
  • 美丽的交叉编译交互式构建系统
  • chrome调试支持
  • 其他,类型数组,ES6支持,…

特点

  • 指定要编译的版本 build_system/build_settings.py
  • 只需使用即可开始构建python build.py --interactive,选择构建:
[0] Docker >> android-x86 >> NODE_ENABLED
[1] Docker >> android-arm >> NODE_ENABLED
[2] Docker >> alpine-linux-x64 >> NODE_ENABLED
[3] Docker >> linux-x64 >> NODE_ENABLED
[4] Docker >> linux-x86 >> NODE_ENABLED
[5] Vagrant >> macosx-x64 >> NODE_ENABLED
[6] Vagrant >> macosx-x86 >> NODE_ENABLED
[7] Native >> windows-x64 >> NODE_ENABLED
[8] Docker >> windows-x64 >> NODE_ENABLED
[9] Vagrant >> windows-x64 >> NODE_ENABLED
  • 选择构建步骤(或all):

    NodeJS --> CMake --> JNI --> Optimize --> Java/Android --> JUnit
    
  • 将V8编译为共享库 libj2v8_{platform}_{abi}.{ext}

    • 注意nodejs构建步骤无法构建Node共享库(错误),创建libnode.a要链接的静态对象libj2v8.so
    • 拥有一个JNI层,以使Java可以访问v8的大部分内容
    • 用Java实现的附加功能(例如JS <-> Java桥)
    • 最终构建输出是.aar作为项目依赖项包括在内的Gradle

优点

  • 相对活跃的项目
  • 高质量的代码,包括Java单元测试
  • 将Java的全部功能添加到您的应用程序设计工具包中
  • 出色,直观的构建系统(完成后)

缺点

  • 很少,大多数是过时的使用文档
    • 大型JS项目中的用法尤其没有记载
  • 必须维护的许多JNI粘合代码
  • 项目维护不力(许多旧的未解决问题,未合并的PR)
    • 一些公关公司徘徊了两年,甚至没有得到回应。不好
  • 比其他选项更难理解J2V8项目设置(许多文件)

2.直接使用NodeJS,作为本机库嵌入([node-on-android](https://github.com/node-on-

mobile/node-on-android))

android上的Node通过使用共享库在android应用中运行Node.js来工作。然后WebView,它捆绑了一个托管您的UI代码的。所有的UI都是经典的html / css / js。

在节点应用程序中,您可能需要node-on-android访问WebView。您可以使用它在中加载html页面WebView

根据node-on-android创建者(@mafintosh)的说法,这比J2V8更容易和更好,因为它直接将V8编译
为真实的东西

特点

  • 构建完整的NodeJS应用程序,包括UI(通过本地WebView)

特点

  • gradle app项目中的相关目录/文件:
    • app/src/main/include/node带有节.h点头
    • app/src/main/jniLibs/arm64-v8alibc++_shared.solibnode.so
    • app/src/main/cppnative-lib.cpp(包括node.h
    • Java代码,仅启动一个Service在单独线程中运行的with节点
  • 没有用于的JNI libnode.so,因此private native void startNode(String... app);在IDE中显示为错误(但可以编译)
  • NodeJS项目位于 android/app/src/main/assets/node
  • NodeJS代码被传输到临时存储并从那里执行
  • NodeJS应用程序指定要通过公开loadUrl功能 在WebView中加载的视图
    • 可通过NPM软件包访问节点服务 node-on-android

优点

  • 简单的项目,没有太多的管道代码
  • 随附最新的v8.x Node版本
  • 基于HTML的简单应用程序UI编程(例如,使用choo
  • 开箱即用:)

缺点

  • 非常新的项目,仍然只有实验代码
  • 仅用于arm64架构(已计划完整的移动支持或DIY构建) 注意 :64位不能与React Native结合使用不支持64位!
  • 无法使用本机UI(除非使用Gradle / Java / XML进行编码)
  • Node应用程序上没有调试支持(AFAIK,但也许您可以通过某种方式连接到WebView)

3.将React Native与NodeJS应用即服务react-native-node结合

在React Native应用程序的后台在后台 运行 真实的 Node.js进程。

使用此软件包,您可以:在Android中运行http服务器,使用Node流,与文件系统接口,从React
Native的JS线程中卸载一些繁重的处理工作,等等!在Android中运行真正的Node.js,您可以执行桌面上Node.js可以执行的所有操作。

特点

  • 将React Native用于UI,NodeJS作为后台服务

特点

  • 派生自NodeBase
  • 与Android Service上的Node 非常相似(在单独的线程上与Node一起运行)
    • 但是node被编译/用作应用程序,而不是嵌入式共享库
    • NodeJS应用程序代码位于 {projectRoot}/background
    • NodeJS可执行文件位于 /android/src/main/res/raw/bin_node_v710
    • 在构建时,Node应用被压缩,并在`/ android / src / main / res / raw / {appName}中解压缩
    • 就像从命令行运行一样调用NodeJS服务,并传递args
  • RNNode通过导入,RN中可以使用节点服务react-native-node
    • react-native-node 还包含在构建时传输Node代码的CLI
  • 示例项目通过REST从React Native到NodeJS服务进行通信
    • 在节点端运行express服务器http://localhost:5000

优点

  • 简单的项目,没有太多的管道代码
  • 显而易见:在Android上使用NodeJS响应本机支持!

缺点

  • 非常新的项目,仍然只有实验代码
  • 带有旧的NodeJS 7.1.0版本(但可以自己构建较新的版本)
  • 在RN和Node应用之间进行通信的简便方法(基于REST)
    • 需要扩展REST API或使用自己的机制
  • Node应用程序上没有调试支持。真的很难知道发生了什么

状态(2017-08-17)

我的目标是React Native + NodeJS。这是我的活动状态:

  • 将NodeJS v7.x版本编译为可执行文件
  • 编译NodeJS v7.4.0到v7.9.0均可与新的J2V8构建系统一起使用
  • 编译NodeJS v8.1.2将很快与J2v8一起使用(针对编译libc++
  • react-native-node 确实可以编译,但是尽管多次尝试却无法运行
  • node-on-android 可以,但是仅节点应用程序开发和与RN不兼容的64位

我之所以决定合并react-native-nodeJ2V8是因为:

  • 很棒的交叉编译构建PR:https : //github.com/eclipsesource/J2V8/pull/327
  • 内置.aar于精美的J2V8中,可轻松包含在Gradle中

React Native 0.46.4+ NodeJS 7.9.0现在可以使用了!看到:


我的用例: 具有P2P去中心化网络的胖客户端

我正在考虑一个CQRS(命令-查询-责任-隔离)设计:

  • react-native UI是从节点服务查询的视图构造的
  • react-native UI操作触发节点后台服务上的命令
  • 后台服务处理网络消息,传入命令,触发事件
  • 事件存储在Realm DB中,该数据库构成了前后之间的桥梁

结论

即使经过多年尝试将NodeJS移植到Android上的人们,仍然没有真正好的解决方案,它是先锋。

在设置项目和构建环境时,会遇到许多障碍和错误,但是一旦设置,您就可以在手机上享受Node的全部功能。

2020-05-01