React Native与ExMobi技术路线探索

Stella981
• 阅读 681

随着Facebook陆续开源React Native的iOS和Android版本,这种以JavaScript来开发原生APP的方式在移动应用开发圈里得到广泛关注,虽然React Native并不是第一个采用JavaScript编写原生APP的产品,但是其独特的设计思想和实现方式是非常值得借鉴的。

而作为国内老字号的移动应用开发平台,同样支持开发原生APP 以及轻应用的ExMobi经过7年不断演进之后,在技术架构上又有怎样的突破呢?

这里,笔者就通过亲身体验来剖析React Native与ExMobi在技术架构、开发者受众、成熟度等多维度的异同,从中探索更多移动应用开发技术上的可能与创新,以飨读者。

产品背景

对产品背景的了解,有助于我们对产品的原理、发展等多方面有基础的认识。

React Native官网上的博客不仅很有技术含量,而且还很有情怀,所以我们就从这里入手。下面就是其中一段摘抄:

React Native与ExMobi技术路线探索

可以看出由于WEB在移动端差强人意的表现,使得Facebook要寻求两全其美的办法:

React Native与ExMobi技术路线探索

所以React Native诞生了:

React Native与ExMobi技术路线探索

而ExMobi则不同,ExMobi完全是为移动设备诞生,从早期的非智能机时代、早期智能机时代的Java、Symbian、Windows Mobile、Brew、Black Berry平台到现在的后智能机时代Android、iOS系统盛行,ExMobi的架构也发生了翻天覆地的变化。这里特指的是ExMobi第五代产品。

经过前四代产品的技术积累,并与现在Android和iOS两大主流系统的特性结合,ExMobi产品也是做了很大调整,但始终不变的是坚持Native原生APP为主线,通过技术难关的攻克不断提高开发者的开发效率,又不影响APP的性能和体验,同时也支持HTML5的webapp模式开发,提倡Native Component+Web Plus的主流开发模式,让开发者可以充分利用原生组件和HTML5混合布局,完全标签化写法,并通过JS将本地能力无缝对接,开发方式灵活。

ExMobi也致力于提供优良的开发工具MBuilder,帮助开发者能够快速开发ExMobi应用。

从React Native和ExMobi的产品背景中,我们可以看到两者的共同点都是为了提高移动应用开发效率,降低开发成本,并都尽可能的结合Native和HTML5的优点,提出了各自的创新开发模式。

原生组件通信原理

React Native通过JavaScript编写APP的方式,乍看以为是以webview提供的现成的JS与原生语言之间的互调,但是如果当我们调试一个React Native程序的时候,在debug视图中是不会看到任何webview被调用的痕迹。所以,实际上React Native并没有使用现成的与webview的通信方法,而是使用了更直接的JS运行环境,比如在iOS中为系统自带的JavaScriptCore。这与Phonegap这类以webview为主的界面展现与本地能力调用的模式有本质上的区别,也是确保React Native高性能和高效率的基础。

有了这个核心基础,我们再来看看React Native是如何通过JS来挂钩到原生UI和本地能力的。

React Native与ExMobi技术路线探索

从上图很容易可以看到,开发者通过JS去调用一个React Native提供的方法,实际需要先经过两个桥接封装类,一个JS的桥接,另一个是原生的桥接。两个桥接类之间就是通过前面提到的JS运行环境来通信。JS桥接类的作用是将开发者的调用行为加入到React Native的模块调用队列,同时生成一个回调的ID。Native桥接类的作用是将队列里的调用行为取出来根据模块找到对应的原生UI或者本地能力的函数来执行,并将执行的结果通过回调的ID逐步传递到开发者的JS回调函数中。也就是经过这两个桥接类的相互作用,建立起了JS函数与原生能力的调用序列。

其中不得不提的是React Native进行了虚拟DOM的封装,所有的视图的更新都是虚拟DOM做了一个校验(diff)后最小更新,用内存计算换取UI渲染效率。而开发者可以(不是必须)使用一种叫JSX的语法即可达到像web开发一样使用标签和CSS样式表来开发React Native应用,React Native会将JSX转化为JS语法通过上述通信流程完成原生UI的渲染和本地能力的调用。

