Android开发笔记-JavaScript调用(不使用WebView)

3,547 阅读4分钟

Tip:

最近开发中遇到一种需求,后台返回一个JavaScript公式,要求TextView的值带入公式计算并不断进行数字变化,类似于定时器的实现

比如后台返回一个"S*4",当前TextView的值位1,那么计算过后的TextView的值应该是1,4,16,64...

问题:UI中没有使用到WebView控件,如何计算JavaScript 公式呢?

引申:

作者当时也没有接触过这种需求,所以一时间也无从下手,后来联想到Java后台的原生JavaScript 引擎可以实现,何不在Android中尝试下呢?

JavaScript 引擎

目前在 Android/iOS 上运行 JavaScript,主要有两种方法:一种方法是利用系统的浏览器组件 WebView(Android)和 UIWebView/WKWebView(iOS);另一种方法是编译和集成一个功能全面的 JavaScript 引擎

在 App 开发中经常会使用 WebView 加载一个网页,甚至构建一个完整应用,目前相关的框架和工具也比较多,例如使用 Cordova 构建多平台应用。当我们对于性能和体验要求比较高的时候,WebView 中解析 JS 的效率低(取决于 JavaScript 引擎)、DOM 渲染慢(取决于渲染引擎)以及系统碎片化严重对于 API 支持也不尽相同(取决于浏览器内核)往往影响性能瓶颈和开发体验。

目前基于高性能 JavaScript 引擎的方案也有很多,如 React Native、weex、NativeScript、Tabrisjs 等,每个方案之间都有一些不一样的地方,不过都离不开底层 JavaScript 引擎的支持。要想了解这些上层框架的原理,我们首先需要了解 JavaScript 引擎的基本内容。

  • JavaScript 引擎是一个专门处理 JavaScript 脚本的虚拟机,一般会附带在网页浏览器之中。在 Android 和 iOS 中可以运行的最主要的 JavaScript 引擎有 JavaScriptCore、V8、SpiderMonkey、Rhino JavaScriptCore 是一个在 WebKit 中提供 JS 引擎的开源框架,目前该引擎由 Apple 维护,使用于 Safari 浏览器,iOS7 后也集成到了 iPhone 平台。由于其使用 C 语言编写,因此在 Android 开发中并不能直接使用。Github 上的开源项目 AndroidJSCore(目前已经停止维护了,官方仓库指向LiquidCore) 能够帮助开发者经过调用 Java 接口而使用 JavaScriptCore。
  • V8 是由 Google 开发并维护的高性能开源 JS 引擎,采用 C++编写,使用于 Google Chrome 浏览器。同 JavaScriptCore 一样,在 Android 开发中,相关接口需要通过一层包装进行调用。Github 上的开源项目 J2V8 基于 jni 实现了 Java 对 V8 的封装,下文我们重点介绍一下。
  • SpiderMonkey 最初由 Netscape 开发,如今由 Mozilla 开发并维护,且被广泛用于 Mozilla 产品(如 FireFox)。SpiderMonkey 提供了一些核心的 JavaScript 数据类型,如数字,字符串,数组,对象等等,以及一些方法如 Array.push。它还使得每个应用程序都容易将其自己的对象和方法暴露给 JavaScript 代码。应用开发者可以决定应用如何将与所写脚本相关的对象暴露出来。
  • Rhino 是由 Mozilla 开发的开源 JS 引擎,采用 Java 编写,因此可以直接调用,在 JDK 6、JDK 7 中更是捆绑了该引擎,其提供的特性包括:
  • Nashorn 由 Oracle 开发并维护,从 JDK 8 开始,Rhino 被 Nashorn 代替,成为 JDK 默认 JS 引擎。Nashorn 同 JDK8 一同发布和开源,较 Rhino 而言性能更好,但不支持 Android Dalvik 虚拟机。
单从 JS 引擎来说,Rhino 执行不需要通过 JNI 且占用更少的内存,但执行效率很低;V8 和 JavaScriptCore 等 C 语言开发的引擎
远胜于 Rhino 等 Java 开发的引擎,但需要一层 Java 包装层,并存在 JNI 调用性能问题。
就 J2V8 和 AndroidJSCore 两个包装层而言:J2V8 的可用性、可靠性、健壮性更优;AndroidJSCore 还存在着不少的性能问题

需求实现

  • V8引擎

implementation 'com.eclipsesource.j2v8:j2v8:5.0.103@aar'

特别注意:在每个CPU架构(arm64-v8a、armeabi-v7a、armeabi、x86)中 V8引擎包都在15M上下

  • Rhino

implementation 'io.apisense:rhino-android:1.0'
// proguard混淆
-keep class com.sun.script.** {*;}
-keep class sun.misc.** {*;}
-keep class sun.reflect.** {*;}
-keep class sun.security.** {*;}
-dontwarn org.mozilla.javascript.**
-dontwarn org.mozilla.classfile.**
-keep class org.mozilla.javascript.** { *; }
-keep class com.sun.phobos.** {*;}
-keep class javax.script.**

Rhino包大致在140k上下