HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

flutter、rn、uni-app比较

flutter rn React Native weex

更新DCloud已推出强大的uni-app x,性能更优。 详见

关于uni-app x与flutter等其他跨平台方案的对比,详见:https://doc.dcloud.net.cn/uni-app-x/select.html

-----下文已过期-----

前言

每当我们评估新技术时要问的第一个问题就是“它会给我们的业务和客户带来哪些价值?”,工程师们很容易对闪闪发光的新事物着迷,却经常会忽略这些新事物其实可能对我们的客户没有任何好处,反而只会让现有的工作流程更加复杂。

先解释2个读者常见误解,不然很多内容看不懂:

  1. uni-app不是web app,它支持原生渲染
  2. uni-app虽然使用了weex,但自己大量改进了weex,和阿里是否继续维护weex没有关系

flutter最近比较热闹,毕竟是Google出品。

但我们不是炒作热点的媒体,也不是忽悠你交学费的培训机构,我们作为实际的跨平台开发者,冷静的分析下这个东东。

flutter是Google为Fuchsia操作系统设计的应用开发方式。

Fuchsia OS要兼容廉价物联网设备,要求对硬件的消耗降低,并且为了避免与oracle的java打官司,Fuchsia 使用了dart语言+flutter界面库的方式。

从设计上来看,这套方案的性能确实够高。dart虽然属于大前端范畴,但dart是和java一样的强类型语言,这让dart虚拟机可以做很多优化,性能方面超出了js。

dart曾经与typescript竞争,谁才是更好的js?但不幸输给了typescript,chrome也放弃了内置dart虚拟机的计划。

不过dart团队没有解散,几年后,他们借助flutter,再次出现在公众面前。

性能分析和写法的对比

flutter作为界面库(注意它只是界面库,dart语言是另一个项目),它唯一要干的事情就是渲染界面。不像HTML5,flutter界面库连视频、定位等都没有,就是一个纯排版引擎,绘制文字、按钮、图片等常用界面控件。

这个排版引擎的特点是简单、高性能。

在3大主流渲染引擎里,webview渲染、js调用原生渲染(react native/weex/uni-app)、flutter自绘渲染。(uni-app是双渲染引擎,webview和weex都内置了,随便开发者使用切换)

所以我们要清楚,提升性能是有代价的,你究竟想要灵活丰富的css3,还是想要固定flex模式排版,抑或是最简单但高性能的flutter排版?开发便利性和运行性能不可兼得。

同时我们要明白,性能的差别,并不是因为Google的chrome团队、Android团队的技术比同公司的flutter团队差。而是flutter提供的布局写法是被限制过的,解析快,所以渲染快。别忘了webview的排版引擎也是世界级工程师用c写的。

但通过这种方式提升性能的代价,就是布局复杂的界面时,flutter的代码嵌套的让人崩溃。

我们先举个例子,同样的界面,用HTML和flutter如何实现:

<div class="greybox">  
  <div class=redbox>  
    smaple text  
  </div>  
</div>  

.greybox {  
  display: flex;  
  align-items: center;  
  justify-content: center;  
  background-color: #e0e0e0; /* grey 300 */  
  width: 320px;  
  height: 240px;  
  font: 18px  
}  
.redbox {  
  background-color: #ef5350; /* red 400 */  
  padding: 16px;  
  color: #ffffff  
}
var container = new Container( // grey box  
  child: new Center(  
    child: new Container( // red box  
      child: new Text(  
        "smaple text",  
        style: new TextStyle(  
          color: Colors.white,  
          fontSize: 18.0,  
        ),  
      ),  
      decoration: new BoxDecoration(  
        color: Colors.red[400],  
      ),  
      padding: new EdgeInsets.all(16.0),  
    ),  
  ),  
  width: 320.0,  
  height: 240.0,  
  color: Colors.grey[300],  
);

可以看出,从代码的写法来说,flutter没有tag和样式的说法,更没有css选择器,从头到尾只有dart语言,它的界面控件是用dart代码new出来的,每个控件的样式,是在new的时候设置的类json写法的参数。

如果我们要嵌套布局,就要不停的在dart里写child,同时在dart里给child们设样式参数。上面的代码,只是嵌套了1层,实际开发中,dom要嵌套好多层,想象那样的代码。。。所以大家都诟病dart是“嵌套地狱”。

或者,你可以这么理解,这是一个只有js,没有html和css的浏览器。你需要用js createElement来创建元素,用js的style方法给每个element设style,反正就是不能写html和css代码。前端都已经发展到各种mvc等视图逻辑分离的架构了,也有了vue组件这种组件化模式方便用各种轮子快速完成界面。你是否能适应dart这种低效的界面开发模式?从开发模式来讲,这确实是一种倒退。

浏览器的html提供了tag和样式分离的写法,还有各种各样的css选择器,但其实这也是有代价的。它导致webview初始化时要同时先启动webkit排版引擎来解析这些编写随性的html、css,同时还要启动一个js引擎比如v8或jscore来解析里面的js。

而dart就很简单,只启动一个dart引擎,解析严格的dart语法,它不会去操心有些标签未闭合要如何容错,不会判断宽度320后面是px还是rem或者是动态计算百分比。

对比这2个引擎初始化时要干的事,差别简直太大了。

所以从解析效率上,flutter肯定比webview要高。但从编码灵活性上,flutter写的代码,嗯,难看而低效!

flutter使用的也是flex布局思想,这是一个强嵌套布局模型,比web常规排版引擎的嵌套更多。当界面复杂时,flutter的代码要嵌套几十层,每层的元素的json样式都和元素一起混写在dart代码里,让人崩溃。

有人提出是否可以通过一种预编译的dsl来简化写法,让flutter的开发不这么痛苦。

但这个难度太大了,从严格转换为松散是简单的,从松散转换为严格几乎是不可能的。

什么意思呢?比如flutter代码转换web代码,是很简单的,flutter已经自带了这个功能。但是想反过来,那可难了。

类似的还有,把typescript转为js是容易的,反之,不是绝对不可行,但会复杂到你宁愿去重写一套typescript代码。

flutter的性能高,除了简单严格,还有一个特点,就是逻辑层与视图层统一,运行在同一套dart虚拟机下。

我们知道rn、weex以及uni-app的nvue,也是原生渲染的,它们的性能高于webview。但同为原生渲染的,怎么会慢于flutter呢?其实不是原生渲染慢,而是js和原生通信慢。

rn、weex以及uni-app的nvue都采用了独立的js引擎(iOS是jscore,Android是v8,最新版rn开始在Android上搞自己的js引擎Hermes),从js与dart的比较上,性能稍逊一筹。但这不是主要问题,因为v8的jit不是盖的,也是编译为字节码解析的。性能上的主要问题是:rn、weex、uni-app的js引擎和原生渲染层是两个运行环境。

当js引擎联网获取到数据后,通知原生视图层更新界面时,有一个跨环境的通信折损。同样,当用户在屏幕上操作原生视图层时,要给js引擎发送通知,也会产生这个通信折损。

不过这种性能差别,在大多数场景中,用户是感受不到的。比较影响的场景,是跟手式的js响应操作绘制帧动画,或者说js连续操作界面元素方面,flutter折损更少。

这个通信折损,其实普遍存在于所有逻辑和视图分离的框架中,包括国内各家小程序也有这个问题。

为了解决react native上js绘制动画卡的问题,曾经的react native拥趸aribnb搞了一个lottie的动画库,但lottie只能静态执行,无法跟手交互。weex更进一步,搞了个BindingX,这个技术很赞,它可以预定义规则,让用户界面在原生层交互时通过预定义规则直接响应,而无需传递给js层。在需要短时间内来回通信的场景时,可以使用BindingX这类解决方案。它的性能和灵活性比rn更强了一些。

在uni-app里,nvue页面可以直接使用bindingx。至于uni-app的vue页面不是基于weex渲染的,它遇到通信折损时,解决方案叫wxs,wxs是一种运行在视图层的js,它的性能和和灵活性都非常高,完全可以达到flutter的水准。

说回来flutter,它只有一个dart引擎,没有来回通信产生的性能问题。不过任何事情都是有利有弊的,flutter在普通的界面绘制上效率虽然高,但一旦涉及原生的界面,反而会遇到更多问题。

前面已经说过,flutter只是一个基础排版引擎,缺少很多能力,当我们需要在flutter界面上内嵌一个原生的视频播放扩展控件时(flutter没有内置视频播放能力),或者原生的高德地图sdk,那么在拖动视频进度时、拖动地图时,flutter一样会产生原生和dart之间的通信,造成性能损耗。

事实上,由于flutter是在一个类canvas环境绘制的,想把一个原生控件嵌入flutter的布局里某些元素之间去排版,还不是一件容易做到的事情,坑很多。

每个人都想要一个像css3那样灵活写法的布局引擎,他们给react native和weex提需求,给flutter提需求。殊不知,让这些产品团队实现了css3时,他们的性能优势已经不再了,他们相当于又实现了一遍webview。这种无意义的需求,他们是不会受理了。

性能好,有个度,客观地讲,rn/weex调用原生渲染的性能,和flutter的渲染性能,在用户体验上并没有明显区别,甚至在很多场景下,和webview渲染的小程序也没有明显区别。

也简单说说webview渲染小程序,为什么性能高,核心是预载。点击一个新页面时,webview是提前创建好的,不会走复杂的webkit、v8的初始化流程,连开发者的js代码,也是预载好的。所以点击新页面时,它的渲染速度和原生应用没什么差别。当然也有个坏处,就是启动慢。微信里启动小程序速度看着还行,其实是微信在启动小程序之前,就已经提前初始化了小程序运行环境。

即便是排版引擎,ui库好用吗?

不管是rn还是flutter,有一个设计,很不中国化。它们在iOS和Android平台上,使用2套ui库。

比如flutter,在iOS上写一个button,要用CupertinoButton,是iOS风格的控件,在Android上则要用RaisedButton,是Material风格的控件。

rn也是如此,它的官方说法是:learn once,write anywhere。它都不敢说:write once,run anywhere。因为它确实要求开发者写2套代码。

中国的开发者可没有这种习惯,中国的每个开发者,为了避免用户换手机后不会用自己的app,都会使用中性的设计。

就连微信Android版,底部的tab也是仿iOS而不是Material风格(Material风格是把底tab放在顶部的,并且左右滑动,微信曾经有这样一个临时版本,因为被用户吐槽,很快就下掉了)。

这种中外差异怎么造成的?

国外Android手机,其手机主界面就是强烈的Material风格。用户在Android主界面习惯的风格和使用方式,如果启动一个App后不是这样,会导致用户不会用了。

Google也一再给Android开发者强调,App必须使用Material风格。这其实也是一个防止用户切换脱离Android生态的策略设计。

所以国外开发者的App,Android上都会遵循Material风格,当然,这种Material风格的App是上不了Apple的Appstore的。

这就导致他们默认就是要写2套ui的,所以rn和flutter都是iOS、Android各自1套ui控件。

但在中国,我们的国产Android Rom,根本不是Material风格,很多rom以仿iOS体验为卖点。

所以中国的App,全都是贴近iOS的中性风格,中国的用户换了手机,不管是手机os本身,还是App的使用,都不会造成切换障碍。

rn和flutter这种“跨平台”排版引擎,其跨平台性,对于中国开发者而言,又打了折扣。

其实类似小程序那样的ui风格,是能够良好的跨iOS和Android的体验的,不管用什么手机,打开小程序都不会觉得有问题。

uni-app默认也是这种通用ui风格。uni-app的开发者只需要写一套界面ui,就可以适应不同手机的用户,真正的 write once,run anywhere。

动态性

webview、rn/weex,都有一个特点,可以远程动态载入js代码,可以更新本地的js代码。前端开发者认为动态性是天经地义的,但其实flutter并不支持。

flutter是有编译优化概念的,如果它提供动态性支持,会影响它的性能。

业内有些开发者,改造了flutter,用一个独立的v8/jscore来加载动态js代码,去操作flutter布局引擎的渲染。好像还有些人在追捧这样的方案,简直是闲得蛋疼。

flutter本来没有跨环境通信的问题,结果又弄了一个js引擎进来搞出了进程通信问题,造成性能下降,还把包体积增加了很大,还不如直接用rn/weex/uni-app。

除了flutter,rn/weex/uni-app都可以动态热更新。

跨平台排版引擎和跨平台应用开发引擎的区别

有些人说他们的App用rn/weex、flutter。但是具体用它们做了什么呢?

是整个App用了它们,还是某个页面用了它们?

一个页面跨平台,和一个应用跨平台,是完全不同的2个概念。

webview、rn/weex、flutter全部是渲染引擎,webview因为HTML5的发展,还算是多了一些能力比如位置服务、多媒体等。而rn/weex、flutter真的只是一个纯粹的排版引擎,没有任何原生能力。

如果一个原生应用里,某个不涉及原生能力的界面想跨平台,那么这几个引擎都可以,并且flutter的性能最高。所以能看到一些公司尝试把App中的个别原生交互较少页面使用flutter实现。

但如果一个完整的应用,想用跨平台工具开发,那就不是排版引擎的范畴了,它需要应用开发引擎。

什么是跨平台应用开发引擎?不但排版部分要跨平台,开发API也要跨平台。

应用开发离不开os或三方sdk的能力调用,如果是单纯的排版引擎,一旦涉及os能力和sdk调用,就必须iOS、Android的工程师配合,编写不同的原生代码整合在一起。这就不跨平台了。

Airbnb曾是React Native 框架的倡导者和开发者代表。但他们于2019年正式发公告,弃用了react native。

原因是什么?

很简单,react native并不能提升Airbnb的开发效率,反而降低了他们的效率。