var React = require('react-native');

var styles = React.StyleSheet.create({
    text: {
        color: 'red',
        backgroundColor: 'white',
        fontSize: 30,
        margin: 80,
        textAlign: 'center'
    },
    container: {
        flex: 1
    }
});

class HelloWorld extends React.Component {
    render() {
        return React.createElement(React.Text, {style: styles.text}, "Hello World!");
    }
}

class Main extends React.Component {
    render() {
        return (<React.NavigatorIOS
            style={styles.container}
            initialRoute={{
              title: 'Property Finder',
              component: HelloWorld,
            }}/>);
    }
}

上面的代码段就是一个React Native的例子。它定义了两个组件,一个是HelloWorld,一个是Main,其中HelloWorld组件作为Main组件的一部分进行展示。我们可以看到Main组件里有一段XML的标签,这个语法就是JSX语法,当然,如果不习惯这种语法,也可以完全按照HelloWorld组件的定义,全是使用JS来定义。

ExMobi则是通过解析一种叫UIXML的标签并映射到原生组件的方式渲染窗口和界面,这个解析引擎称为UIXML引擎,在UIXML中也是支持CSS样式表和JS语法。

下面的代码就是一个UIXML代码文件:

<!-- ExMobi UIXML(XHTML)文件 -->
<html>
         <head>
                   <meta content="charset=utf-8"/>
                   <title>dom数据注入</title>
                   <script type="text/javascript" src="res:script/exmobi_lite/core.js"></script>
                   <script type="text/javascript" src="res:script/exmobi_lite/template-native.js"></script>
<style>
                            button {
                                     color : #ff0000;
                            }
                   </style>
                   <script>
                   <![CDATA[
                            function doRender(){                                   
                                     //更简单的用法就是直接对dom操作
                                     $('#content').renderAfter('res:page/template/my.template', 'http://domain/server.jsp', function(h, t, o){
                                               //alert($.JSON.stringify(o));
                                     });
                            }
                   ]]>
                   </script>
         </head>
         <body>
                   <font style="color: #c0392b;">数据注入函数</font>
                   <div style="margin:4 0;">
                            $(selector).renderReplace(str, data, callback);//注入后的数据替换原来dom内的内容
                   </div>
                   <div style="margin:4 0;">
                            $(selector).renderAfter(str, data, callback);//注入后的数据在dom内尾部插入
                   </div>
                   <div style="margin:4 0;">
                            $(selector).renderBefore(str, data, callback);//注入后的数据在dom内顶部插入
                   </div>
                   <div style="text-align: center;">
                            <input id="btn" type="button" value="点击测试" onclick="doRender()"></input>
                   </div>
                   <div id="content"></div>
         </body>
</html>

从上面的代码可以看到很多熟悉的身影——HTML、CSS、JS,所以使用ExMobi开发移动应用跟web开发基本相差无异,而这种开发方式也容易被开发者认为是采用了webview的引擎来实现,实际上并非如此。在ExMobi的原生应用中完全可以一个html文件都不需要创建,也不会产生对webview的调用。

那ExMobi又是如何做到的呢?

React Native与ExMobi技术路线探索

ExMobi应用都是从一个UIXML描述文件开始的,此文件中的内容为类似HTML的标签,支持CSS和JS语法,但是并不是标准的HTML。从1至4步骤中,我们可以看到UIXML引擎将UIXML文件解析并渲染为原生组件的过程。这个过程中,会为每一个UIXML组件都生成一个ID,对于部分有生命周期事件(加载完毕、处于激活状态、处于非激活状态、销毁等)的组件会进行JS事件的触发。

第5步就是将UIXML界面中的组件的JS事件和开发者的自定义函数绑定到UIXML的JS运行环境中。

