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

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

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

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

  • 这些方法之间的主要区别
  • 每种方法的具体利弊
  • 可能的障碍、挑战和缺点
  • 您知道其他可行的替代方案吗?

可行的方法是

  1. 运行包含 NodeJS (J2V8)
  2. 直接使用NodeJS,嵌入为本机库(node-on-android))
  3. 将 React Native 与 NodeJS app-as-a-service (react-native-node)相结合)

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

  • NPM直接使用Termux安装NodeJS而无需生根(不适用于最终用户)
  • LiquidCore - 原生移动微应用devenv(未调查,有趣的概念)
  • dna2oslab - 有一个用于节点可执行文件的NodeJS构建脚本
  • 为Android构建NodeJS - 博客,其中包含有用的编译技巧和示例项目

答案 1

调查可行的选择

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

我对各种选择进行了更多的调查,以下是一些初步发现。

0. 编译 NodeJS

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

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

总结一下:

  • 共享库构建都失败(除非在Android上进行物理构建,见下文)
  • 带有 NodeJS () 的 J2V8 在 7.x 至libnode.alibj2v8.so7.9.0
  • build-as-node-executable 适用于 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)。

参见 slideshare: Running NodeJS in a Java World(或參閱 InfoQ 視頻,32 分鐘)

产品特点

  • 用更强大的 v8 替换 JavaScriptCore 引擎(使用 NodeJS)
  • 通过添加 J2V8 JNI / Java 层支持多线程(线程/工作线程)
    • 每个线程都可以有自己的隔离 V8 实例
  • 双向 js 到 java 桥接(从脚本调用 java,反之亦然)
  • 双向集成错误/异常处理
  • 漂亮的交叉编译交互式构建系统(正在开发中))
  • 部件版式调试支持
  • 其他, 类型化数组, ES6 支持, ...

特点

  • 指定要在其中编译的版本build_system/build_settings.py
  • 只需使用 开始构建,选择 build: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}

    • 注意:构建步骤无法构建 Node 共享库(错误),创建静态以链接nodejslibnode.alibj2v8.so
  • 具有 JNI 层,使 Java 可以访问 v8 的大部分内容
  • 在Java中实现的其他功能(例如.JS <-->Java桥接器)
  • 最终构建输出是一个 Gradle,可作为项目依赖项包含在内.aar

优点

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

缺点

  • 很少,大部分过时的使用文档
    • 在大型(r)规模的JS项目中使用特别无文档记录
  • 必须维护的大量 JNI 胶水代码
  • 项目维护得不好(许多旧的未决问题,未合并的PR)
    • 一些公关徘徊了2年,甚至没有得到回应。不好
  • 与其他选项相比,更难理解 J2V8 项目设置(许多文件)
  • 许可问题(EPL 1.0 许可证中的“保留所有权利”)

2. 直接使用 NodeJS,嵌入为原生库(节点在 android 上))

Android上的Node的工作原理是使用共享库在Android应用程序内运行Node.js。然后,它会捆绑一个托管 UI 代码的。所有的UI都只是经典的html/css/js。WebView

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

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

产品特点

  • 构建成熟的NodeJS应用程序,包括UI(通过本机WebView)

特点

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

优点

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

缺点

  • 非常新的项目,只有实验代码
  • 仅用于架构(计划提供完整的移动支持或DIY构建)arm64
  • 没有原生UI可能(除非用Gradle /Java/ XML编码)
  • 在Node应用程序上没有调试支持(AFAIK,但也许你可以以某种方式附加到WebView)

3. 将 React Native 与 NodeJS app-as-a-service (react-native-node)相结合)

在后台运行一个真正的 Node.js进程,在 React Native 应用程序后面。

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

产品特点

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

特点

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

优点

缺点

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

状态 (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工作正常,但仅节点应用程序开发和 64 位与 RN 不兼容

我决定与以下因素结合使用:react-native-nodeJ2V8

React Native + NodeJS 现在正在工作!看:0.46.47.9.0


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

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

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

细节:Realm.io 来桥接Android胖客户端应用程序中的本机NodeJS + React Native(CQRS风格)


结论

即使经过多年人们试图将NodeJS移植到Android,仍然没有真正好的解决方案,这是开创性的。

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


答案 2

截至今天(2018年3月),还有另一种可行的替代方案尚未在当前答案中列出:Node.js移动应用程序

该项目的核心是提供一个原生库,用于将Node.js嵌入到原生Android和iOS应用程序中;但它也附带了React NativeCordova的插件。

该库的预构建二进制文件可用于 Android armeabi-v7a、x86、arm64-v8a、x86_64 和 iOS 64 位。

核心库是 nodejs/node-chakracore 的分叉,而 nodejs/node 又是 nodejs/node 的分叉。Android版本几乎是常规的Node.js构建为一个库,并修复了一些可移植性。iOS版本使用ChakraCore引擎而不是V8(由于nodejs/node-chakracore分支的变化,用ChakraCore替换V8是可能的)。

React Native 和 Cordova 插件使得将 Node.js添加到使用这些框架构建的应用程序中变得更加容易。Node.js代码在比框架(React Native / Cordova)不同的引擎和线程中运行。两个 JavaScript 世界之间的通信是通过插件提供的消息传递桥实现的。

更多信息,包括一些文档,可在项目网站上找到

(完全披露:我为开发Node.js移动应用程序的公司工作。