“本来我们可以只维护Android和iOS两套代码,但现在我们要维护三套(指多了一套react native的js代码),这让我们很疲惫” -- aribnb

开发者选用跨平台开发引擎,本来是为了提高效率、降低成本。Airbnb正是在实践了几年后,发现rn根本无法实现他选用跨平台引擎的初衷时,无奈放弃了rn,用原生开发重写。

要想真的提升开发效率,降低开发成本,那么跨平台开发引擎,需要提供一个完整的应用开发平台,包含所有常用的应用开发能力的跨平台。在不常用的部分,提供插件市场以及免原生介入的插件使用方式。

在react native、flutter的社区,也有不少三方提供的原生插件,但是连Airbnb这样的国外开发者对此都不满意。更何况对于很多中国开发者常用的场景,其对应的插件的质量、跨端性都难以商用。

更麻烦的是如果你不会原生开发,就没法把这些插件与你的前端代码集成起来。

uni-app,它的设计目标不是跨平台排版引擎,而是跨平台应用开发引擎。

所以uni-app的排版部分,可以选择小程序强化webview引擎和weex引擎,可根据自己的需求切换。而能力层面,uni-app提供了htmlplus API、Native.js、插件市场,解决了原生能力js化的问题。

uni-app让开发者真的不用懂原生开发就能做出完整的跨平台应用。遇到极个别的需求,开发者也可以去插件市场找人订做一个原生插件,自己仍然使用js来集成,仍然可以云端直接打包。

技术学习成本和难度

rn,要求开发者学习react,要求精通flex布局,要求原生开发协作。

flutter,要求开发者学习dart,了解dart和flutter的API、要求精通flex布局,要求原生开发协作。

weex已经内嵌到uni-app中,就不单独提了。

uni-app,要求开发者学习vue,了解小程序。

很明显uni-app的学习成本太低了,它没有附加专有技术,全部使用公共技术。

学习成本和难度,直接意味着:开发成本、招聘成本、上线速度、上线风险。

另外,dart究竟值不值得学,是一个大问题。

Google的天才工程师也发明了go语言,它确实有很多理论优势,但实际上市场的主流,仍然是c和c++。

质量

这几种跨平台引擎,整体的质量水平是差不多的,都是可以商用,但是有各种小坑。

2020年7月6日的数据,各家的github的issues如下: 框架 issues
uni-app 557
react native 816
flutter 7840

代码量是flutter最多,对应它的issues的数量也越多。
对于uni-app和react native来讲,渲染层是基于相对成熟的原生渲染或webview渲染来做的,不像flutter一切都是自己实现。而逻辑层uni-app也使用相对成熟的v8和jscore,出问题的点相对要少。

各框架的更新都比较频繁,真的有影响商用的大问题,肯定都会及时修复。

目前各个框架都有较大的用户使用量,质量方面均是可控的。

生态

任何开发引擎,都离不开生态。

对于国内的开发者,有很多独特的开发sdk,中国开发者需要的全端推送(UniPush集成了iOS、华为、小米、OPPO等众多原厂推送)、各种国内微信、阿里、微博等各种登陆、支付、分享SDK、各种国内地图、各种ui库、以及Echart图表等,都是在uni-app体系里,这方面生态可比rn、flutter丰富多了。uni-app的插件市场有数千款插件,不能说应有尽有,但确实是最丰富的跨端开发框架生态了。

另外,uni-app的生态还比其他竞品强在如下方面:

  • App和H5提供了renderjs技术,使得浏览器专用的库也可以在App和H5里使用,比如echart、threejs等参考
  • 兼容微信小程序 JS SDK,丰富的小程序生态内容可直接引入uni-app,并且在App侧通用,参考
  • 兼容微信小程序自定义组件,并且App、H5侧通用,参考

这些丰富的生态兼容,是rn和flutter无法享受的。

更新:2020年11月google全球开发者大会公布的数据,flutter全球月活开发者50万,中国占11%,也就是5.5万。这数字太小了,撑不起好生态。DCloud的开发者月活100万+,生态更繁荣。

其他端的跨端性

flutter和rn,都是支持web技术的。但都是仅限于普通界面排版,涉及定位、摄像头、相册什么的,是要单独写代码的。

另外flutter的H5版,嗯,作为中国开发者,你不会想要一个如此浓郁的Material风格的H5版的。。。

更何况这个Material ui库大的很,编译出来的H5版要十几M的体积。

uni-app的web端是包含非常完善的。

  1. 丰富能力都可以直接跨端使用,风格也是跨端风格。
  2. uni-app的web引擎体积只有1百K,gzip后只剩下30k(不含vue、vue-router),比其他工具的引擎体积要小的多。
  3. uni-app的web端是现今为数不多的、好用的响应式框架。bootstrap已经不行了。
  4. uni-app的web端支持ssr服务端渲染
    上面这些优势,都是flutter的web版不具备的。当然react的web版也可以实现这些,它的web代码和react native的代码重用度很低。

另外,中国离不开小程序,rn、flutter官方都不会支持小程序,由于架构差异太大,国内三方也做不到把rn代码良好的编译为小程序代码。uni-app则可以一套代码,同时编译为iOS、Android、Web、微信小程序、支付宝小程序、百度小程序、头条小程序、QQ小程序、京东小程序、快手小程序。

结论

每种技术的诞生,有其背后公司的目的。

但凡没有明确公司战略的技术,除非是特别简单的技术,否则很难商用,因为为了商用要投入公司非常多资源。

flutter诞生的目的,是为了Fuchsia OS,是为了在下一个互联网大潮,即万物互联的物联网年代,提供一个类似Android在移动互联网位置的垄断性操作系统。

因为Google已经很明确不会在下一个时代使用Android+java的路线了。

至于在Android上去java化,那是Kotlin的使命,与flutter无关。

跨iOS和Android平台开发,这不是Google的战略目标。

但万物互联何时到来?Fuchsia OS何时流行?这在现实中是一个问号,在Google内部,也只是战略储备项目。

一个语言的流行,不是一件简单的事情,不是有优点,就会流行,它需要天时地利人和。

6年前我们就知道dart比js更好,dart不应该消亡,但想成为主流技术,太难太难了。

同样我们也知道go比c++更好,但go还是起不来。

想靠flutter驱动dart流行是不现实的,甚至是反过来的。跨iOS、Android开发在国外不是主流市场,这点价值造就不出一个这么难建的生态。

所以dart能否流行,是要打一个大大的问号的,它可能会像go语言一样,叫好不叫座。

一个跨平台公司,应当是中立的。而flutter在这个位置上很尴尬,它是google出品的、同时跨iOS和Android的开发引擎。

如果这个引擎做大了,Apple会怎么看?那可不是像微信搞个小程序那么简单了,微信是中立三方,且只在中国。Apple不会让google的flutter在iOS上做大的。
本来Apple有政策,iOS的webview只能用Apple的UIWebview和WKwebview,js引擎只能用Apple的jscore,就是为了限制chrome和v8进入iOS生态。但google钻了个政策漏洞,在iOS上提供了dart引擎和Skia渲染引擎,这不算违反之前的Apple政策,但未来flutter真的做大的话,Apple高概率会更新政策,补上这个漏洞。

至于react native和uni-app,因为在iOS上使用了iOS自带的原生渲染和iOS的jscore,严格符合Apple政策,更加安全。

目前,flutter在国内一些大厂的原生App里得到了局部应用。这个应用场景,目的不是为了节省成本,flutter开发成本很高,生态也不完善,但因为性能高,一些大公司愿意负担这个代价来使用flutter,在原生app里部分页面使用flutter制作。但是这个场景,有个尴尬,就是flutter页面无法动态更新,但很多大app对动态发版的需求极强,有些厂商改造了flutter使其可动态发布,但又降低了flutter的性能。目前还没有一个完美的解决方案。

写了这么多,最后总结下flutter与uni-app的比较:

  • flutter与uni-app的相对优势:
    • 性能好一些。比rn有优势,但比拥有bindingx和wxs的uni-app,在实际开发中没有很明显的差距。
  • flutter与uni-app的相对劣势:
    • 需要原生协作,维护3套代码,无法有效降低开发成本,提升开发效率
    • 嵌套地狱,代码难看难维护
    • 不支持热更新
    • 目前质量和成熟度很低
    • 原生可视控件融合不好,比如webview、video、map
    • ui库不适合国情
    • 学习成本高
    • 应用场景有限,dart未来扑朔迷离

更新:uni-app里其实也可以使用flutter,有插件作者提供了插件,使得uni-app的应用在某些页面可以打开flutter页面,详见

再总结下rn和uni-app的比较

  • rn与uni-app的相对优势:
    • rn的坑虽然比weex的少,但uni-app已经填了weex的很多坑。这方面差别不大。
    • rn的生态虽然比weex丰富。但uni-app是反过来的,uni-app的国内应用生态丰富度超过了rn。
    • rn是纯单页的,嵌入原生App比较灵活。而uni-app是应用整体的概念,如果要内嵌入其他原生应用的话,要求原生应用内嵌uni-app应用整体进来。即集成uni小程序sdk
  • rn与uni-app的相对劣势:
    • 需要原生协作,维护3套代码,无法有效降低开发成本,提升开发效率
    • 不支持小程序,发布到h5也无法直接发
    • 性能不如uni-app
    • 国内的插件生态不如uni-app丰富
    • ui库不适合国情,learn once,write anywhere
    • 学习成本高,用人成本高,不利于开发商降低开发成本
    • rn是纯单页应用,如果一个应用的页面很多,用rn写会很崩溃,变量污染和干扰严重。而weex/uni-app支持多页面,页面之间上下文隔离,写页面较多的大型应用更合适
      另外react在中国的市场占有率远不如vue。这也是中国与国外不同的特色情况。

贴个vue、react、react native的百度指数对比,无论总体量的差距,还是发展趋势的下滑程度,可以明显看出react系在中国确实不行了。

中国的开发者,过去总会想:

  1. 小程序那套webview优化的技术,我能不能用到我的App里?现在uni-app已经为你解决了这个问题。
  2. weex能不能坑少点,API和插件多点?现在uni-app已经为你解决了这个问题。

如果你是一个资源充沛的大公司,原生App中部分不要求动态更新、也没有太多原生交互的页面,可以尝试使用flutter实现。但如果大范围使用,你也会遇到和aribnb一样的问题,维护3套代码还不如维护2套代码。

如果你开发uni-app选用了原生渲染,那App的性能足够好,且你得到了切实的开发效率的提升、成本的下降、快速和低风险的上线。

选择跨平台工具而不是原生开发,本质目的不就是为了成本和效率吗?在跨平台开发里能真正解决你本质需求的,就是uni-app。

当然,uni-app的app引擎并没有吊炸天。App平台,所有跨平台工具都还比不过原生,这是客观事实。只是,如果uni-app不能满足你的需求,你没有必要去用其他跨平台工具,直接上原生吧。

更新:近3年来,uni-app、react native、flutter都在持续发展。但从用户体量、社区规模对比,uni-app增长迅猛,而其他家表现平平。

继续阅读 »

更新DCloud已推出强大的uni-app x,性能更优。 详见

关于uni-app x与flutter等其他跨平台方案的对比,详见:https://doc.dcloud.net.cn/uni-app-x/select.html

-----下文已过期-----

前言

每当我们评估新技术时要问的第一个问题就是“它会给我们的业务和客户带来哪些价值?”,工程师们很容易对闪闪发光的新事物着迷,却经常会忽略这些新事物其实可能对我们的客户没有任何好处,反而只会让现有的工作流程更加复杂。

先解释2个读者常见误解,不然很多内容看不懂:

  1. uni-app不是web app,它支持原生渲染
  2. uni-app虽然使用了weex,但自己大量改进了weex,和阿里是否继续维护weex没有关系

flutter最近比较热闹,毕竟是Google出品。

但我们不是炒作热点的媒体,也不是忽悠你交学费的培训机构,我们作为实际的跨平台开发者,冷静的分析下这个东东。

flutter是Google为Fuchsia操作系统设计的应用开发方式。

Fuchsia OS要兼容廉价物联网设备,要求对硬件的消耗降低,并且为了避免与oracle的java打官司,Fuchsia 使用了dart语言+flutter界面库的方式。

从设计上来看,这套方案的性能确实够高。dart虽然属于大前端范畴,但dart是和java一样的强类型语言,这让dart虚拟机可以做很多优化,性能方面超出了js。

dart曾经与typescript竞争,谁才是更好的js?但不幸输给了typescript,chrome也放弃了内置dart虚拟机的计划。

不过dart团队没有解散,几年后,他们借助flutter,再次出现在公众面前。

性能分析和写法的对比

flutter作为界面库(注意它只是界面库,dart语言是另一个项目),它唯一要干的事情就是渲染界面。不像HTML5,flutter界面库连视频、定位等都没有,就是一个纯排版引擎,绘制文字、按钮、图片等常用界面控件。

这个排版引擎的特点是简单、高性能。

在3大主流渲染引擎里,webview渲染、js调用原生渲染(react native/weex/uni-app)、flutter自绘渲染。(uni-app是双渲染引擎,webview和weex都内置了,随便开发者使用切换)

所以我们要清楚,提升性能是有代价的,你究竟想要灵活丰富的css3,还是想要固定flex模式排版,抑或是最简单但高性能的flutter排版?开发便利性和运行性能不可兼得。

同时我们要明白,性能的差别,并不是因为Google的chrome团队、Android团队的技术比同公司的flutter团队差。而是flutter提供的布局写法是被限制过的,解析快,所以渲染快。别忘了webview的排版引擎也是世界级工程师用c写的。

但通过这种方式提升性能的代价,就是布局复杂的界面时,flutter的代码嵌套的让人崩溃。

我们先举个例子,同样的界面,用HTML和flutter如何实现:

