前几天面试一个高级工程师,他有多年的Android开发经验,同一应用也常常负责做IOS的版本,后端人力不够时也去帮忙改改BUG,在小公司里人很容易被训练成多面手。在谈到混合开发时,他说之前还用过PhoneGap进行过开发,那么我很自然地就问他:“你对现在比较流行的React Native怎么看呢?”
结果他一脸茫然,不知React Native为何物。在确认不是他听错的情况后,我对他的看法就改变了,我认为对于目前的移动端开发来说,没用过React Native并不可耻,但是没听说过的话就很没脸混了。
所以,这一题我们来谈谈在Android中遇到JavaScript的问题。
面试题:Android中Java和JavaScript如何交互?
先说一些基础的知识,而JavaScript 是一种脚本语言,个人认为他比Java更面像对象,它没有编译、链接等操作,在运行时才动态的进行词法、语法分析,生成抽象语法树和字节码,然后由解释器负责执行或者使用 JIT 将字节码转化为机器码再执行。整个流程由 JavaScript 引擎负责完成,在Android手机上,这个JavaScript 引擎就是WebView的实现内核。
在Android 4.4版本中,原本基于Android WebKit的WebView实现被换成基于Chromium的WebView实现。
在Android应用中我们可以通过WebView从url加载网页,很多公司在面试时也会考查一下面试者是否有Java和JavaScript交互的经验。这里我们也简单说一下,Java和JavaScript交互主要分为:
1、Java调用WebView加载的网页上的JavaScript
在Java端可以通过WebView调用JavaScript,基本格式为:
webView.loadUrl(“javascript:methodName(parameterValues)”)
有时还要注意这个javascript:methodName是有参数还是无参数,有返回值的情况也会有所不同,毕竟我们从webView.loadUrl的接口看不到如何处理返回值。Android 4.4之后WebView增加了evaluateJavascript接口可以供我们通过ValueCallback这个回调处理返回值。
public void evaluateJavascript(String script, ValueCallback resultCallback)
在4.4之前的版本,常用的思路是Java调用JavaScript方法,JavaScript方法执行完毕,再次调用Java代码将值返回。
2、JavaScript调用本地的Java对像方法
JavaScript调用Java需要在WebView通过addJavascriptInterface添加一个实例到WebView的一个Map对象中,也就是下面接口中第一个参数。
public void addJavascriptInterface(Object object, String name)
调用格式为window.�name.methodName(parameterValues),methodName为object实例提供的方法。在Android 4.2之后引入了@JavascriptInterface,被标为JavascriptInterface的方法才能在JavaScript端进行调用,也就是说在4.2之前的版本开放JavaScript调用Java实例的功能是有全安隐患的。
因为JavaScript端调用Java时是通过反射的方式。可以在JavaScript端通过window.�name.getClass().forName反射调用java.lang.Runtime类的方法(getRuntime),之后便可以执行一些命令做些坏事情了。
所以在4.2之前的版本一般都建议:
关闭JavaScript功能(setJavaScriptEnabled);
不使用addJavascriptInterface;
用removeJavascriptInterface移除系统自带的实例(如:WebView默认会addJavascriptInterface添加一个 “searchBoxJavaBridge_” 的实例)。
如果非要在4.2之前的版本使用JavaScript功能,那该怎么办呢?这个问题我也没有很好的答案,你可以试试问问面试者,看看他们的想法。
混合开发(Hybrid App)的问题
人都是向往懒和舒服的,当我们针对同一业务需求要开发多个版本的移动端应用时,我们很容易想到能不能像JAVA一样只写一次代码在各个平台都可以运行,所以就产生了一种叫Hybrid App(混合应用)开发方式。
简单地说,原来一个项目我们一般要做Web、Android和IOS三个应用,现在我们做混合应用,用CSS,HTML和JavaScript编写应用,在Android和IOS上用Webview做为载体来运行。很多开源库也为我们写为了JavaScript调用原生模块的接口供我们调用。只要我们的HTML界面看起来像手机自带的控件,那么理论上用户是区分不开是原生的应用还是Web应用,而且可以动态部署的优点也很吸引人。
但理想是丰满的,现实总是那么残酷。
性能问题首当其冲,IOS的手机要好些,但在硬件标准参差不齐的Android设备上,使用Webview加载和渲染JavaScript的性能较差,稍微复杂一点或CSS动画多一些,卡顿现象就很常见了。
而且兼容性问题也很突出,包括Android官方的WebView实现内核都发生了变化,每个版本所支持的功能也有不同。再加上ROM厂商乱改系统自带的WebView,从而导致在各种小细节上不同手机的显示效果或运算结果不同。
安全问题和调试难的问题也不容忽视,最终发现解决它们成本并不比原生开发的成本低。之前Facebook也想使用H5来做移动应用,后来也无法解决这些问题,最终放弃了,所以才有了今天的React Native。
React Native
正如项目的名字那样,React Native的目的是构建真正native的应用。而不是构建在Webview里运行的混合模式的应用,开发完全由JavaScript和React来完成。简单说它的原理就是,开发用JavaScript开发Web的方式进行开发,最终在移动端会使用一个JavascriptCore解释器引擎来解析JS相关文件成相应的原生控件再进行渲染,性能上得到了很大的提升。
FaceBook开发React是对以前思维模式进行了改变,不再追求一次编写到处运行,而是转而探讨:
Learn once,Write anywhere!
小结
前端的发展如火如荼,而且从业人数不可小觑,目前高端的前端开发的薪资待遇方面都很不错,也说明了市场对它的认可。虽然目前看,前端开发还有些混乱(开发框架和模式琳琅满目),难度和复杂度也在增加,但并不能排除它一统天下的可能性。
做为Android的工程师,你无法确认Androd或者IOS会不会走Symbian(Nokia用的平台)的老路,这样看来,接触一些前端开发知识,对我们来说是很有必要的。这也是为什么我会因为一个高级工程师不知道React Native而改变对他的看法。