React Native
关于 React Native 目前网上有很多讨论了,知乎上也有不少回答,尽管有些回答从底层实现角度看并不准确,但大部分关键点倒是都提到了。
鉴于我不喜欢重复别人说过的话,这里就聊点别的。
React Native 的思路简单来说就是在不同平台下使用平台自带的 UI 组件,这个思路并不新奇,十几年前的 SWT 就是这么做的。
从团队上看,Facebook 的 iOS 团队中不少成员是来自 Apple 的,比如 Paper 团队的经理及其中不少成员都是,因为 iOS 不开源,所以从 Apple 中出来的开发者还是有优势的,比如前 Apple 开发者搞出来的 Duet 就限时购买了市面上所有其他方案,而且从 Facebook 在 iOS 上开源的项目看他们在 iOS 方面的经验和技术都不错,所以从团队角度看他们做出来的东西不会太差。
在做 React Native 方案的同时,其实 Facebook 还在做一个 Objective-C++ 上类似 React 的框架 ComponentKit,以下是它的代码示例:
@implementation ArticleComponent+ (instancetype)newWithArticle:(ArticleModel *)article{ return [super newWithComponent: [CKStackLayoutComponent newWithView:{} size:{} style:{ .direction = CKStackLayoutDirectionVertical, } children:{ {[HeaderComponent newWithArticle:article]}, {[MessageComponent newWithMessage:article.message]}, {[FooterComponent newWithFooter:article.footer]}, }];}@end
它的可读性比 JSX 中的 XML 差了不少,而且随着大家逐步接受 Swift,这种基于 Objective-C++ 的方案恐怕没几年就过时了,所以 Facebook 押宝 React 是比较正确的。
我看到有人说这是 Facebook 回归 H5,但其实 React Native 和 Web 扯不上太多关系,我所理解的 Web 是指 W3C 定义的那些规范,比如 HTML、CSS、DOM,而 React Native 主要是借鉴了 CSS 中的 Flexbox 写法,还有 navigator、XMLHttpRequest 等几个简单的 API,更别说完全没有 Web 的开放性,所以 React Native 和 HTML 5 完全不是一回事。
Facebook Groups 的 iOS 版本很大一部分基于 React Native 开发,其中用到了不少内部通过组件,比如 ReactGraphQL,这里我就八卦一下它,GraphQL 这是一个结构化数据查询的语法,就像 MongoDB 查询语法那样查询 JSON 数据,不过它并不是一种文档型数据库,而只是一个中间层,具体的数据源可以连其它数据库,它想取代的应该是 RESTful 那样的前后端简单 HTTP 协议,让前端更方便的获取数据,据说将会开源(看起来打算用 Node 实现)。
写文章拖时间太长的问题就是这期间会发生很多事情,比如 GraphQL 在我开始写的时候外界都不知道,所以需要八卦一下,结果现在官方已经宣布了,不过官方并没提到我说的那个 Node 实现,它目前还在悄悄开发阶段
React Native 的官方视频中说它能做到 App 内实时更新,其实这是 Apple 明文禁止的(App Store Review Guidelines 中的 2.7),要做得低调。
我比较喜欢的是 React Native 中用到了 Flow,它支持定义函数参数的类型,极大提升了代码可读性,另外还能使用 ES6 的语法,比如 class 关键字等。
React Native 比传统 Objective-C 和 UIView 的学习成本低多了,熟悉 JavaScript 的开发者应该半天内就能写个使用标准 UI 的界面,而且用 XML+CSS 画界面也远比 UIView 中用 Frame 进行手工布局更易读(我没用过 Storyboards,它虽然看起来直观,但多人编辑很容易冲突),感兴趣可以抽空看看这个详细的入门教程,亲自动手试试就能体会到了,Command + R 更新代码感觉很神奇。
它目前已经有组件仓库了,而且在 github 上都有 500 多仓库了,其中有 sqlite、Camera 等原生组件,随着这些第三方组件的完善,基于 React Native 开发越来越不需要写原生代码了。
不过坏消息是 React Native 的 Android 版本还要等半年,这可以理解,因为在 Android 上问题要复杂得多,有 Dalvik/ART 拦在中间,使得交互起来很麻烦。
NativeScript 和 React Native 在侧重点上有很大的不同,使得这两个产品目前走向了不同的方向:
- React Native 要解决的是开发效率问题,它并没指望完全取代 Native 开发,它的 rootView 继承自 UIView,所以可以在部分 View 是使用,很方便混着,不需要重写整个 app,而且混用的时候还需要显示地将 API 暴露给 JavaScript
- NativeScript 则像是 Titanium 那样企图完全使用 JavaScript 开发,将所有系统 API 都暴露给了 JavaScript,让 JavaScript 语言默认就拥有 Native 语言的各种能力,然后再次基础上来开发
方向的不同导致这两个产品将会有不同的结局,我认为 React Native 肯定会完胜 NativeScript,因为它的使用风险要小很多,你可以随时将部分 View 使用 React Native 来试验,遇到问题就改回 Native 实现,风险可控,而用 NativeScript 就不行了,这导致大家在技术选型的时候不敢使用 NativeScript。
话说 Angular 团队看到 React Native 后表示不淡定了,于是开始重新设计 Angular 2 的展现架构,将现有的 Render 层独立出来,以便于做到像 React 那样适应不同的运行环境,可以运行在 NativeScript 上。
综合来看,我觉得 React Native 很值得尝试,而且风险也不高。
游戏引擎中的脚本
游戏引擎大多都能跨平台,为了提升开发效率,不少引擎还内嵌了对脚本支持,比如:
- Ejecta,它实现了 Canvas 及 Audio 的 API,可以开发简单的游戏,但目前还不支持 Android
- CocoonJS,实现了 WebGL 的 API,可以运行 Three.js 写的游戏
- Unreal Engine 3,可以使用 UnrealScript 来开发,这个语言的语法很像 Java
- Cocos2d-js,Cocos2d-x 的 JavaScript binding,它内部使用的 JS 引擎是 SpiderMonkey
- Unity 3D,可以使用 C# 或 JavaScript 开发游戏逻辑
- Corona,使用 Lua 来开发
- ...
目前这种方式只有 Unity 3D 发展比较好,Cocos2d-JS 据说还行,有些小游戏在使用,Corona 感觉比较非主流,虽然它也支持简单的按钮等界面元素,但用来写 APP 我不看好,因为不开源所以没研究,目前看来比较大的好处似乎是虚拟机体积小,内嵌版本官方号称只有 1.4M,这是 Lua 引擎比较大的优势。
而剩下的 3 个都基本上挂了,Ejecta 至今还不支持 Android,CocoonJS 转型为类似 Crosswalk 的 WebView 方案,而 Unreal Engine 4 开始不再支持 UnrealScript,而是转向了使用 C++ 开发,感兴趣可以围观一下 Epic 创始人解释为什么要这么做。
当然,这些游戏引擎都不适合用来做 APP,一方面是会遇到前面提到的界面绘制问题,另一方面游戏引擎的实现一般都要不断重绘,这肯定比普通 App 更耗电,很容易被用户发现后怒删。
Adobe AIR
尽管 Flash 放弃了移动端下的浏览器插件版本,但 Adobe AIR 还没挂,对于熟悉 ActionScript 的团队来说,这是一种挺好的跨平台游戏开发解决方案,国内游戏公司之前有用,现在还有没人用我就不知道了。
但开发 APP 方面,它同样缺乏好的 UI 库,Flex 使用体验很差,目前基本上算挂了,目前只有 Feathers 还算能看,不过主要是给游戏中的 UI 设计的,并不适合用来开发 APP。
Dart
Dart 在 Web 基本上失败了,于是开始转战移动开发,目前有两个思路,一个是类似 Lua 那样的嵌入语言来统一公共代码,但因为 Dart 虚拟机源自 V8,在一开始设计的时候就只有 JIT 而没有解释器,甚至连字节码都没有,所以它无法在 iOS 下运行,于是 Dart 团队又做了个小巧的虚拟机 Fletch,它基于传统的字节码解释执行方式来运行,目前代码只有 1w 多行,和 Lua 一样轻量级。
另一个就是最近比较热门的 Sky,这里吐槽一下国内外的媒体,我看到的报道都是说 Google 想要用 Dart 取代 Android 下的 Java 开发。。。这个东东确实是 Google 的 Chrome 团队开发的,但 Google 是一个很大的公司好不好,内部有无数小团队,某个小团队并不能代表个 Google,如果真是 Google 高层的决定,它将会在 Google I/O 大会主题演讲上推出来,而不是 Dart Developer Summit 这样非主流的技术分享。
有报道称 Sky 只支持在线应用,不支持离线,这错得太离谱了,人家只是为了演示它的在线更新能力,你要想将代码内嵌到 app 里当然是可以的。
Sky 的架构如下图所示,它参考了 Chrome,依靠一个消息系统来和本地环境进行通讯,使得 Dart 的代码和平台无关,可以运行在各种平台上。
如果你读过前面的文章,那你一定和我一样非常关心一个问题:Sky 的 UI 是怎么绘制出来的?使用系统还是自己画?一开始看 Sky 介绍视频的时候,我还以为它底层绘制基于 Chrome,因为这个视频的演讲者是 Eric Seidel,他是 WebKit 项目中非常有名的开发者,早年在 Apple 开发 WebKit,2008 年跳槽去了 Chrome 团队,但他在演讲中并没有提到 WebView,而且演示的时候界面非常像原生 Material Design 效果(比如点击有涟漪效果),所以我又觉得它是类似 React Native 那样使用原生 UI。
然而当我下载那个应用分析后发现,它既没使用 Chrome/WebView 也没使用原生 UI 组件,难不成是自己绘制的?
从 Sky SDK 的代码上看,它其中有非常多 Web 的痕迹,比如支持标准的 CSS、很多 DOM API,但它编译后的体积非常小,libsky_shell.so 只有 8.7 MB,我之前尝试精简过 Chrome 内核,将 WebRTC 等周边功能删掉也要 22 MB,这么小的体积肯定要删 Web 核心功能,比如 SVG 和部分 CSS3,所以我怀疑它实现了简版的 Chrome 内核渲染。
后来无意间看了一下 Mojo 的代码,才证实确实如此,原来前面那张图中介绍的 Mojo 其实并不完整,Mojo 不仅仅是一个消息系统,它是一个简版的 Chrome 内核!使用 cloc 统计代码就暴露了:
C++ 不包含注释的代码部分就有近 70w 行啊,而且一看目录结构就是浓浓的 Chromium 风格,至少从技术难度来说相对秒掉前面所有方案,也印证了我前面说过如果有简化版 CSS/HTML 就能很好解决性能问题。
这也让我理解了为什么 Eric 在谈到 Mojo 的时候语焉不详,让人误以为仅仅是一个消息系统,他要是明确说这是一个精简版 Chrome,那得引起多大的误会啊,没准会有小编用「Google 宣布开发下一代浏览器内核取代 Blink」这样的标题了。
之前 Dart 决定不将 Dart VM 放到 Chrome 里,原来并不是因为被众人反对而死心了,而是因为 fork 了一个 Chrome 自己拿来玩了。
综合来看,目前 Dart 的这两个方案都非常不成熟,Sky 虽然在技术上看很强大,但 Dart 语言目前接受度非常低,比起它所带来的跨平台优点,它的缺点更大,比如无法使用第三方 Native UI 库,也无法使用第三方 Web UI 库,这导致它的社区会非常难发展,命中注定非主流,真可惜了这帮技术大牛,但方向比努力更重要,希望他们能尽早醒悟,让 Sky 也支持 JavaScript。
结论及参考
看到这里估计不少读者晕了,有那么多种方案,最后到底哪个最适合自己?该学哪个?这里简单说说我的看法。
如果你只会 JavaScript,那目前较好的方案是 React Native,有了它你即使不了解 Native 开发也能写出很多中小应用,等万一火了再学 Native 开发也不迟啊。
如果你只会 Java,那可以尝试 RoboVM 或 j2objc,j2objc 虽然目前更稳定靠谱,但它不能像 RoboVM 那样完全用 Java 开发,所以你还得学 Objective-C 来写界面,而 RoboVM 的缺点就是貌似还不太稳定,而且似乎除了游戏以外还没见到比较知名的应用使用,而它这种方案注定会比 j2objc 更容易出问题,所以你得做好踩坑的心理准备。
如果你只会 C#,那仅有的选择就是 Xamarin 了。
如果你只会 Objective-C,很杯具目前没有比较靠谱的方案,我建议你还是学学 Java 吧,多学一门语言没啥坏处。
如果你只会 C++,可以做做游戏或非 UI 的公共部分,我不建议使用 QT 或自己画界面,还是学学 Native 开发吧。
如果你只会 Go,还别指望用它开发移动端,因为目前的实现很低效,而且这和 Go 底层的实现机制密切相关,导致很难优化,所以预计很长一段时间内也不会有改观。
如果你会 Rust,说明你很喜欢折腾,多半也会前面所有语言,自己做决定吧。。。
(举报)