<div class="greybox">  
  <div class=redbox>  
    smaple text  
  </div>  
</div>  

.greybox {  
  display: flex;  
  align-items: center;  
  justify-content: center;  
  background-color: #e0e0e0; /* grey 300 */  
  width: 320px;  
  height: 240px;  
  font: 18px  
}  
.redbox {  
  background-color: #ef5350; /* red 400 */  
  padding: 16px;  
  color: #ffffff  
}
var container = new Container( // grey box  
  child: new Center(  
    child: new Container( // red box  
      child: new Text(  
        "smaple text",  
        style: new TextStyle(  
          color: Colors.white,  
          fontSize: 18.0,  
        ),  
      ),  
      decoration: new BoxDecoration(  
        color: Colors.red[400],  
      ),  
      padding: new EdgeInsets.all(16.0),  
    ),  
  ),  
  width: 320.0,  
  height: 240.0,  
  color: Colors.grey[300],  
);

可以看出,从代码的写法来说,flutter没有tag和样式的说法,更没有css选择器,从头到尾只有dart语言,它的界面控件是用dart代码new出来的,每个控件的样式,是在new的时候设置的类json写法的参数。

如果我们要嵌套布局,就要不停的在dart里写child,同时在dart里给child们设样式参数。上面的代码,只是嵌套了1层,实际开发中,dom要嵌套好多层,想象那样的代码。。。所以大家都诟病dart是“嵌套地狱”。

或者,你可以这么理解,这是一个只有js,没有html和css的浏览器。你需要用js createElement来创建元素,用js的style方法给每个element设style,反正就是不能写html和css代码。前端都已经发展到各种mvc等视图逻辑分离的架构了,也有了vue组件这种组件化模式方便用各种轮子快速完成界面。你是否能适应dart这种低效的界面开发模式?从开发模式来讲,这确实是一种倒退。

浏览器的html提供了tag和样式分离的写法,还有各种各样的css选择器,但其实这也是有代价的。它导致webview初始化时要同时先启动webkit排版引擎来解析这些编写随性的html、css,同时还要启动一个js引擎比如v8或jscore来解析里面的js。

而dart就很简单,只启动一个dart引擎,解析严格的dart语法,它不会去操心有些标签未闭合要如何容错,不会判断宽度320后面是px还是rem或者是动态计算百分比。

对比这2个引擎初始化时要干的事,差别简直太大了。

所以从解析效率上,flutter肯定比webview要高。但从编码灵活性上,flutter写的代码,嗯,难看而低效!

flutter使用的也是flex布局思想,这是一个强嵌套布局模型,比web常规排版引擎的嵌套更多。当界面复杂时,flutter的代码要嵌套几十层,每层的元素的json样式都和元素一起混写在dart代码里,让人崩溃。

有人提出是否可以通过一种预编译的dsl来简化写法,让flutter的开发不这么痛苦。

但这个难度太大了,从严格转换为松散是简单的,从松散转换为严格几乎是不可能的。

什么意思呢?比如flutter代码转换web代码,是很简单的,flutter已经自带了这个功能。但是想反过来,那可难了。

类似的还有,把typescript转为js是容易的,反之,不是绝对不可行,但会复杂到你宁愿去重写一套typescript代码。

flutter的性能高,除了简单严格,还有一个特点,就是逻辑层与视图层统一,运行在同一套dart虚拟机下。

我们知道rn、weex以及uni-app的nvue,也是原生渲染的,它们的性能高于webview。但同为原生渲染的,怎么会慢于flutter呢?其实不是原生渲染慢,而是js和原生通信慢。

rn、weex以及uni-app的nvue都采用了独立的js引擎(iOS是jscore,Android是v8,最新版rn开始在Android上搞自己的js引擎Hermes),从js与dart的比较上,性能稍逊一筹。但这不是主要问题,因为v8的jit不是盖的,也是编译为字节码解析的。性能上的主要问题是:rn、weex、uni-app的js引擎和原生渲染层是两个运行环境。

当js引擎联网获取到数据后,通知原生视图层更新界面时,有一个跨环境的通信折损。同样,当用户在屏幕上操作原生视图层时,要给js引擎发送通知,也会产生这个通信折损。

不过这种性能差别,在大多数场景中,用户是感受不到的。比较影响的场景,是跟手式的js响应操作绘制帧动画,或者说js连续操作界面元素方面,flutter折损更少。

这个通信折损,其实普遍存在于所有逻辑和视图分离的框架中,包括国内各家小程序也有这个问题。

为了解决react native上js绘制动画卡的问题,曾经的react native拥趸aribnb搞了一个lottie的动画库,但lottie只能静态执行,无法跟手交互。weex更进一步,搞了个BindingX,这个技术很赞,它可以预定义规则,让用户界面在原生层交互时通过预定义规则直接响应,而无需传递给js层。在需要短时间内来回通信的场景时,可以使用BindingX这类解决方案。它的性能和灵活性比rn更强了一些。

在uni-app里,nvue页面可以直接使用bindingx。至于uni-app的vue页面不是基于weex渲染的,它遇到通信折损时,解决方案叫wxs,wxs是一种运行在视图层的js,它的性能和和灵活性都非常高,完全可以达到flutter的水准。

说回来flutter,它只有一个dart引擎,没有来回通信产生的性能问题。不过任何事情都是有利有弊的,flutter在普通的界面绘制上效率虽然高,但一旦涉及原生的界面,反而会遇到更多问题。

前面已经说过,flutter只是一个基础排版引擎,缺少很多能力,当我们需要在flutter界面上内嵌一个原生的视频播放扩展控件时(flutter没有内置视频播放能力),或者原生的高德地图sdk,那么在拖动视频进度时、拖动地图时,flutter一样会产生原生和dart之间的通信,造成性能损耗。

事实上,由于flutter是在一个类canvas环境绘制的,想把一个原生控件嵌入flutter的布局里某些元素之间去排版,还不是一件容易做到的事情,坑很多。

每个人都想要一个像css3那样灵活写法的布局引擎,他们给react native和weex提需求,给flutter提需求。殊不知,让这些产品团队实现了css3时,他们的性能优势已经不再了,他们相当于又实现了一遍webview。这种无意义的需求,他们是不会受理了。

性能好,有个度,客观地讲,rn/weex调用原生渲染的性能,和flutter的渲染性能,在用户体验上并没有明显区别,甚至在很多场景下,和webview渲染的小程序也没有明显区别。

也简单说说webview渲染小程序,为什么性能高,核心是预载。点击一个新页面时,webview是提前创建好的,不会走复杂的webkit、v8的初始化流程,连开发者的js代码,也是预载好的。所以点击新页面时,它的渲染速度和原生应用没什么差别。当然也有个坏处,就是启动慢。微信里启动小程序速度看着还行,其实是微信在启动小程序之前,就已经提前初始化了小程序运行环境。

即便是排版引擎,ui库好用吗?

不管是rn还是flutter,有一个设计,很不中国化。它们在iOS和Android平台上,使用2套ui库。

比如flutter,在iOS上写一个button,要用CupertinoButton,是iOS风格的控件,在Android上则要用RaisedButton,是Material风格的控件。

rn也是如此,它的官方说法是:learn once,write anywhere。它都不敢说:write once,run anywhere。因为它确实要求开发者写2套代码。

中国的开发者可没有这种习惯,中国的每个开发者,为了避免用户换手机后不会用自己的app,都会使用中性的设计。

就连微信Android版,底部的tab也是仿iOS而不是Material风格(Material风格是把底tab放在顶部的,并且左右滑动,微信曾经有这样一个临时版本,因为被用户吐槽,很快就下掉了)。

这种中外差异怎么造成的?

国外Android手机,其手机主界面就是强烈的Material风格。用户在Android主界面习惯的风格和使用方式,如果启动一个App后不是这样,会导致用户不会用了。

Google也一再给Android开发者强调,App必须使用Material风格。这其实也是一个防止用户切换脱离Android生态的策略设计。

所以国外开发者的App,Android上都会遵循Material风格,当然,这种Material风格的App是上不了Apple的Appstore的。

这就导致他们默认就是要写2套ui的,所以rn和flutter都是iOS、Android各自1套ui控件。

但在中国,我们的国产Android Rom,根本不是Material风格,很多rom以仿iOS体验为卖点。

所以中国的App,全都是贴近iOS的中性风格,中国的用户换了手机,不管是手机os本身,还是App的使用,都不会造成切换障碍。

rn和flutter这种“跨平台”排版引擎,其跨平台性,对于中国开发者而言,又打了折扣。

其实类似小程序那样的ui风格,是能够良好的跨iOS和Android的体验的,不管用什么手机,打开小程序都不会觉得有问题。

uni-app默认也是这种通用ui风格。uni-app的开发者只需要写一套界面ui,就可以适应不同手机的用户,真正的 write once,run anywhere。

动态性

webview、rn/weex,都有一个特点,可以远程动态载入js代码,可以更新本地的js代码。前端开发者认为动态性是天经地义的,但其实flutter并不支持。

flutter是有编译优化概念的,如果它提供动态性支持,会影响它的性能。

业内有些开发者,改造了flutter,用一个独立的v8/jscore来加载动态js代码,去操作flutter布局引擎的渲染。好像还有些人在追捧这样的方案,简直是闲得蛋疼。

flutter本来没有跨环境通信的问题,结果又弄了一个js引擎进来搞出了进程通信问题,造成性能下降,还把包体积增加了很大,还不如直接用rn/weex/uni-app。

除了flutter,rn/weex/uni-app都可以动态热更新。

跨平台排版引擎和跨平台应用开发引擎的区别

有些人说他们的App用rn/weex、flutter。但是具体用它们做了什么呢?

是整个App用了它们,还是某个页面用了它们?

一个页面跨平台,和一个应用跨平台,是完全不同的2个概念。

webview、rn/weex、flutter全部是渲染引擎,webview因为HTML5的发展,还算是多了一些能力比如位置服务、多媒体等。而rn/weex、flutter真的只是一个纯粹的排版引擎,没有任何原生能力。

如果一个原生应用里,某个不涉及原生能力的界面想跨平台,那么这几个引擎都可以,并且flutter的性能最高。所以能看到一些公司尝试把App中的个别原生交互较少页面使用flutter实现。

但如果一个完整的应用,想用跨平台工具开发,那就不是排版引擎的范畴了,它需要应用开发引擎。

什么是跨平台应用开发引擎?不但排版部分要跨平台,开发API也要跨平台。

应用开发离不开os或三方sdk的能力调用,如果是单纯的排版引擎,一旦涉及os能力和sdk调用,就必须iOS、Android的工程师配合,编写不同的原生代码整合在一起。这就不跨平台了。

Airbnb曾是React Native 框架的倡导者和开发者代表。但他们于2019年正式发公告,弃用了react native。

原因是什么?

很简单,react native并不能提升Airbnb的开发效率,反而降低了他们的效率。

“本来我们可以只维护Android和iOS两套代码,但现在我们要维护三套(指多了一套react native的js代码),这让我们很疲惫” -- aribnb

开发者选用跨平台开发引擎,本来是为了提高效率、降低成本。Airbnb正是在实践了几年后,发现rn根本无法实现他选用跨平台引擎的初衷时,无奈放弃了rn,用原生开发重写。

要想真的提升开发效率,降低开发成本,那么跨平台开发引擎,需要提供一个完整的应用开发平台,包含所有常用的应用开发能力的跨平台。在不常用的部分,提供插件市场以及免原生介入的插件使用方式。

在react native、flutter的社区,也有不少三方提供的原生插件,但是连Airbnb这样的国外开发者对此都不满意。更何况对于很多中国开发者常用的场景,其对应的插件的质量、跨端性都难以商用。

更麻烦的是如果你不会原生开发,就没法把这些插件与你的前端代码集成起来。

uni-app,它的设计目标不是跨平台排版引擎,而是跨平台应用开发引擎。

所以uni-app的排版部分,可以选择小程序强化webview引擎和weex引擎,可根据自己的需求切换。而能力层面,uni-app提供了htmlplus API、Native.js、插件市场,解决了原生能力js化的问题。

uni-app让开发者真的不用懂原生开发就能做出完整的跨平台应用。遇到极个别的需求,开发者也可以去插件市场找人订做一个原生插件,自己仍然使用js来集成,仍然可以云端直接打包。

技术学习成本和难度

rn,要求开发者学习react,要求精通flex布局,要求原生开发协作。

flutter,要求开发者学习dart,了解dart和flutter的API、要求精通flex布局,要求原生开发协作。

weex已经内嵌到uni-app中,就不单独提了。

uni-app,要求开发者学习vue,了解小程序。

很明显uni-app的学习成本太低了,它没有附加专有技术,全部使用公共技术。

学习成本和难度,直接意味着:开发成本、招聘成本、上线速度、上线风险。

另外,dart究竟值不值得学,是一个大问题。

Google的天才工程师也发明了go语言,它确实有很多理论优势,但实际上市场的主流,仍然是c和c++。

质量

这几种跨平台引擎,整体的质量水平是差不多的,都是可以商用,但是有各种小坑。

2020年7月6日的数据,各家的github的issues如下: 框架 issues
uni-app 557
react native 816
flutter 7840

代码量是flutter最多,对应它的issues的数量也越多。
对于uni-app和react native来讲,渲染层是基于相对成熟的原生渲染或webview渲染来做的,不像flutter一切都是自己实现。而逻辑层uni-app也使用相对成熟的v8和jscore,出问题的点相对要少。

各框架的更新都比较频繁,真的有影响商用的大问题,肯定都会及时修复。

目前各个框架都有较大的用户使用量,质量方面均是可控的。

生态

任何开发引擎,都离不开生态。