第6-13步跟React Native类似,也是先经过一个JS桥接类的序列化要执行的函数,然后再映射到原生的函数中来执行。

与React Native不同的是,ExMobi没有虚拟DOM的概念,UIXML描述是直接映射到Native View中的。这种实现方式在操作DOM时,如果不产生容器的变化一般是对性能和效率影响不大的。但是为了保证效率与性能的提高,UIXML提供了原生UI批处理的JS桥接类(window.beignPreferenceChange()与window.endPreferenceChange()),当开发者遇到DOM大量及多次改动,或者无法判断是否会产生较大改动时,可以按需将DOM操作包含在此批处理类中,UIXML引擎会从内存中通过组件的ID来判断组件的状态,使一组在批处理内的DOM结构改变只需一次刷新,从而提高原生UI的渲染效率。

从React Native和ExMobi在原生组件的通信原理中可以看出,这类以原生UI组件为展示基础的开发框架的核心就是对原生组件的封装和桥接技术的使用。但是React Native是从JS文件开始,在JS中可以渲染UI标签,而ExMobi则是从UI标签(UIXML)文件开始,在UIXML中可以绑定JS函数和事件。

且两者的实现都是以Run Time技术为核心理念的,所有的原生组件都是运行中创建的,而不是在一开始就编译好,这与交叉编译的实现方式有本质的不同。Run Time的好处就在于业务逻辑的代码可以实时的载入,不需要重新编译客户端,无须重新打包发布,面对审核严厉的AppStore来说,对开发者无疑是一个很大的利好。

当然,对于原生组件封装的颗粒度和使用的原生组件分类,甚至Android和iOS的封装是否需要一致也是开发者热衷于讨论的话题。或者下次可以有幸再跟各位分享。

开发与调试

不同的开发者对开发工具的使用习惯各不相同,正所谓工欲善其事,必先利其器,选准了工具才能提高开发效率。那React Native和ExMobi各自使用什么工具进行开发和调试的呢?形式又是怎样的呢?

React Native并没有自主的开发工具。其开发方式是先到官网上下载React Native的安装包,然后使用npm(NodeJS的包管理工具)来安装并下载相关依赖模块。创建工程也是通过npm来完成。创建完的工程包含了Android和iOS的子工程,分别需要各自搭建原生的开发环境方能运行。所以React Native对开发者的要求是需要有一些原生开发的基础的。并且,如果你是要做iOS应用的开发,则需要有一台MAC电脑。

搭建好原生开发环境之后,开发者就可以使用HTML编辑器来通过编写JS文件完成开发,效果查看需要启动相应的编译工具和模拟器,比如:iOS需要通过XCode来编译应用到模拟器中,代码中可以使用Console类来打印日志到XCode的控制台中查看,但是无法进行debug调试。有一点比较好的是,当JS有改动的时候,无需重新编译就看到修改后的效果,非常方便,这也是有赖于React Native的Run Time机制。

特别的,如果开发者想要在真机上调试那就有些麻烦了。React Native开发时加载JS的方式是通过启动HTTP接口来动态刷新的,而默认是本机调试的接口地址对应的IP和端口为127.0.0.1:8081,在真机上调试显然是无法连接到此接口的,这就需要开发者自己通过命令来修改,然后编译一个React Native的原生安装包给真机安装好才能连接到想要调试的开发环境中。这个过程比较复杂,无论是对原生开发者还是web开发者来接触React Native开发都需要一定的过渡时间。

并且,由于React Native的原生组件在不同平台上的写法不同,Android有自己的组件,iOS也有自己的组件。当开发者开发完某个平台的应用的时候,想要在另一个平台上运行,还需要修改代码符合目标平台的规范。

这也是为什么说React Native是Learn Once , Write Anywhere的原因——使用React Native开发Android和iOS的应用,开发方式是一样的,只是写法稍有不同,可以做到技术经验的积累。

由于React Native的开发和调试方式跟原生类似,此处省略N张截图。

