在 Android 上运行 ClojureScript

jopen 9年前

在 Android 上运行 ClojureScript

在过去的几天里,我有了开发生涯中最有意义的经历之一, 想在这里跟大家分享。

现在我们已经让 ClojureScript 可以在 Android 上运行了。不是在一个 WebView 里面,也不是利用像 Cordova 这样的东西,而是实实在在的运行在一个嵌入式的 JavaScript 引擎中。到底发生了什么?
在 Android 上运行 ClojureScript

最近,我们做了一些工作创建出了一个 iOS 的 ClojureScript REPL 应用,Replete。整个看上去很酷,而对应的 Android 应用就只算勉强能创建出来。不幸的是,我的 Android 技术平平,也不能立马就上手。

不过,这方面 Tahmid Sadik 的技术还能上得了台面。

Tahmid 可以把UI都串起来,也能将 Rhino 实例化并对JavaScript语句进行计算,但是接下来让引导式的 ClojureScript 运行起来对他而言可谓是一次挑战。

不过在此之前,他必须在他的 app 里将 ClojureScript 引导起来。引导这个词被我特意标明,指出他需要用 Google 的 Closure 依赖管理系统把 ClojureScript 运行时启动起来,没有 JavaScript,也没有其他的优化(例如 :none 模式),根据需要,可以定义 CLOSURE_IMPORT_SCRIPT 环境变量。如果想包含一个 REPL,用这种方式来引入运行时是很重要的。这也为在你的 REPL 包含源码级的名字空间提供了支持。

实际上,Replete 也需要做这些,用到的是 Ambly 的一个功能。我当然知道,Replete 是一个独立的 REPL,并不需要 Ambly。不过我使用了一个小花招,可以复用这个功能,让 ClojureScript 启动在 Replete 里运行。

顺便说一下,我最初是打算用 React Native 来实现 Replete 的。结果发现,使用 React Native 的 ClojureScript 支持还为时尚早,而可以引导的 ClojureScript 确实只是初期的功能,要想能够实际工作还需要做很多努力。所以,对于 Replete,我还是保持简单吧,就算是 Goby 也没有用到。

对于上述的结果,好的一点是不需要 React Native 的依赖(Android 版还没有正式公开发布),也没有 Goby 的依赖(只支持 iOS)。Replete 内置的 ClojureScript 非常简洁,使用传统的 iOS 的 UI,事实证明这对 Tahmid 去完成同样功能的 Android 版很有帮助。

让我们回到故事的开始:本质上 Tahmid 复制了 Ambly 的 bootstrap 逻辑,按照顺序逐一的执行了在 Rhino 里的 JavaScript 语句。不过时不时的他会遇到一些奇怪的问题,我的记忆中几个月前也会遇到类似的问题,在研究过 Ambly 的代码后,我给了一点建议。

之后,他基本上可以引导成功 ClosureScriptle。

cljs.core.apply.call(null,cljs.core.inc,new cljs.core.PersistentVector(null, 1, 5, cljs.core.PersistentVector.EMPTY_NODE, [1], null))

这行就是(apply inc [1])需要绑定的JavaScript代码

然后Tahmid终于有了2.0。真棒!这应该是有史以来的第一次,在基于Android的嵌入式的Rhino上跑起来ClojureScript。

接下来,需要尝试用起来reader, analyzer, 和compiler。现在我们来试一下,只需要简单的使用Replete里的JavaScript,让Android的app执行Replete的read_eval_print函数,参数为字符串 (+ 1 2),如果工作正常,那么恭喜,ClojureScript已经成功启动了。

replete.core.read_eval_print.call(null,'(+ 1 2)')

且慢,Transit 里执行 goog.require('replete.core');的时候出了问题,应该是跟 randomUUID 有关。悲剧了,看上去显然还有很多地方需要处理。

不过没关系,Replete 之前一直尝试用不同的方式加载 analysis 缓存,感谢 Karl Mikkelsen,我们有了一个可用的版本只使用纯 JavaScript,没有任何依赖。把这个用起来之后,在把print回调弄好(这样类似 println 这样的方法就可以工作了),接下来 Tahmid 就通过Slack通知我:

I got 3  (+ 1 2) = 3

  ... 然后不断烦我,还会擅自发博客。就这样,引导的 ClojureScript REPL 在 Android 上诞生了!

Tahmid 在界面上封装了一些东西,修复了 JavaScript/ClojureScript 集成的一些小问题之后就发布了Replicator

简直就是一场暴风雨!

现在,Tahmid 正在用 JavaScriptCore 替换 Rhino,这就没那么快了。

我认为这将使速度提升。这为我们在 Android 上使用 JavaScriptCore 进行本地交换的功能提供一些重要的基础。

从大图片来看,我真的认为 ClojureScript 在 Android 上运行很快。特别是使用 JavaScriptCore。对于这个观点的问题,可以看看 Bocko 对 Android 的 Vladimir Iakovlev 的端口在启动速度上的差异。

以上是在模拟器上运行的结果,但是,我仍然认为它显示了 ClojureScript 真正的实现了在移动设备上减少计算延时的承诺。我认为是时候让 ClojureScript 活跃起来,用于为移动设备开发应用!