对于国内的开发者,有很多独特的开发sdk,中国开发者需要的全端推送(UniPush集成了iOS、华为、小米、OPPO等众多原厂推送)、各种国内微信、阿里、微博等各种登陆、支付、分享SDK、各种国内地图、各种ui库、以及Echart图表等,都是在uni-app体系里,这方面生态可比rn、flutter丰富多了。uni-app的插件市场有数千款插件,不能说应有尽有,但确实是最丰富的跨端开发框架生态了。

另外,uni-app的生态还比其他竞品强在如下方面:

  • App和H5提供了renderjs技术,使得浏览器专用的库也可以在App和H5里使用,比如echart、threejs等参考
  • 兼容微信小程序 JS SDK,丰富的小程序生态内容可直接引入uni-app,并且在App侧通用,参考
  • 兼容微信小程序自定义组件,并且App、H5侧通用,参考

这些丰富的生态兼容,是rn和flutter无法享受的。

更新:2020年11月google全球开发者大会公布的数据,flutter全球月活开发者50万,中国占11%,也就是5.5万。这数字太小了,撑不起好生态。DCloud的开发者月活100万+,生态更繁荣。

其他端的跨端性

flutter和rn,都是支持web技术的。但都是仅限于普通界面排版,涉及定位、摄像头、相册什么的,是要单独写代码的。

另外flutter的H5版,嗯,作为中国开发者,你不会想要一个如此浓郁的Material风格的H5版的。。。

更何况这个Material ui库大的很,编译出来的H5版要十几M的体积。

uni-app的web端是包含非常完善的。

  1. 丰富能力都可以直接跨端使用,风格也是跨端风格。
  2. uni-app的web引擎体积只有1百K,gzip后只剩下30k(不含vue、vue-router),比其他工具的引擎体积要小的多。
  3. uni-app的web端是现今为数不多的、好用的响应式框架。bootstrap已经不行了。
  4. uni-app的web端支持ssr服务端渲染
    上面这些优势,都是flutter的web版不具备的。当然react的web版也可以实现这些,它的web代码和react native的代码重用度很低。

另外,中国离不开小程序,rn、flutter官方都不会支持小程序,由于架构差异太大,国内三方也做不到把rn代码良好的编译为小程序代码。uni-app则可以一套代码,同时编译为iOS、Android、Web、微信小程序、支付宝小程序、百度小程序、头条小程序、QQ小程序、京东小程序、快手小程序。

结论

每种技术的诞生,有其背后公司的目的。

但凡没有明确公司战略的技术,除非是特别简单的技术,否则很难商用,因为为了商用要投入公司非常多资源。

flutter诞生的目的,是为了Fuchsia OS,是为了在下一个互联网大潮,即万物互联的物联网年代,提供一个类似Android在移动互联网位置的垄断性操作系统。

因为Google已经很明确不会在下一个时代使用Android+java的路线了。

至于在Android上去java化,那是Kotlin的使命,与flutter无关。

跨iOS和Android平台开发,这不是Google的战略目标。

但万物互联何时到来?Fuchsia OS何时流行?这在现实中是一个问号,在Google内部,也只是战略储备项目。

一个语言的流行,不是一件简单的事情,不是有优点,就会流行,它需要天时地利人和。

6年前我们就知道dart比js更好,dart不应该消亡,但想成为主流技术,太难太难了。

同样我们也知道go比c++更好,但go还是起不来。

想靠flutter驱动dart流行是不现实的,甚至是反过来的。跨iOS、Android开发在国外不是主流市场,这点价值造就不出一个这么难建的生态。

所以dart能否流行,是要打一个大大的问号的,它可能会像go语言一样,叫好不叫座。

一个跨平台公司,应当是中立的。而flutter在这个位置上很尴尬,它是google出品的、同时跨iOS和Android的开发引擎。

如果这个引擎做大了,Apple会怎么看?那可不是像微信搞个小程序那么简单了,微信是中立三方,且只在中国。Apple不会让google的flutter在iOS上做大的。
本来Apple有政策,iOS的webview只能用Apple的UIWebview和WKwebview,js引擎只能用Apple的jscore,就是为了限制chrome和v8进入iOS生态。但google钻了个政策漏洞,在iOS上提供了dart引擎和Skia渲染引擎,这不算违反之前的Apple政策,但未来flutter真的做大的话,Apple高概率会更新政策,补上这个漏洞。

至于react native和uni-app,因为在iOS上使用了iOS自带的原生渲染和iOS的jscore,严格符合Apple政策,更加安全。

目前,flutter在国内一些大厂的原生App里得到了局部应用。这个应用场景,目的不是为了节省成本,flutter开发成本很高,生态也不完善,但因为性能高,一些大公司愿意负担这个代价来使用flutter,在原生app里部分页面使用flutter制作。但是这个场景,有个尴尬,就是flutter页面无法动态更新,但很多大app对动态发版的需求极强,有些厂商改造了flutter使其可动态发布,但又降低了flutter的性能。目前还没有一个完美的解决方案。

写了这么多,最后总结下flutter与uni-app的比较:

  • flutter与uni-app的相对优势:
    • 性能好一些。比rn有优势,但比拥有bindingx和wxs的uni-app,在实际开发中没有很明显的差距。
  • flutter与uni-app的相对劣势:
    • 需要原生协作,维护3套代码,无法有效降低开发成本,提升开发效率
    • 嵌套地狱,代码难看难维护
    • 不支持热更新
    • 目前质量和成熟度很低
    • 原生可视控件融合不好,比如webview、video、map
    • ui库不适合国情
    • 学习成本高
    • 应用场景有限,dart未来扑朔迷离

更新:uni-app里其实也可以使用flutter,有插件作者提供了插件,使得uni-app的应用在某些页面可以打开flutter页面,详见

再总结下rn和uni-app的比较

  • rn与uni-app的相对优势:
    • rn的坑虽然比weex的少,但uni-app已经填了weex的很多坑。这方面差别不大。
    • rn的生态虽然比weex丰富。但uni-app是反过来的,uni-app的国内应用生态丰富度超过了rn。
    • rn是纯单页的,嵌入原生App比较灵活。而uni-app是应用整体的概念,如果要内嵌入其他原生应用的话,要求原生应用内嵌uni-app应用整体进来。即集成uni小程序sdk
  • rn与uni-app的相对劣势:
    • 需要原生协作,维护3套代码,无法有效降低开发成本,提升开发效率
    • 不支持小程序,发布到h5也无法直接发
    • 性能不如uni-app
    • 国内的插件生态不如uni-app丰富
    • ui库不适合国情,learn once,write anywhere
    • 学习成本高,用人成本高,不利于开发商降低开发成本
    • rn是纯单页应用,如果一个应用的页面很多,用rn写会很崩溃,变量污染和干扰严重。而weex/uni-app支持多页面,页面之间上下文隔离,写页面较多的大型应用更合适
      另外react在中国的市场占有率远不如vue。这也是中国与国外不同的特色情况。

贴个vue、react、react native的百度指数对比,无论总体量的差距,还是发展趋势的下滑程度,可以明显看出react系在中国确实不行了。

中国的开发者,过去总会想:

  1. 小程序那套webview优化的技术,我能不能用到我的App里?现在uni-app已经为你解决了这个问题。
  2. weex能不能坑少点,API和插件多点?现在uni-app已经为你解决了这个问题。

如果你是一个资源充沛的大公司,原生App中部分不要求动态更新、也没有太多原生交互的页面,可以尝试使用flutter实现。但如果大范围使用,你也会遇到和aribnb一样的问题,维护3套代码还不如维护2套代码。

如果你开发uni-app选用了原生渲染,那App的性能足够好,且你得到了切实的开发效率的提升、成本的下降、快速和低风险的上线。

选择跨平台工具而不是原生开发,本质目的不就是为了成本和效率吗?在跨平台开发里能真正解决你本质需求的,就是uni-app。

当然,uni-app的app引擎并没有吊炸天。App平台,所有跨平台工具都还比不过原生,这是客观事实。只是,如果uni-app不能满足你的需求,你没有必要去用其他跨平台工具,直接上原生吧。

更新:近3年来,uni-app、react native、flutter都在持续发展。但从用户体量、社区规模对比,uni-app增长迅猛,而其他家表现平平。

收起阅读 »

力谱云解析-如何盘活水果店?拉新、裂变、复购全周期App运营攻略

移动APP

消费升级浪潮下,蛋糕一直在升级,但线下市场的寒冬仍在继续。那么,坚持口碑与品质的传统水果店,该如何依靠移动互联网盘活?基于移动互联网+社交裂变+电商APP,目前最可行的方案是开发一款属于自己的社交电商APP,进行线上销售。那么开发APP,如何进行有效运营?力谱云为您梳理并提供一站式拉新、裂变、复购全程APP营销攻略。

力谱云解析-如何盘活水果店?拉新、裂变、复购全周期App运营攻略

拉新 – 触达用户只是第一步

传统水果店主,普遍依靠店铺所在的社区口碑,进行每一个用户的触达,往往存在着促销活动难以及时触达用户的难点。因此,也有不少店主会通过加微信账号,建立社群,或广发朋友圈信息,进行促销活动的扩散,但总体存在刷屏过猛,涉嫌恶意骚扰,乃至被屏蔽的营销短处。

而小程序+微信公众号这一对拉新小能手,则完全不在怕的。首先,小程序随用随走的轻量级运营方式,非常适合进行初期的用户拉新。水果店可以设置奖励制度,鼓励到店用户,关注微信公众号,在菜单页面的小程序中进行下单,即送XX水果、或领取无门槛红包等方式,让用户果断关注下单。这样,运营者即可通过日常定期的营销活动推送,优质的水果鉴别干货文等,在公众号中即可进行用户营销。

如果店主已拥有广大的会员基础,而苦于运营、管理成本难题,则可采用重量级的运营武器——开发App,来进行深度用户运营。可通过力谱云的会员等级、积分、签到领红包、售后、客服等各个方面,深度优化用户消费体验,为后续复购提供粉丝基础。而这些运营功能,都是小程序与微信公众号,所无法给予的。目前,力谱云支持App+小程序+微商城+移动网站的一站式开发服务,让企业主用更少的技术投入资金,覆盖更广阔的移动蓝海渠道。

社交裂变 – 以老带新,深挖老用户价值

在传统水果市场中,依靠口碑与品质,固然能让老用户带来新用户,但是效果却不大。原因有二,一无利益基础,二无便利的消费平台,因此很难激励老用户吸引新用户进行消费,更难于变现。而社交裂变+App的强强联手,则一举改变了这一难题,在其中,目前最给力的获客变现模式,则非分销与拼团莫属。

1 分销 – 运营者可通过力谱云强大的运营管理后台,制定分销奖励制度,如新人下载App,老用户可得XX积分;新人消费,老用户获X%奖励金等策略,鼓励老用户转发商品链接,并分享给自己的微信/QQ好友,实现以老带新的裂变营销模式。

2 拼团 – 通过9.9元/西瓜等赚人眼球的大促活动,鼓励用户拉人进行拼购,这一模式受熟人关系影响,成团率更高,变现率也高。在618、双11等营销活动中,已成为目前最主流的裂变营销方式。目前,力谱云潜心研发APP营销模式,不仅支持拼购营销,也推出了一站式的社区团购方式,助力企业用最前沿的营销模式,不断开拓移动市场。

复购 – 定期营销,唤醒用户消费

复购,往往指用户对品牌或者服务的重复购买次数,复购率越高,则用户的忠诚度越高。随着获客成本的逐年激增,除了不放过每一个拉新机会,更多的企业也在试图,建立有效的用户唤醒机制,刺激老用户购买欲。

1 会员制建立 – 复购在于深挖老用户价值,若无会员体系,则一切化为空谈。首先,可通过力谱云APP开发平台的“会员”模式,借助会员积分、会员等级购买体系,打下复购基础;其次,可通过预付卡、购物卡等方式,鼓励用户充值XXX元增XXX元等模式,提升用户复购率。

2 营销活动推送 – 定期策划营销活动,并通过微信账号、社群、公众号、App进行活动推送,通过力谱云平台的秒杀、满减优惠、代金券、优惠套装等数十种营销工具,按活动/产品等需求,进行策略的变换制定,不断提升用户购物兴趣。

力谱云全周期运营:研发、运营、营销全hold

力谱云作为一款专业为电商企业主,提供集研发、运营、营销为一体的移动电商平台,一直致力于研发上,借力“SaaS+PaaS”的云计算模式,降低研发门槛,提升研发效率,为企业提供颠覆式的高性价比云开发服务。在运营及营销层面,则不断在大量市场验证、及具体企业实战案例的探索过程中,通过不断优化并迭代拉新、变现等运营&营销工具,帮助企业平台更富营销力、运营力。如果您的企业,正在尝试云集分销、拼多多拼购、生鲜配送、B2B裂变新渠道等多种前沿模式,选择力谱云,全周期助您轻松运营到底!

继续阅读 »

消费升级浪潮下,蛋糕一直在升级,但线下市场的寒冬仍在继续。那么,坚持口碑与品质的传统水果店,该如何依靠移动互联网盘活?基于移动互联网+社交裂变+电商APP,目前最可行的方案是开发一款属于自己的社交电商APP,进行线上销售。那么开发APP,如何进行有效运营?力谱云为您梳理并提供一站式拉新、裂变、复购全程APP营销攻略。

力谱云解析-如何盘活水果店?拉新、裂变、复购全周期App运营攻略

拉新 – 触达用户只是第一步

传统水果店主,普遍依靠店铺所在的社区口碑,进行每一个用户的触达,往往存在着促销活动难以及时触达用户的难点。因此,也有不少店主会通过加微信账号,建立社群,或广发朋友圈信息,进行促销活动的扩散,但总体存在刷屏过猛,涉嫌恶意骚扰,乃至被屏蔽的营销短处。