ExMobi具有自主的开发工具叫MBuilder,无论是开发Android还是iOS应用都可以在这里面完成。开发者只需要下载MBuilder安装包进行一键安装即可进行ExMobi应用的创建、开发、模拟器调试、真机调试等一系列简单方便的操作。这主要也是有赖于ExMobi的UIXML引擎在多个平台上的定义和实现是一致的,也就是说写好一套代码就可以在多个平台上运行,无须对代码进行区分修改。

下图为MBuilder的界面,它是基于eclipse的一个插件,自定义了很多内置编辑器,组件拖拽,真机调试等功能,并能在创建应用的时候使用现有模板。

React Native与ExMobi技术路线探索

特别的是,ExMobi有个基座的概念的,结合前面介绍Run Time模式,与React Native相似,UIXML、JS和CSS等代码也是要通过HTTP接口加载到基座中就可以运行出原生的界面,为了开发调试方便,基座上可以直接配置IP和端口,所以任何机器上的ExMobi代码可以很方便的同步到模拟器或者真机上调试。

下图即为PC版基座模拟器的截图:

React Native与ExMobi技术路线探索

更强大的是, 开发者可以在PC版的ExMobi模拟器中对UIXML的JS代码进行调试,并综合Console控制台日志进行错误分析,开发调试跟在Chrom/Firefox中调试JS一样,非常方便。

React Native与ExMobi技术路线探索

同时,MBuilder支持一键生成安装包,并安装到真机中运行查看效果,在开发个阶段都能帮助开发者提高开发效率。

React Native与ExMobi技术路线探索

所以,ExMobi提倡的是Write Once , Run Anywhere,在Android和iOS中使用相同的用户体验。当然,ExMobi提供了区分Android和iOS的函数,开发者也可以根据需要做平台差异化展示。

组件的数量和扩展方式

对于开发者来说成熟的组件以及灵活的扩展无疑是对高质量应用的最佳保障。

从React Native官网上大概可以看到其有30个左右的组件,有的仅支持Android,有的仅支持iOS,但是其中的View组件是可以比较灵活的通过组合来形成新的组件。

React Native与ExMobi技术路线探索

而且React Native支持组件的扩展,通过原生开发就可以开发出符合自己要求的UI组件。目前市面上也有一些不错的React Native UI组件,比如:表单处理组件、照相/摄像组件、视频播放组件、轮播组件等等,基于Facebook的影响力,未来应该还会涌现出很多优秀的组件插件库。

下面就来亲眼目睹一下:

React Native与ExMobi技术路线探索  React Native与ExMobi技术路线探索

React Native与ExMobi技术路线探索  React Native与ExMobi技术路线探索

ExMobi的原生UI组件从官网提供的开发手册中可以看到90+个组件,并且在其公开的原生插件也有30多款,除了基本的UI布局组件,比如:九宫格、列表、下拉刷新、轮播、通讯录、拍照摄像、日期时间选择组件等等。

当然,ExMobi也支持对原生UI和能力的扩展,开发者也可以通过原生开发扩展ExMobi的能力。所以也有很多跟国内广泛使用的SDK结合的原生插件,比如:百度地图、讯飞语音、支付宝、微信/微博分享/登录、汉王名片识别、百度影音播放等等,以及一些专业的企业级SDK集成,比如:深信服VPN、企业版WPS文档编辑、蓝牙打印、身份证识别、CA认证等等。

所以,从本地化的角度看,ExMobi扎根国内,需求比较接地气,更容易满足开发者的需要。而对于React Native想要适应目前的开发环境,还需要不断的定制出更多的符合要求的组件。

下面是从ExMobi论坛上的一些截图:

React Native与ExMobi技术路线探索  React Native与ExMobi技术路线探索

React Native与ExMobi技术路线探索  React Native与ExMobi技术路线探索

第一个真不是格瓦拉上截的图哦,ExMobi官网上还有很多比较成熟的UI界面分享,基本可以满足大部分的开发需要。

面向的开发者