而小程序+微信公众号这一对拉新小能手,则完全不在怕的。首先,小程序随用随走的轻量级运营方式,非常适合进行初期的用户拉新。水果店可以设置奖励制度,鼓励到店用户,关注微信公众号,在菜单页面的小程序中进行下单,即送XX水果、或领取无门槛红包等方式,让用户果断关注下单。这样,运营者即可通过日常定期的营销活动推送,优质的水果鉴别干货文等,在公众号中即可进行用户营销。

如果店主已拥有广大的会员基础,而苦于运营、管理成本难题,则可采用重量级的运营武器——开发App,来进行深度用户运营。可通过力谱云的会员等级、积分、签到领红包、售后、客服等各个方面,深度优化用户消费体验,为后续复购提供粉丝基础。而这些运营功能,都是小程序与微信公众号,所无法给予的。目前,力谱云支持App+小程序+微商城+移动网站的一站式开发服务,让企业主用更少的技术投入资金,覆盖更广阔的移动蓝海渠道。

社交裂变 – 以老带新,深挖老用户价值

在传统水果市场中,依靠口碑与品质,固然能让老用户带来新用户,但是效果却不大。原因有二,一无利益基础,二无便利的消费平台,因此很难激励老用户吸引新用户进行消费,更难于变现。而社交裂变+App的强强联手,则一举改变了这一难题,在其中,目前最给力的获客变现模式,则非分销与拼团莫属。

1 分销 – 运营者可通过力谱云强大的运营管理后台,制定分销奖励制度,如新人下载App,老用户可得XX积分;新人消费,老用户获X%奖励金等策略,鼓励老用户转发商品链接,并分享给自己的微信/QQ好友,实现以老带新的裂变营销模式。

2 拼团 – 通过9.9元/西瓜等赚人眼球的大促活动,鼓励用户拉人进行拼购,这一模式受熟人关系影响,成团率更高,变现率也高。在618、双11等营销活动中,已成为目前最主流的裂变营销方式。目前,力谱云潜心研发APP营销模式,不仅支持拼购营销,也推出了一站式的社区团购方式,助力企业用最前沿的营销模式,不断开拓移动市场。

复购 – 定期营销,唤醒用户消费

复购,往往指用户对品牌或者服务的重复购买次数,复购率越高,则用户的忠诚度越高。随着获客成本的逐年激增,除了不放过每一个拉新机会,更多的企业也在试图,建立有效的用户唤醒机制,刺激老用户购买欲。

1 会员制建立 – 复购在于深挖老用户价值,若无会员体系,则一切化为空谈。首先,可通过力谱云APP开发平台的“会员”模式,借助会员积分、会员等级购买体系,打下复购基础;其次,可通过预付卡、购物卡等方式,鼓励用户充值XXX元增XXX元等模式,提升用户复购率。

2 营销活动推送 – 定期策划营销活动,并通过微信账号、社群、公众号、App进行活动推送,通过力谱云平台的秒杀、满减优惠、代金券、优惠套装等数十种营销工具,按活动/产品等需求,进行策略的变换制定,不断提升用户购物兴趣。

力谱云全周期运营:研发、运营、营销全hold

力谱云作为一款专业为电商企业主,提供集研发、运营、营销为一体的移动电商平台,一直致力于研发上,借力“SaaS+PaaS”的云计算模式,降低研发门槛,提升研发效率,为企业提供颠覆式的高性价比云开发服务。在运营及营销层面,则不断在大量市场验证、及具体企业实战案例的探索过程中,通过不断优化并迭代拉新、变现等运营&营销工具,帮助企业平台更富营销力、运营力。如果您的企业,正在尝试云集分销、拼多多拼购、生鲜配送、B2B裂变新渠道等多种前沿模式,选择力谱云,全周期助您轻松运营到底!

收起阅读 »

力谱云V3.6新发布,BBC&信息流全新升级

移动APP

力谱云V3.6新上线啦!致力于APP开发的力谱云平台,以当前市场火爆的营销策略和客户的个性化需求为方针,奠定正确的APP开发基调,不断更新优化,更加符合客户的需求。在本期更新的APP开发版本中,力谱云新增了BBC商品分析报表、BBC多级区域代理商、BBC店铺商品审核规则、提现验证、信息流、BC积分商品设置等共计15项功能,另有其他细节调整。

APP开发功能更新:力谱云V3.6新发布,BBC&amp;信息流全新升级

BBC商品分析报表

功能描述:新增BBC商品分析报表,平台方可根据店铺筛选,查看每个店铺的数据

操作:查看“数据分析”→“商品数据分析”→“BBC 商品数据分析”

力谱云|平台方BBC商品数据分析

力谱云|店铺方商品数据分析

BBC 多级区域代理商

功能描述:BBC多级区域代理,根据店铺地址来计算代理收益;即按店铺地址所在区域,判定收益归属

力谱云|BBC 多级区域代理商操作

操作:

商品管理→编辑商品信息→参与区域代理→设置代理收益基数
区域代理管理→代理商管理→添加并编辑代理商信息
移动端:

力谱云|BBC多级区域代理商界面

BBC商品审核

功能描述:BBC支持设置店铺上传商品审核规则,审核通过后才能在平台上显示

操作:

B2B2C管理→审核规则设置→全部自动审核/全部人工审核/部分自动审核

B2B2C管理→B2B2C商品管理→查看【店铺待审核商品列表】→通过/驳回,填写理由

提现验证

功能描述:会员、接单端、店铺提现,需输入对应账号的手机验证码

操作:财务管理→应收账款→提现→编辑提现申请信息,获取验证码→申请提现

注意:App用户需下载新版本,才能进行提现。

店铺时间设置

功能描述:店铺可以设置营业时间,自动开关店铺

操作:店铺管理→店铺信息管理→店铺营业设置→强制关闭店铺/设置营业时间

等级制团队分销

功能描述:等级制团队分销中,团队奖获得者的间接上级可获得培训奖

操作:等级制团队分销→等级制团队分销设置→简化版算法配置→设置→允许【间接上级获得培训奖】

供应链-订单信息隐藏

功能描述:供应链模式下,店铺方订单中,可隐藏收货人的地址和联系方式

代金券

功能描述:新增批量发放代金券

操作:代金券管理→B2C代金券管理→批量发放代金券→导入要发放的代金券

BC积分商品设置

功能描述:B2C商城支持设置积分商品

操作:B2C 商品管理→B2C商品管理→编辑商品信息→勾选积分商品,设置积分BC积分商品设置

移动端:

BBC店铺排序优化

功能描述:BBC 店铺列表管理,优化排序功能。点击【置顶排序】按钮,可编辑排序数字,为空的不参与排序,大于等于0可参与排序

注意:休息中的店铺也参与排序

操作:B2B2C店铺管理→B2B2C店铺列表管理→编辑置顶排序

积分、余额报表

功能描述:【积分明细记录】菜单变更为【积分统计报表】、【余额统计报表】。两个报表均可导出,报表主要展示会员的积分、余额变更前后的记录列表

信息流体验提升

功能描述:

图片和视频,进入详情页面,均支持直接滑动进入下一条。进入的该条为第一条,可不停下滑,展示的内容是列表中的下一条
支持录制 60s 视频
发帖内容详情显示已输入/可输入字数,可输入字数扩展到 1000
主题下的下一条全是该主题下的,关注下的下一条全是该关注下的
图片帖下滑,仅展示图片,视频帖下滑,下面仅展示视频
视频播放完成之后,增加重新播放按钮显示在屏幕正中央
用户可删除自己发的帖子;可展开全部评论后进行评论,也可直接参与评论
信息流新增店铺定位,可直接跳转地图导航;新增【商品】,可直接跳转商品页面
信息流标题与文案展示优化,点击【展开】,即可上下滑动查看整体文案
移动端:

收货地址优化

功能描述:收获地址优化,支持新样式,类似京东

固定省市模式:所有的三级联动形式都是新版省市区的选择样式

涉及页面:商品详情页的地址选择、收货地址编辑页面、快速注册页面

移动端:

返利设置菜单调整

功能描述:商品返利设置、收银台返利设置,转移至新⻚面——会员返利设置

BC管家婆

功能描述:BC管家婆,支持批量同步商品库存和商品订单功能

继续阅读 »

力谱云V3.6新上线啦!致力于APP开发的力谱云平台,以当前市场火爆的营销策略和客户的个性化需求为方针,奠定正确的APP开发基调,不断更新优化,更加符合客户的需求。在本期更新的APP开发版本中,力谱云新增了BBC商品分析报表、BBC多级区域代理商、BBC店铺商品审核规则、提现验证、信息流、BC积分商品设置等共计15项功能,另有其他细节调整。

APP开发功能更新:力谱云V3.6新发布,BBC&amp;信息流全新升级

BBC商品分析报表

功能描述:新增BBC商品分析报表,平台方可根据店铺筛选,查看每个店铺的数据

操作:查看“数据分析”→“商品数据分析”→“BBC 商品数据分析”

力谱云|平台方BBC商品数据分析

力谱云|店铺方商品数据分析

BBC 多级区域代理商

功能描述:BBC多级区域代理,根据店铺地址来计算代理收益;即按店铺地址所在区域,判定收益归属

力谱云|BBC 多级区域代理商操作

操作:

商品管理→编辑商品信息→参与区域代理→设置代理收益基数
区域代理管理→代理商管理→添加并编辑代理商信息
移动端:

力谱云|BBC多级区域代理商界面

BBC商品审核

功能描述:BBC支持设置店铺上传商品审核规则,审核通过后才能在平台上显示

操作:

B2B2C管理→审核规则设置→全部自动审核/全部人工审核/部分自动审核

B2B2C管理→B2B2C商品管理→查看【店铺待审核商品列表】→通过/驳回,填写理由

提现验证

功能描述:会员、接单端、店铺提现,需输入对应账号的手机验证码

操作:财务管理→应收账款→提现→编辑提现申请信息,获取验证码→申请提现

注意:App用户需下载新版本,才能进行提现。

店铺时间设置

功能描述:店铺可以设置营业时间,自动开关店铺

操作:店铺管理→店铺信息管理→店铺营业设置→强制关闭店铺/设置营业时间

等级制团队分销

功能描述:等级制团队分销中,团队奖获得者的间接上级可获得培训奖

操作:等级制团队分销→等级制团队分销设置→简化版算法配置→设置→允许【间接上级获得培训奖】

供应链-订单信息隐藏

功能描述:供应链模式下,店铺方订单中,可隐藏收货人的地址和联系方式

代金券

功能描述:新增批量发放代金券

操作:代金券管理→B2C代金券管理→批量发放代金券→导入要发放的代金券

BC积分商品设置

功能描述:B2C商城支持设置积分商品

操作:B2C 商品管理→B2C商品管理→编辑商品信息→勾选积分商品,设置积分BC积分商品设置

移动端:

BBC店铺排序优化

功能描述:BBC 店铺列表管理,优化排序功能。点击【置顶排序】按钮,可编辑排序数字,为空的不参与排序,大于等于0可参与排序

注意:休息中的店铺也参与排序

操作:B2B2C店铺管理→B2B2C店铺列表管理→编辑置顶排序

积分、余额报表

功能描述:【积分明细记录】菜单变更为【积分统计报表】、【余额统计报表】。两个报表均可导出,报表主要展示会员的积分、余额变更前后的记录列表

信息流体验提升

功能描述:

图片和视频,进入详情页面,均支持直接滑动进入下一条。进入的该条为第一条,可不停下滑,展示的内容是列表中的下一条
支持录制 60s 视频
发帖内容详情显示已输入/可输入字数,可输入字数扩展到 1000
主题下的下一条全是该主题下的,关注下的下一条全是该关注下的
图片帖下滑,仅展示图片,视频帖下滑,下面仅展示视频
视频播放完成之后,增加重新播放按钮显示在屏幕正中央
用户可删除自己发的帖子;可展开全部评论后进行评论,也可直接参与评论
信息流新增店铺定位,可直接跳转地图导航;新增【商品】,可直接跳转商品页面
信息流标题与文案展示优化,点击【展开】,即可上下滑动查看整体文案
移动端:

收货地址优化

功能描述:收获地址优化,支持新样式,类似京东

固定省市模式:所有的三级联动形式都是新版省市区的选择样式

涉及页面:商品详情页的地址选择、收货地址编辑页面、快速注册页面

移动端:

返利设置菜单调整

功能描述:商品返利设置、收银台返利设置,转移至新⻚面——会员返利设置

BC管家婆

功能描述:BC管家婆,支持批量同步商品库存和商品订单功能

收起阅读 »

UNIAPP电影视频类项目发布,这框架确实不错

HTML5+ 技术分享 PHP uniapp 源码分享

手机端:

PHP后台:

码云:

APP端地址:https://gitee.com/lim2018/dianyb
后台地址:https://gitee.com/lim2018/dianyb-admin

继续阅读 »

手机端:

PHP后台:

码云:

APP端地址:https://gitee.com/lim2018/dianyb
后台地址:https://gitee.com/lim2018/dianyb-admin

收起阅读 »

uni-app开发的应用,使用于微信端下的使用总结,分享等功能,注意要点

微信兼容 uniapp 微信分享

一开始被uni-app开发微信H5的wx问题困扰了,主要原因是不太理解uni-app的机制,后来不断摸索,尝试,也逐渐理解了当中的细节和原委,在这里和大家分享出来

概念,H5页面中
jssdk 为<script src="//res.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
unisdk 为<script src="//js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.1.5.1.js"></script>

注意要点

1.H5页面引入unisdk的作用是为了h5页面中用统一的uni对象和其它uniapp的vue页面相互沟通,直接跳转页面,传递参数等

2.如果uniapp发布的目标是微信mp,想用webview打开一个H5页面(可以判断浏览器是mp or 公众号 or app),html中的wx对象即为H5页面中引入的jssdk的wx对象,和微信公众号网页开发无区别

3.如果uniapp发布的目标是微信公众号H5, 虽然你在整个项目主页面的index.html中引入了jssdk,然而当你想在 uni的vue页面中使用wx对象,如home.vue的调用 wx.config(), 或者在index.html页面中调用wx.config() ,都会得到报错,因为wx对象是uni定义的另一个全局对象,而不是你期待的jssdk的wx对象,若确实使用jssdk的wx对象(在微信公众号or微信MP的webview中呈现整个项目),就需要jweixin-module,如果H5是使用hash路由方式,那么只用wx.config一次即可,使用的例子
var jswx = require('jweixin-module/index.js')
jswx.ready()
jswx.config(...)
jswx.getLocation 使用即可

我通常这么做:
主项目main.js中
Vue.prototype.$wx = wx //uni的全局对象
isInWXWebview = window && window.navigator.userAgent.indexOf('MicroMessenger') > 0
if(isInWXWebview){ //在微信中,且为webview打开主项目
var jswx = require('jweixin-module/index.js')
jswx.ready()
jswx.config(...)
Vue.prototype.$wx = jswx //切换为微信jssdk对象
}
然后,在uni的vue页面中,this.$wx.getLocation 就可以用了

4.在微信开发者工具打开uniapp的mp,然后打开webview页面,在H5里面的console.log信息是不会打印出来的,得用公众号网页调试的方式来打开来查看

5.uniapp的webview发布为微信mp,运行时为webview,发布为H5,运行时为iframe,需要注意wx.config中的真正路径

6.微信公众号网页的分享是不能通过页面内的按钮触发的,只能提示右上角分享,同理,在mp的webview打开的网页中也是如此,可以提示用户微信mp右上角分享按钮触发分享;但是mp原生页面支持button触发分享,也就是uni的vue页面支持点击触发,所以可以这样变通处理:webview中的按钮点击后,navigateTo(mp原生页面),在mp原生页面中button再触发分享,用这种方式你连网页中都不需要jssdk了, 而jssdk直接支持的方法就不需要这样了,wx.config成功后直接调用即可,如wx.getLocation

总结,你写在主页面index.html页面中的wx对象有可能不是jssdk的对象(当项目发布为H5时),而写在vue文件中的wx对象是uni的,用webview打开的页面html中的wx肯定是jssdk的

继续阅读 »

一开始被uni-app开发微信H5的wx问题困扰了,主要原因是不太理解uni-app的机制,后来不断摸索,尝试,也逐渐理解了当中的细节和原委,在这里和大家分享出来

概念,H5页面中
jssdk 为<script src="//res.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
unisdk 为<script src="//js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.1.5.1.js"></script>

注意要点

1.H5页面引入unisdk的作用是为了h5页面中用统一的uni对象和其它uniapp的vue页面相互沟通,直接跳转页面,传递参数等

2.如果uniapp发布的目标是微信mp,想用webview打开一个H5页面(可以判断浏览器是mp or 公众号 or app),html中的wx对象即为H5页面中引入的jssdk的wx对象,和微信公众号网页开发无区别

3.如果uniapp发布的目标是微信公众号H5, 虽然你在整个项目主页面的index.html中引入了jssdk,然而当你想在 uni的vue页面中使用wx对象,如home.vue的调用 wx.config(), 或者在index.html页面中调用wx.config() ,都会得到报错,因为wx对象是uni定义的另一个全局对象,而不是你期待的jssdk的wx对象,若确实使用jssdk的wx对象(在微信公众号or微信MP的webview中呈现整个项目),就需要jweixin-module,如果H5是使用hash路由方式,那么只用wx.config一次即可,使用的例子
var jswx = require('jweixin-module/index.js')
jswx.ready()
jswx.config(...)
jswx.getLocation 使用即可

我通常这么做:
主项目main.js中
Vue.prototype.$wx = wx //uni的全局对象
isInWXWebview = window && window.navigator.userAgent.indexOf('MicroMessenger') > 0
if(isInWXWebview){ //在微信中,且为webview打开主项目
var jswx = require('jweixin-module/index.js')
jswx.ready()
jswx.config(...)
Vue.prototype.$wx = jswx //切换为微信jssdk对象
}
然后,在uni的vue页面中,this.$wx.getLocation 就可以用了

4.在微信开发者工具打开uniapp的mp,然后打开webview页面,在H5里面的console.log信息是不会打印出来的,得用公众号网页调试的方式来打开来查看

5.uniapp的webview发布为微信mp,运行时为webview,发布为H5,运行时为iframe,需要注意wx.config中的真正路径

6.微信公众号网页的分享是不能通过页面内的按钮触发的,只能提示右上角分享,同理,在mp的webview打开的网页中也是如此,可以提示用户微信mp右上角分享按钮触发分享;但是mp原生页面支持button触发分享,也就是uni的vue页面支持点击触发,所以可以这样变通处理:webview中的按钮点击后,navigateTo(mp原生页面),在mp原生页面中button再触发分享,用这种方式你连网页中都不需要jssdk了, 而jssdk直接支持的方法就不需要这样了,wx.config成功后直接调用即可,如wx.getLocation

总结,你写在主页面index.html页面中的wx对象有可能不是jssdk的对象(当项目发布为H5时),而写在vue文件中的wx对象是uni的,用webview打开的页面html中的wx肯定是jssdk的

收起阅读 »

【实战教程】uni-app商城类项目实战视频教程

教程 uniapp 视频教程 uniapp 教程

课程概述

本季度预计220课时,每周三和周六更新,每次更新10课时。

本季度为uni-app实战项目第2季度,将实战开发仿商城类app,其中会包括发布到安卓端app,IOS端app、微信小程序,H5等,另外还会涉及Weex(nvue),Vuex模块化管理,商城支付模块等。

课程学习链接入口:

uni-app实战商城类app和小程序开发视频教程

https://study.163.com/course/courseMain.htm?courseId=1209401825&share=2&shareId=480000001892585

或者进入网易云课堂,搜索uni-app即可看到

课程大纲见以下图!





课程学习链接入口:

uni-app实战商城类app和小程序开发视频教程

https://study.163.com/course/courseMain.htm?courseId=1209401825&share=2&shareId=480000001892585

或者进入网易云课堂,搜索uni-app即可看到