从前面的了解, React Native和ExMobi的开发语言都是以类web的标签化+JS开发为主,并且都支持原生组件和能力的扩展,所以,无论是web开发者还是原生程序开发者要使用这两个工具都不是非常难的事情。

这里主要是从React Native和ExMobi的一些宣讲和推广等渠道了解的信息作为判断。

React Native从开发环境的搭建到开发方式上其实都是偏向于原生的,纯粹的web开发者要想很快能够熟练使用React Native甚至说是搭建开发环境似乎还是要多花一些心思的。并且在React Native的宣讲中,仍然是建议原生开发者能够尝试接纳React Native这种新的开发模式,以提高自己的开发效率。或许可以推断,React Native在设计之初所考虑面向的开发者为原生开发者。

ExMobi则把移动应用开发的各个环节都通过MBuilder这个IDE来紧密集合。一键安装的跨平台开发工具和更接近的web开发模式对于传统web开发人员来说不可谓无故意而为之的“嫌疑”,而从官方提供三类开发者,UIXML开发者、HTML5开发者和原生插件开发者来看,如果单纯使用ExMobi来开发,不考虑原生插件,那么其面向的开发者必定的是web开发者。当然

当然,现在全栈式开发越来越多的走进人们的视野,单一的技术已经无法满足开发的需要,或许对不同技术的巧妙应用才能带来下一波的技术创新。这里我们讨论的只是从入门和使用的角度的受众,对技术的不断探索对于程序员来说是不遗余力的。

与HTML5的结合

Native与HTML5从来都不是竞争关系,而更多的是合作关系,只是不同的开发者使用的比例不同罢了。但是如何结合,React Native与ExMobi也都提出了各自的思路。

React Native使用的JSX其实就是一个JS框架,这个框架在Facebook的另一个产品React JS中也是一个基础,应该是属于一个体系中的产品。所以,这一体系中的产品无论Android、iOS还是Web,开发方式都是一样的,只是各自的UI组件不同,每一种平台都要渲染自己的UI组件。

而React JS本身也没有对H5的组件做过多的封装,而是提出了一种全新的UI组件的封装与渲染模式,它与MVV*概念不应相提并论,而是可以跟jQuery、BootStrap等优秀的前端框架一起来使用。

除此之外,React Native也支持webview组件来使用HTML5。所以,从Web到Native,React的整个体系还是相对比较完整的。

ExMobi也有一个HTML5的开发框架伴侣——Agile Lite移动应用前端框架,此框架是一个完整的MVC的框架,而且封装的UI组件与ExMobi的UI组件基本一致,并支持组件的扩展。同时可以在ExMobi的webview组件和微信中智能调用各自的本地能力,而在普通浏览器中则调用浏览器能力。开发者可以很方便的使用框架进行完整webapp的开发而不需要再借助其他的前端框架(当然也可以结合Bootstrap、Ratchet等框架)。而其对微信API的封装也可以提升微信应用的开发效率,基于ExMobi支持的webview组件,使用Agile Lite开发的微信应用也可以方便移植到ExMobi开发的原生app中。

下面是Agile Lite官网提供的示例,开发者可以体验一下:

React Native与ExMobi技术路线探索

总结

对于开发者来说现在有越来越多的技术方向可以选择,移动应用开发也不例外。React Native以其敏锐的技术眼光与ExMobi多年的市场检验结果不谋而合,都坚定的选择了移动应用原生开发的技术路线,并通过各自的技术特点将原生开发的思路扩展到web开发的领域,通过web开发的技巧使开发的APP完全具备原生应用的所有高效、流畅、无限接近系统效果的用户体验。虽然在技术路线上稍有不同,但也给开发者更多的思考空间,相信随着移动物联时代的不断进步,还会涌现出更多新的思维和模式,请让我们一起翘首期待。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
Java获得今日零时零分零秒的时间(Date型)
publicDatezeroTime()throwsParseException{    DatetimenewDate();    SimpleDateFormatsimpnewSimpleDateFormat("yyyyMMdd00:00:00");    SimpleDateFormatsimp2newS
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这