课程目录:(实际参考uni-app实战商城类app和小程序开发视频教程

继续阅读 »

课程概述

本季度预计220课时,每周三和周六更新,每次更新10课时。

本季度为uni-app实战项目第2季度,将实战开发仿商城类app,其中会包括发布到安卓端app,IOS端app、微信小程序,H5等,另外还会涉及Weex(nvue),Vuex模块化管理,商城支付模块等。

课程学习链接入口:

uni-app实战商城类app和小程序开发视频教程

https://study.163.com/course/courseMain.htm?courseId=1209401825&share=2&shareId=480000001892585

或者进入网易云课堂,搜索uni-app即可看到

课程大纲见以下图!





课程学习链接入口:

uni-app实战商城类app和小程序开发视频教程

https://study.163.com/course/courseMain.htm?courseId=1209401825&share=2&shareId=480000001892585

或者进入网易云课堂,搜索uni-app即可看到

课程目录:(实际参考uni-app实战商城类app和小程序开发视频教程

收起阅读 »

获取设备信息(imei、imsi、uuid)的调整使用plus.device.getInfo方法的说明

Device

本功能自HBuilderX 2.0.3+起支持

Android平台各大应用商店已经要求API等级(targetSdkVersion)为26或以上。高版本Android系统完善了授权系统,获取设备信息(如imei)需要经过用户授权确认,弹出获取设备信息的授权提示框:

如果不在manifest里指定,HBuilder的打包默认targetSdkVersion是21,而HBuilderX已经是26了。targetSdkVersion变高就会引发动态权限问题。

目前5+ API获取设备信息是通过以下属性方式读取

为了保证以上属性可用,应用需在启动时进行初始化赋值,原生层这时候就需要申请获取设备信息权限读取imei、imsi等信息。
即使应用没有调用以上API,应用启动时仍然执行此初始化赋值逻辑,导致应用启动时弹出上图所示的设备信息授权提示框。

为了避免应用启动时弹出设备信息授权提示框,新增plus.device.getInfo方法。当应用需要获取设备信息时调用此API,才会触发弹出授权提示框,不获取设备信息就不会弹出设备信息授权提示框。
建议使用5+ API的属性方式获取imei、imsi、uuid信息的代码调整使用plus.device.getInfo方法

至于属性和方法的区别,可能普通程序员看不懂,但做底层的会知道,属性就是启动时就必须初始化的。

原来的plus.device.imei、plus.device.imsi、plus.device.uuid等属性方式的API不推荐使用,后续会逐步废弃。
为了保证向下兼容,目前还可以使用,但不一定可以获取到正确的值。
取决于应用启动前是否已经获取设备信息权限:

  1. 如果应用启动前没有获取设备信息授权(询问或拒绝状态),则无法获取设备信息,按权限被拒绝的逻辑处理。
  2. 如果应用获取设备信息授权,则可以获取设备信息。

注意:调用plus.device.imei、plus.device.imsi、plus.device.uuid不会触发授权提示框

继续阅读 »

本功能自HBuilderX 2.0.3+起支持

Android平台各大应用商店已经要求API等级(targetSdkVersion)为26或以上。高版本Android系统完善了授权系统,获取设备信息(如imei)需要经过用户授权确认,弹出获取设备信息的授权提示框:

如果不在manifest里指定,HBuilder的打包默认targetSdkVersion是21,而HBuilderX已经是26了。targetSdkVersion变高就会引发动态权限问题。

目前5+ API获取设备信息是通过以下属性方式读取

为了保证以上属性可用,应用需在启动时进行初始化赋值,原生层这时候就需要申请获取设备信息权限读取imei、imsi等信息。
即使应用没有调用以上API,应用启动时仍然执行此初始化赋值逻辑,导致应用启动时弹出上图所示的设备信息授权提示框。

为了避免应用启动时弹出设备信息授权提示框,新增plus.device.getInfo方法。当应用需要获取设备信息时调用此API,才会触发弹出授权提示框,不获取设备信息就不会弹出设备信息授权提示框。
建议使用5+ API的属性方式获取imei、imsi、uuid信息的代码调整使用plus.device.getInfo方法

至于属性和方法的区别,可能普通程序员看不懂,但做底层的会知道,属性就是启动时就必须初始化的。

原来的plus.device.imei、plus.device.imsi、plus.device.uuid等属性方式的API不推荐使用,后续会逐步废弃。
为了保证向下兼容,目前还可以使用,但不一定可以获取到正确的值。
取决于应用启动前是否已经获取设备信息权限:

  1. 如果应用启动前没有获取设备信息授权(询问或拒绝状态),则无法获取设备信息,按权限被拒绝的逻辑处理。
  2. 如果应用获取设备信息授权,则可以获取设备信息。

注意:调用plus.device.imei、plus.device.imsi、plus.device.uuid不会触发授权提示框

收起阅读 »

nvue不同编译模式介绍

weex nvue uniapp

HBuilderX2.0.3 版本开始,nvue文件同时支持两种编译模式:

  • weex 模式:老模式,使用 weex组件,写法同weex标准写法。只能在 App 端中运行,部分 uni-app JS Api 不能使用。
  • uni-app 模式:新模式,默认模式,使用 uni-app 基础组件,组件、jsapi写法同uni-app。支持app.vue里的全局样式;支持nvue页面编译H5和小程序端;可以使用绝大部分 uni-app Api 。uni-app模式也可以使用weex里的组件,比如list、refresh、recircle-list。

为什么要提供2个模式?

weex模式的组件、渲染机制是weex官方维护的。它的渲染性能其实与react native是一样的,在性能体验方面足以应付一线互联网公司的苛求。但它有4个问题:

  1. 内置组件较少,或不完善。与小程序的组件相比,weex缺少太多内置组件,比如picker、map。而video等weex已内置的组件,也不够强大
  2. API缺失严重。因为weex只是个渲染器,它调用设备能力或push等三方sdk,都需要原生开发。
  3. 周边生态不完善。weex生态没有什么好的组件和模板。而uni-app的插件市场里众多优秀的组件和模板又无法用于nvue。
  4. nvue无法多端开发,只能用于app。开发者在多端需要维护多套代码。
  5. weex的排版思路和uni-app的vue差异有点多。比如weex不支持rpx。我们希望使用原生渲染,但尽可能多的兼容开发者的习惯。

weex的第二个问题,即能力问题,uni-app通过给nvue补充uni API和plus API,得到了解决。
但剩下的几个问题,需要uni-app的新编译模式才能解决。
我们要把小程序的所有组件,在weex的原生渲染机制上,重新实现一遍,让小程序的组件可以直接用原生来渲染。然后包括uni ui等扩展组件也都将兼容nvue。
现在插件市场的新闻模板,已经支持nvue新编译模式,它可以一套代码编译到App、小程序、H5全端。并且在App上是原生渲染的高性能体验。

之所以仍然存在weex模式,一是为了向下兼容,之前已经使用nvue的weex模式开发的app,不会因为HBuilderX的升级而导致页面错乱;二是为了方便weex的老用户迁移。

对于普通开发者,正常来讲应该选择uni-app编译模式。

注意nvue的uni-app编译模式,仍然是要求写nvue文件。

配置方式--uni-app编译模式或weex编译模式

manifest.json 的源码视图里配置是切换模式, manifest.json -> app-plus -> nvueCompiler 切换编译模式。

nvueCompiler 有两个值:

  • weex
  • uni-app
// manifest.json      
{      
    // ...      
     /* App平台特有配置 */      
    "app-plus": {      
        "nvueCompiler":"uni-app" //是否启用 uni-app 模式    
    }      
}     

差异说明

组件差异

在老的 weex 模式中,我们使用的是 weex组件 遵循的是 weex规范,如果使用 nvue 页面将不能跨端开发,仅能在 App 端运行。如果跨端那么意味着要实现vue 页面和 .nvue 页面两套代码。

代码示例

<template>  
    <div>  
        <text>测试页面</text>  
    </div>  
</template>  

而在 uni-app 模式中,我们将可以在 weex 组件的基础上使用 uni-app 的基础组件,目前已支持部分组件,并支持 .nvue 页面编译到 H5 和小程序端。

代码示例

<template>  
    <view>  
        <text>测试页面</text>  
    </view>  
</template>  

nvue的uni-app编译模式组件使用注意

组件的使用注意事项: 组件 注意事项
text 文字尽量写在text节点,非text节点的文字无法自动更新
rich-text nodes 属性只支持节点列表不支持 HTML String
web-view 必须指定高度,不支持页面通讯和网页内使用Plus API 。但在nvue里可以使用plus.webview.create来创建webview。这样的webview能力上更强大,但注意和原页面会有层级问题

默认页面滚动差异

weex 模式中,我们需要页面滚动,必须使用 <list> 组件或者 <scroller> 组件,这与我们开发小程序或者 web 的习惯并不符合。而在 uni-app 模式中,则可以像 vue 页面一样方便开发,不需要去声明额外的组件进行滚动,只要页面内容高度高于屏幕,就会自动滚动。实际上,在新模式里自动给每个nvue页面的根下套了一个scroller。

单位差异

weex的px是动态单位,并且不支持rpx。这与uni-app的设计不符。
在新模式中,rpx和px分别是动态单位和静态单位,与vue的设计一样。

Tips

注意事项

API 注意事项

.nvue 支持大部分 uni-app API详情

css 注意事项

.nvue 中,有些 css 样式需要注意,与 web 开发中样式写法会有区别。

1、只有text标签可以设置字体大小,字体颜色
2、布局不能使用百分比
3、只能使用 class 选择器


/* 错误 */  
#id {}  
.a .b .c {}  
.a > .b {}  

/* 正确 */  
.class {}  

4、border 不支持简写


/* 错误 */  
.class {  
    border: 1px red solid;  
}  

/* 正确 */  
.class {  
    border-width: 1px;  
    border-style: solid;  
    border-color: red;  
}  

5、background 不支持简写

/* 错误 */  
.class {  
    background: red;  
}  

/* 正确 */  
.class {  
    background-color: red;  
}

6、.nvue 页面的布局排列方向默认为竖排(column),如需改变布局方向,可以在 manifest.json -> app-plus -> nvue -> flex-direction 节点下修改,仅在 uni-app 模式下生效。 详情
7、nvue的uni-app编译模式下,App.vue 中的样式,会编译到每个 nvue文件。非uni-app编译模式不会。对于共享样式,如果有不合法属性控制台会给出警告,可以通过条件编译屏蔽 App 中的警告。

/* 错误 */  
/*  控制台警告:WARNING: `border` is not a standard property name (may not be supported)  */  
.class {  
    border: 1px red solid;  
}  

/* 正确 */  
.class {  
    border-width: 1px;  
    border-style: solid;  
    border-color: red;  
}  

默认逻辑

manifest.json 配置文件中,未明确指定编译模式(即未配置app-plus -> nvueCompiler),在HBuilderX2.4以前,默认值为 weex 模式,2.4起默认值改为 uni-app 模式。

nvue编译为H5、小程序时注意

nvue页面编译为H5、小程序时,会做一件css默认值对齐的工作。
因为weex布局只支持flex,并且默认flex方向是垂直。而H5和小程序端,使用web渲染,web默认不是flex,并且设置display:flex后,它的flex方向默认是水平的。
所以nvue编译为H5、小程序时,会自动把页面默认布局设为flex、方向为垂直。当然开发者手动设置后会覆盖默认设置。

继续阅读 »

HBuilderX2.0.3 版本开始,nvue文件同时支持两种编译模式:

  • weex 模式:老模式,使用 weex组件,写法同weex标准写法。只能在 App 端中运行,部分 uni-app JS Api 不能使用。
  • uni-app 模式:新模式,默认模式,使用 uni-app 基础组件,组件、jsapi写法同uni-app。支持app.vue里的全局样式;支持nvue页面编译H5和小程序端;可以使用绝大部分 uni-app Api 。uni-app模式也可以使用weex里的组件,比如list、refresh、recircle-list。

为什么要提供2个模式?

weex模式的组件、渲染机制是weex官方维护的。它的渲染性能其实与react native是一样的,在性能体验方面足以应付一线互联网公司的苛求。但它有4个问题:

  1. 内置组件较少,或不完善。与小程序的组件相比,weex缺少太多内置组件,比如picker、map。而video等weex已内置的组件,也不够强大
  2. API缺失严重。因为weex只是个渲染器,它调用设备能力或push等三方sdk,都需要原生开发。
  3. 周边生态不完善。weex生态没有什么好的组件和模板。而uni-app的插件市场里众多优秀的组件和模板又无法用于nvue。
  4. nvue无法多端开发,只能用于app。开发者在多端需要维护多套代码。
  5. weex的排版思路和uni-app的vue差异有点多。比如weex不支持rpx。我们希望使用原生渲染,但尽可能多的兼容开发者的习惯。

weex的第二个问题,即能力问题,uni-app通过给nvue补充uni API和plus API,得到了解决。
但剩下的几个问题,需要uni-app的新编译模式才能解决。
我们要把小程序的所有组件,在weex的原生渲染机制上,重新实现一遍,让小程序的组件可以直接用原生来渲染。然后包括uni ui等扩展组件也都将兼容nvue。
现在插件市场的新闻模板,已经支持nvue新编译模式,它可以一套代码编译到App、小程序、H5全端。并且在App上是原生渲染的高性能体验。

之所以仍然存在weex模式,一是为了向下兼容,之前已经使用nvue的weex模式开发的app,不会因为HBuilderX的升级而导致页面错乱;二是为了方便weex的老用户迁移。

对于普通开发者,正常来讲应该选择uni-app编译模式。

注意nvue的uni-app编译模式,仍然是要求写nvue文件。

配置方式--uni-app编译模式或weex编译模式

manifest.json 的源码视图里配置是切换模式, manifest.json -> app-plus -> nvueCompiler 切换编译模式。

nvueCompiler 有两个值:

  • weex
  • uni-app
// manifest.json      
{      
    // ...      
     /* App平台特有配置 */      
    "app-plus": {      
        "nvueCompiler":"uni-app" //是否启用 uni-app 模式    
    }      
}     

差异说明

组件差异

在老的 weex 模式中,我们使用的是 weex组件 遵循的是 weex规范,如果使用 nvue 页面将不能跨端开发,仅能在 App 端运行。如果跨端那么意味着要实现vue 页面和 .nvue 页面两套代码。

代码示例

<template>  
    <div>  
        <text>测试页面</text>  
    </div>  
</template>  

而在 uni-app 模式中,我们将可以在 weex 组件的基础上使用 uni-app 的基础组件,目前已支持部分组件,并支持 .nvue 页面编译到 H5 和小程序端。

代码示例

<template>  
    <view>  
        <text>测试页面</text>  
    </view>  
</template>  

nvue的uni-app编译模式组件使用注意

组件的使用注意事项: 组件 注意事项
text 文字尽量写在text节点,非text节点的文字无法自动更新
rich-text nodes 属性只支持节点列表不支持 HTML String
web-view 必须指定高度,不支持页面通讯和网页内使用Plus API 。但在nvue里可以使用plus.webview.create来创建webview。这样的webview能力上更强大,但注意和原页面会有层级问题

默认页面滚动差异

weex 模式中,我们需要页面滚动,必须使用 <list> 组件或者 <scroller> 组件,这与我们开发小程序或者 web 的习惯并不符合。而在 uni-app 模式中,则可以像 vue 页面一样方便开发,不需要去声明额外的组件进行滚动,只要页面内容高度高于屏幕,就会自动滚动。实际上,在新模式里自动给每个nvue页面的根下套了一个scroller。

单位差异

weex的px是动态单位,并且不支持rpx。这与uni-app的设计不符。
在新模式中,rpx和px分别是动态单位和静态单位,与vue的设计一样。

Tips

注意事项

API 注意事项

.nvue 支持大部分 uni-app API详情

css 注意事项

.nvue 中,有些 css 样式需要注意,与 web 开发中样式写法会有区别。

1、只有text标签可以设置字体大小,字体颜色
2、布局不能使用百分比
3、只能使用 class 选择器


/* 错误 */  
#id {}  
.a .b .c {}  
.a > .b {}  

/* 正确 */  
.class {}  

4、border 不支持简写


/* 错误 */  
.class {  
    border: 1px red solid;  
}  

/* 正确 */  
.class {  
    border-width: 1px;  
    border-style: solid;  
    border-color: red;  
}  

5、background 不支持简写

/* 错误 */  
.class {  
    background: red;  
}  

/* 正确 */  
.class {  
    background-color: red;  
}

6、.nvue 页面的布局排列方向默认为竖排(column),如需改变布局方向,可以在 manifest.json -> app-plus -> nvue -> flex-direction 节点下修改,仅在 uni-app 模式下生效。 详情
7、nvue的uni-app编译模式下,App.vue 中的样式,会编译到每个 nvue文件。非uni-app编译模式不会。对于共享样式,如果有不合法属性控制台会给出警告,可以通过条件编译屏蔽 App 中的警告。

/* 错误 */  
/*  控制台警告:WARNING: `border` is not a standard property name (may not be supported)  */  
.class {  
    border: 1px red solid;  
}  

/* 正确 */  
.class {  
    border-width: 1px;  
    border-style: solid;  
    border-color: red;  
}  

默认逻辑

manifest.json 配置文件中,未明确指定编译模式(即未配置app-plus -> nvueCompiler),在HBuilderX2.4以前,默认值为 weex 模式,2.4起默认值改为 uni-app 模式。

nvue编译为H5、小程序时注意

nvue页面编译为H5、小程序时,会做一件css默认值对齐的工作。
因为weex布局只支持flex,并且默认flex方向是垂直。而H5和小程序端,使用web渲染,web默认不是flex,并且设置display:flex后,它的flex方向默认是水平的。
所以nvue编译为H5、小程序时,会自动把页面默认布局设为flex、方向为垂直。当然开发者手动设置后会覆盖默认设置。

收起阅读 »

基于HBuilder iOS离线打包 oc和js互调

离线打包 HBuilder h5+

本篇文章基于HBuilder iOS离线打包widget方式 oc和js 互调 ps:如果不是离线打包方式代码仅供参考

原理:js调用oc用的是H5+封装好的api,oc调用js 并不是真正的调用js方法,而是注册自定义监听事件,通过监听的方式获取oc传到js里的参数,从而达到oc调用js

js调用原生oc方法

  • js调用oc类方法

    //LoginViewController是oc类 txt是要传的参数  
    plus.ios.importClass("LoginViewController").login("txt“);
  • js调用oc对象方法

    //objectToJsonImage是oc对象方法  massageArray返回值  
    var Massage = plus.ios.importClass("LoginViewController");  
    var massage = new Massage();  
    var massageArray = massage.objectToJsonImage();
  • js调用oc方法可以后的oc的返回值

oc 调用js

  • oc调用js 比较复杂 看代码吧

    (NSMutableArray*)searchViews:(NSArray*)views{  
    
    NSMutableArray *frames = [NSMutableArray array];  
    //遍历view  
    for (UIView *temp in views) {  
    
        if ([temp isMemberOfClass:[PDRCoreAppFrame class]]) {  
    
            [frames addObject:temp];  
        }  
        if ([temp subviews]) {  
    
            NSMutableArray *tempArray = [self searchViews:[temp subviews]];  
    
            for (UIView *tempView in tempArray) {  
    
                if ([tempView isMemberOfClass:[PDRCoreAppFrame class]]) {  
    
                    [frames addObject:tempView];  
                }  
            }  
        }  
    }  
    //返回值 frames 为从该层级中找到的 PDRCoreAppFrame  
    return frames;  
    }  
    (void)evaluatingJavaScriptFromString:(NSString*)string{  
    
    UIWindow *window = [[UIApplication sharedApplication] keyWindow];  
    
    NSArray *views = [[[window rootViewController] view] subviews];  
    
    NSArray *frames = [self searchViews:views];  
    
    for (PDRCoreAppFrame *appFrame in frames) {  
        /*这里需要注意执行异步任务,在block内需要回到主线程来进行JS event的调用,但是如果还是使用  
         dispath_get_main_queue的话会造成调用JS有alert的话线程会死锁,具体原因也不是特别清晰,  
         在stackOverFlow中看到应该是JS和OC不同alert线程的原因  
         */  
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{  
            [appFrame performSelectorOnMainThread:@selector(stringByEvaluatingJavaScriptFromString:) withObject:string waitUntilDone:NO];  
    
        });  
    }  
    }  
    (void)fireEvent:(NSString*)event args:(NSString *)args{  
    NSString *evalStr = nil;  
    
    if (args) {  
        //创建js事件  
        evalStr = [NSString stringWithFormat:@"\  
                   var pathEvent = document.createEvent('HTMLEvents');\  
                   pathEvent.initEvent('%@', true, true);\  
                   pathEvent.eventType = 'message';\  
                   pathEvent.arguments = '%@';\  
                   document.dispatchEvent(pathEvent);",event,args];  
    }else{  
        evalStr = [NSString stringWithFormat:@"\  
                   var pathEvent = document.createEvent('HTMLEvents');\  
                   pathEvent.initEvent('%@', true, true);\  
                   pathEvent.eventType = 'message';\  
                   document.dispatchEvent(pathEvent);",event];  
    }  
    //return evalStr;  
    //调用上述方法  
    [self evaluatingJavaScriptFromString:evalStr];  
    }  
    //通过此代码调用  
    [self fireEvent:@"event_name" args:@"json"];  
    //js端代码  
    document.addEventListener('event_name', function(e) {  
        alert(e.arguments);  
    }, false);
继续阅读 »

本篇文章基于HBuilder iOS离线打包widget方式 oc和js 互调 ps:如果不是离线打包方式代码仅供参考

原理:js调用oc用的是H5+封装好的api,oc调用js 并不是真正的调用js方法,而是注册自定义监听事件,通过监听的方式获取oc传到js里的参数,从而达到oc调用js

js调用原生oc方法

  • js调用oc类方法

    //LoginViewController是oc类 txt是要传的参数  
    plus.ios.importClass("LoginViewController").login("txt“);
  • js调用oc对象方法

    //objectToJsonImage是oc对象方法  massageArray返回值  
    var Massage = plus.ios.importClass("LoginViewController");  
    var massage = new Massage();  
    var massageArray = massage.objectToJsonImage();
  • js调用oc方法可以后的oc的返回值

oc 调用js

  • oc调用js 比较复杂 看代码吧

    (NSMutableArray*)searchViews:(NSArray*)views{  
    
    NSMutableArray *frames = [NSMutableArray array];  
    //遍历view  
    for (UIView *temp in views) {  
    
        if ([temp isMemberOfClass:[PDRCoreAppFrame class]]) {  
    
            [frames addObject:temp];  
        }  
        if ([temp subviews]) {  
    
            NSMutableArray *tempArray = [self searchViews:[temp subviews]];  
    
            for (UIView *tempView in tempArray) {  
    
                if ([tempView isMemberOfClass:[PDRCoreAppFrame class]]) {  
    
                    [frames addObject:tempView];  
                }  
            }  
        }  
    }  
    //返回值 frames 为从该层级中找到的 PDRCoreAppFrame  
    return frames;  
    }  
    (void)evaluatingJavaScriptFromString:(NSString*)string{  
    
    UIWindow *window = [[UIApplication sharedApplication] keyWindow];  
    
    NSArray *views = [[[window rootViewController] view] subviews];  
    
    NSArray *frames = [self searchViews:views];  
    
    for (PDRCoreAppFrame *appFrame in frames) {  
        /*这里需要注意执行异步任务,在block内需要回到主线程来进行JS event的调用,但是如果还是使用  
         dispath_get_main_queue的话会造成调用JS有alert的话线程会死锁,具体原因也不是特别清晰,  
         在stackOverFlow中看到应该是JS和OC不同alert线程的原因  
         */  
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{  
            [appFrame performSelectorOnMainThread:@selector(stringByEvaluatingJavaScriptFromString:) withObject:string waitUntilDone:NO];  
    
        });  
    }  
    }  
    (void)fireEvent:(NSString*)event args:(NSString *)args{  
    NSString *evalStr = nil;  
    
    if (args) {  
        //创建js事件  
        evalStr = [NSString stringWithFormat:@"\  
                   var pathEvent = document.createEvent('HTMLEvents');\  
                   pathEvent.initEvent('%@', true, true);\  
                   pathEvent.eventType = 'message';\  
                   pathEvent.arguments = '%@';\  
                   document.dispatchEvent(pathEvent);",event,args];  
    }else{  
        evalStr = [NSString stringWithFormat:@"\  
                   var pathEvent = document.createEvent('HTMLEvents');\  
                   pathEvent.initEvent('%@', true, true);\  
                   pathEvent.eventType = 'message';\  
                   document.dispatchEvent(pathEvent);",event];  
    }  
    //return evalStr;  
    //调用上述方法  
    [self evaluatingJavaScriptFromString:evalStr];  
    }  
    //通过此代码调用  
    [self fireEvent:@"event_name" args:@"json"];  
    //js端代码  
    document.addEventListener('event_name', function(e) {  
        alert(e.arguments);  
    }, false);
收起阅读 »

HBuilderX editorconfig使用说明

editorconfig editconfig

HBuilderX 2.0.3+起支持

editorconfig是什么?

很多公司都要求各开发成员使用相同的编码风格,比如缩进是空格还是tab。

editorconfig是一套解决这个问题的业内通用规范,通过在项目下存放配置文件.editorconfig,并在这个配置文件中描述规则,然后把这个配置文件和其他代码一起提交git/svn,所有项目成员,都会遵循相同的编码规范。

HBuilderX直接支持该规范,无需下载插件,开箱即用。sublime、vscode支持该规范的话需要先下载插件。

editorconfig的官网是https://editorconfig.org/
editorconfig可以帮助开发者在不同的编辑器和IDE之间定义和维护一致的代码风格。
editorconfig包含一个用于定义代码格式的文件和一批编辑器插件,这些插件可以让编辑器读取配置文件并依此格式化代码。
editorconfig的配置文件十分易读,并且可以在各个操作系统、编辑器下工作。

editorconfig的配置文件是怎样的?

以下是一个用于设置Python和JavaScript行尾和缩进风格的配置文件。

# EditorConfig is awesome: http://EditorConfig.org  

# top-most EditorConfig file  
root = true  

# Unix-style newlines with a newline ending every file  
[*]  
end_of_line = lf  
insert_final_newline = true  

# 4 space indentation  
[*.py]  
indent_style = space  
indent_size = 4  

# Tab indentation (no size specified)  
[*.js]  
indent_style = tab  

# Indentation override for all JS under lib directory  
[lib/**.js]  
indent_style = space  
indent_size = 2  

# Matches the exact files either package.json or .travis.yml  
[{package.json,.travis.yml}]  
indent_style = space  
indent_size = 2

案例

很多开源项目都用到了editorconfig

比如jQuery, jQueryGithub上的.editorconfig配置文件如下:

root = true  

[*]  
indent_style = tab  
end_of_line = lf  
charset = utf-8  
trim_trailing_whitespace = true  
insert_final_newline = true  

[package.json]  
indent_style = space  
indent_size = 2

如上,可以看到,JQuery配置了:编码格式、缩进风格等

在哪里存放配置文件

当打开一个文件时,editorconfig插件会在打开文件的目录和其每一级父目录查找.editorconfig文件,直到有一个配置文件root=true

如果一个工程中出现多个配置文件,EditorConfig配置文件的读取层级是自上而下的,最深层的配置文件,最后读取。配置规则也是 按照读取的顺序来生效,所以路径上离代码最近的配置规则,优先级最高。

相对于其他开发工具(如vscode),HBuilderX对editorconfig更完善。在其他工具中,项目外层如果有editorconfig文件,也会影响这个项目,经常让人莫名其妙。HBuilderX没有这个bug。

文件格式详情

editorconfig文件使用INI格式(译注:请参考维基百科),目的是可以与Python ConfigParser Library兼容,但是允许在分段名(译注:原文是section names)中使用“and”。
分段名是全局的文件路径,格式类似于gitignore。斜杠/作为路径分隔符,#或者;作为注释。注释应该单独占一行。editorconfig文件使用UTF-8格式、CRLFLF作为换行符。

通配符

通配符 说明
* 匹配除/之外的任意字符串
** 匹配任意字符串
匹配任意单个字符
[name] 匹配name字符
[!name] 匹配非name字符
{s1,s3,s3} 匹配任意给定的字符串(0.11.0起支持)

特殊字符可以用\转义,以使其不被认为是通配符。

支持的属性

属性说明 说明
indent_style tab为hard-tabs,space为soft-tabs
indent_size 设置整数表示规定每级缩进的列数和soft-tabs的宽度(译注:空格数)。如果设定为tab,则会使用tab_width的值(如果已指定)
tab_width 设置整数用于指定替代tab的列数。默认值就是indent_size的值,一般无需指定。
end_of_line 定义换行符,支持lf、cr和crlf。
trim_trailing_whitespace 设为true表示会除去换行行首的任意空白字符,false反之
insert_final_newline 设为true表明使文件以一个空白行结尾,false反之
root 表明是最顶层的配置文件,发现设为true时,才会停止查找.editorconfig文件。

注意

  1. 在HBuilderX内, 所有的属性名和属性值对大小写敏感。通常,如果没有明确指定某个属性,则会使用编辑器的配置,而editorconfig不会处理。
  2. 推荐不要指定某些editorconfig属性。比如,tab_width不需要特别指定,除非它与indent_size不同。同样的,当indent_style设为tab时,不需要配置indent_size,这样才方便阅读者使用他们习惯的缩进格式。另外,如果某些属性并没有规范化(比如end_of_line),就最好不要设置它。
  3. 如果你不需要editorconfig的功能,可以在工具-设置中关闭这个功能。

HBuilderX 启用或关闭editorconfig配置

在【设置】中,有个editorconfig开关,您可以自由选择开启与关闭.editorconfig

继续阅读 »

HBuilderX 2.0.3+起支持

editorconfig是什么?

很多公司都要求各开发成员使用相同的编码风格,比如缩进是空格还是tab。

editorconfig是一套解决这个问题的业内通用规范,通过在项目下存放配置文件.editorconfig,并在这个配置文件中描述规则,然后把这个配置文件和其他代码一起提交git/svn,所有项目成员,都会遵循相同的编码规范。

HBuilderX直接支持该规范,无需下载插件,开箱即用。sublime、vscode支持该规范的话需要先下载插件。

editorconfig的官网是https://editorconfig.org/
editorconfig可以帮助开发者在不同的编辑器和IDE之间定义和维护一致的代码风格。
editorconfig包含一个用于定义代码格式的文件和一批编辑器插件,这些插件可以让编辑器读取配置文件并依此格式化代码。
editorconfig的配置文件十分易读,并且可以在各个操作系统、编辑器下工作。

editorconfig的配置文件是怎样的?

以下是一个用于设置Python和JavaScript行尾和缩进风格的配置文件。

# EditorConfig is awesome: http://EditorConfig.org  

# top-most EditorConfig file  
root = true  

# Unix-style newlines with a newline ending every file  
[*]  
end_of_line = lf  
insert_final_newline = true  

# 4 space indentation  
[*.py]  
indent_style = space  
indent_size = 4  

# Tab indentation (no size specified)  
[*.js]  
indent_style = tab  

# Indentation override for all JS under lib directory  
[lib/**.js]  
indent_style = space  
indent_size = 2  

# Matches the exact files either package.json or .travis.yml  
[{package.json,.travis.yml}]  
indent_style = space  
indent_size = 2

案例

很多开源项目都用到了editorconfig

比如jQuery, jQueryGithub上的.editorconfig配置文件如下:

root = true  

[*]  
indent_style = tab  
end_of_line = lf  
charset = utf-8  
trim_trailing_whitespace = true  
insert_final_newline = true  

[package.json]  
indent_style = space  
indent_size = 2

如上,可以看到,JQuery配置了:编码格式、缩进风格等

在哪里存放配置文件

当打开一个文件时,editorconfig插件会在打开文件的目录和其每一级父目录查找.editorconfig文件,直到有一个配置文件root=true

如果一个工程中出现多个配置文件,EditorConfig配置文件的读取层级是自上而下的,最深层的配置文件,最后读取。配置规则也是 按照读取的顺序来生效,所以路径上离代码最近的配置规则,优先级最高。

相对于其他开发工具(如vscode),HBuilderX对editorconfig更完善。在其他工具中,项目外层如果有editorconfig文件,也会影响这个项目,经常让人莫名其妙。HBuilderX没有这个bug。

文件格式详情

editorconfig文件使用INI格式(译注:请参考维基百科),目的是可以与Python ConfigParser Library兼容,但是允许在分段名(译注:原文是section names)中使用“and”。
分段名是全局的文件路径,格式类似于gitignore。斜杠/作为路径分隔符,#或者;作为注释。注释应该单独占一行。editorconfig文件使用UTF-8格式、CRLFLF作为换行符。

通配符

通配符 说明
* 匹配除/之外的任意字符串
** 匹配任意字符串
匹配任意单个字符
[name] 匹配name字符
[!name] 匹配非name字符
{s1,s3,s3} 匹配任意给定的字符串(0.11.0起支持)

特殊字符可以用\转义,以使其不被认为是通配符。

支持的属性

属性说明 说明
indent_style tab为hard-tabs,space为soft-tabs
indent_size 设置整数表示规定每级缩进的列数和soft-tabs的宽度(译注:空格数)。如果设定为tab,则会使用tab_width的值(如果已指定)
tab_width 设置整数用于指定替代tab的列数。默认值就是indent_size的值,一般无需指定。
end_of_line 定义换行符,支持lf、cr和crlf。
trim_trailing_whitespace 设为true表示会除去换行行首的任意空白字符,false反之
insert_final_newline 设为true表明使文件以一个空白行结尾,false反之
root 表明是最顶层的配置文件,发现设为true时,才会停止查找.editorconfig文件。

注意

  1. 在HBuilderX内, 所有的属性名和属性值对大小写敏感。通常,如果没有明确指定某个属性,则会使用编辑器的配置,而editorconfig不会处理。
  2. 推荐不要指定某些editorconfig属性。比如,tab_width不需要特别指定,除非它与indent_size不同。同样的,当indent_style设为tab时,不需要配置indent_size,这样才方便阅读者使用他们习惯的缩进格式。另外,如果某些属性并没有规范化(比如end_of_line),就最好不要设置它。
  3. 如果你不需要editorconfig的功能,可以在工具-设置中关闭这个功能。

HBuilderX 启用或关闭editorconfig配置

在【设置】中,有个editorconfig开关,您可以自由选择开启与关闭.editorconfig

收起阅读 »