App开发

一 开发方式

原生开发(Native App)

指在Android、IOS等移动平台上利用官方提供的开发语言、开发类库、开发工具进行App软件开发。其中Android是利用Java、Eclipse、Android studio;IOS是利用Objective-C 和Xcode进行开发。

优点:

  1. 原生APP最大的优势在于性能,能够快速运行、支持大量图片内容以及一些动图等,在使用设备提供的接口方面也更加快捷。
  2. 可实现的功能更多,可访问设备提供的所有功能。
  3. 兼容性更高,经过精心设计与调试后可以达到更加理想的效果。
  4. 在App Store审核期间会进行检测,确保无害后上架,用户无需担心其安全性。

缺点:

  1. 成本高,开发时间长,需要的开发人员过多,Android和iOS需要各自单独开发,无法跨平台兼容。
  2. 需要将App提交于App Store,这意味着客户能否下载使用,取决于客户手机应用商城是否准许。
  3. App Store审核周期较长(首次提交最快5-7天,再次提交最快1-2天,指单次审核,没有被驳回的情况),无法追求快速更新。
  4. 不同用户可能使用不同版本的App,提供所有版本的支持较难。

混合开发(Hybrid App)

Hybrid App指半原生半Web的混合类App。看上去类似Native App,但访问的内容是Web。

混合应用程序让开发人员可以把HTML5应用程序嵌入到一个细薄的原生容器里面,集原生应用程序和HTML5应用程序的优点(及缺点)于一体。

优点:

  1. Hybrid App的优势主要在于开发成本低,一套代码可兼容多种平台,不需要两拨人进行开发。
  2. 更新和部署比较方便,每次升级版本只需要在服务器端升级即可,不需要上传到App Store进行审核。

缺点:

  1. 性能方面不是很稳定,其加载/运行速度太过依赖于网络环境,因其原理在于将Web嵌入进App。
  2. 对于不同机型的兼容较差,在不同比例的屏幕上的表现有一定差异。
  3. 功能/界面的定制性较差,能够实现的功能有局限性。

对比

原生开发混合开发
开发周期开发周期远长于混合开发,Android和IOS都要各自开发开发周期较短,一套代码兼容多种平台
性能运行速度快,在调用设备提供的接口时有性能优势数据需要全部从服务器调取,网络占用高,缓冲时间长
兼容性兼容性高,一般不会出现闪退的情况兼容性一般,在最新手机系统上不能很好的兼容
定制性可访问手机所有功能(如GPS、摄像头),可实现功能最齐全功能、界面无法随意更改,想增加功能困难
跨平台性
维护更新较为复杂代码维护方便、版本更新快
上线需要上传到App Store进行审核,需要注意App Store内容限制每次升级版本只需要在服务器端升级即可

二 混合开发技术

1 uni-app

uni-appHBuilder母公司DCloud推出的一个使用Vue.js开发所有前端应用的框架,开发者编写一套代码,可发布到iOSAndroidH5、以及各种小程序等多个平台,其优势在于高贵的Vue语法与海量的轮子,可以说在诸多框架中,uni-app拥有最高的开发效率。

uni-app在国内热度较高,使用Vue.js开发所有前端应用,其优势在于生态丰富,案例较多,学习成本低,且支持热更新,开发高效,维护至今已拥有成熟的文档及社区支持。

img

uni-app集成了各种登录、支付、分享、地图等支持,对于国内环境而言非常友好,相比之下RN、flutter使用的是Google服务及Facebook登录,在国内都不支持。

一套代码编到13个平台,这不是梦想。眼见为实,扫描13个二维码,亲自体验最全面的跨平台效果!

这是uni-app打市场时喊出最响亮的口号,但也正因其跨平台过多,导致至今uni-app仍有很多坑未填,文档在某些方面也略显混乱,对于开发者而言,就需要去熟悉各个平台的规则。

uni-app由DCloud公司推出,而DCloud公司作为小程序的始祖,其开发的框架更偏向于小程序,而非App。

在性能方面,uni-app内置了双渲染引擎,webview和weex,可随意切换。

2 Flutter

Flutter是一款移动应用程序SDK,一份代码可以同时生成iOS和Android两个高性能、高保真的应用程序。

11451874-12b2515a4cb0cdb1.png

Flutter可以说是目前市面上口碑最好,最为强大的混合开发框架。在诸多跨平台框架中,Flutter有着最好的体验,性能与构建思路最接近原生App。

相对于uni-app和RN,Flutter在性能方面有着压倒性的优势。Flutter的母公司为Google,而Google作为一个轮子大厂,直接在两个平台上重写了各自的UIKit,对接到平台底层,减少UI层的多层转换,这使得Flutter拥有了可以比肩原生的UI性能,这一优势在滑动、拖动、播放动画效果时尤为明显。

13455005-9abc5e26f3fc2b7b.webp

Flutter使用Dart语言进行开发,Dart是一个静态语言,这也是相对于js的一个优势。Dart可以被编译成js,但是看起来更像java。静态语言可以避免错误,获得更多的编辑器提示词,极大的增加可维护性。

在UI表现方面,Flutter用于极为优秀的动画设计。其实现方式为在每一帧渲染正确的组件,从而形成连贯的动画。这种十分暴力的操作在Flutter上却看不到明显的卡顿,这也是Flutter的一个强大之处。相比之下其他跨平台框架几乎不能设计动画……往往会遭遇非常严重的性能问题。同时Flutter不依赖于CSS等外部解释器,几乎不存在UI表达不理想,渲染不正常的情况,可以获得非常稳定的UI表达效果。

然而在Flutter诸多优秀的表现之后,同时存在着很明显的缺陷。

作为一款跨平台框架,使用Flutter开发却仍然难以避免需要手写相当一部分的原生代码,这对于非专业人士(Android与IOS开发人员)而言十分不友好,原因在于选择跨平台框架,很大程度是为了避免接触原生,降低学习与维护成本,而如果团队中存在专业的Android与IOS开发人员,又没有选择混合开发的必要,这就产生了非常尖锐的矛盾。

Flutter提倡“组合”,而不是“继承”。在iOS开发中,我们经常会继承UIView,重写UIView的某个生命周期函数,再添加一些方法和属性,来完成一个自定义的View。但是在Flutter中这些都是不可能的——属性都是final的,例如你继承了了一个Container,你是不能在它的生命周期中修改他的属性的。这导致了初学时很难想明白如何去构建一个完整的组件。

与此同时,Google在UI控件方面做的比较糟糕。例如Appbar组件,它的高度是写死(const)的,而Flutter又使用了“组合”的方式,无法直接对其进行修改,类似问题数不胜数,这会为开发人员带来很多困扰。

Flutter的缺点还表现在:

  1. 适配问题,曾出现开发工具版本升级后,旧代码不兼容问题。
  2. Flutter packages和Dart packages上第三方sdk繁杂,适配性差,不可乱用。
  3. 代码可读性很差,使人联想起十年前前端开发难以避免的回调地狱。
  4. Widget的类型难以选择。
  5. UI风格与国内有很大差异,更偏向圆圆滚滚的Material风,(大)部分用户群体很可能难以接受。
  6. 目前几乎没有第三方开发者平台开发Flutter能力的SDK,需要原生去集成。
  7. 打包后,apk/ipa要大很多。

总结一下,在跨平台框架中,Flutter效果最佳,潜力巨大,但开发语言为Dart,开发思维接近原生,导致其成本高于其他框架。

详见参考文档【浅谈flutter的优点与缺点】、【flutter框架优缺点】。

dart
void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'AutoDriver',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Login(),
    );
  }
}

...省略....

Widget get _appBar {
    return Column(
      children: <Widget>[
        Container(
          decoration: BoxDecoration(
              gradient: LinearGradient(
                  colors: [Color(0x66000000), Colors.transparent],
                  begin: Alignment.topCenter,
                  end: Alignment.bottomCenter)),
          child: Container(
            padding: EdgeInsets.fromLTRB(0, 20, 0, 0),
            height: 80.0,
            decoration: BoxDecoration(
                color:
                    Color.fromARGB((appBarAlpha * 255).toInt(), 255, 255, 255)),
            child: SearchBar(
              searchBarType: appBarAlpha > 0.2
                  ? SearchBarType.homeLight
                  : SearchBarType.home,
              inputBoxClick: _jumpToSearch,
              speakClick: _jumpToSpeak,
              defaultText: SEARCH_BAR_DEFAULT_TEXT,
              leftButtonClick: () {},
            ),
          ),
        ),
        Container(
          height: appBarAlpha > 0.2 ? 0.5 : 0,
          decoration: BoxDecoration(
              boxShadow: [BoxShadow(color: Colors.black12, blurRadius: 0.5)]),
        )
      ],
    );
  }

注:Flutter是Google的产品,国内禁用Google。

3 RN(React Native)

使用 React 来创建 Android 和 iOS 的原生应用

11451874-f497b4b23ec7392f.webp

React Native是一个使用React和应用平台的原生功能来构建Android和IOS应用的开源框架,由Facebook于2015年4月开源。它可将标记元素转化为真实的原生UI元素,同时与主UI线程分开工作以保证性能。

RN拥有仅次于Flutter的性能,运行流畅,但难以避免发热、高功耗问题;其开发语言虽然为React语言,但如果希望将其优化到理想的程度,仍然难以避免接触原生,就目前已有的案例来看,对于RN开发,最理想的方式是Android、IOS、RN三线并行,以保证动画、列表等组件能够流畅运行。

优点

  1. React Native可将标记元素转化为真实的原生UI元素,利用在任何平台上所呈现视图的现有方法。
  2. React Native与主UI线程分开工作,所以应用程序可以在不牺牲功能的前提下保持最大的性能。
  3. 以React为开发框架,开发效率较高。

缺点

  1. RN在动画效率和性能的支持还存在一些问题,且性能问题基本无解。
  2. RN严重依赖于Facebook的维护。苹果在iOS上每次技术的更新、政策的改变都会让原来使用了RN代码库受到影响,等待 Facebook和社区的修复会妨碍 App 的更新和用户体验。

4 对比

4.1 性能

在性能表现上,webview < RN/weex < flutter(uni-app使用webview与weex)

而在开发难度方面则相反,flutter的上手难度远远高于RN与uni-app,当布局复杂的界面时,flutter的代码嵌套令人崩溃,而使用CSS的RN和uni-app则更加灵活

vue
<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  
}
dart
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提供的布局写法是被限制过的,所以解析快、渲染快,它通过降低代码的灵活性与开发效率换取更高的性能。

4.2 开发效率

在开发效率方面,flutter是当之无愧的最差,RN紧随其后。将它们放在一起说,是因为RN和flutter都有一个很不中国化的设计:在两个平台上,使用两套UI库。

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

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

而在中国,人们普遍偏爱贴近iOS的中性风格,对Material风格的接受程度近乎于0(见微信Material临时版本的流产),所有的App都是相同的风格,所以对于国内的开发者,一套通用UI足够,两套毫无意义。

所以uni-app作为当前唯一的主流国产跨平台框架,默认使用了这种中性的iOS风格,真正的做到了write once,run anywhere。相比洋气的flutter与RN,更加符合国内环境。

总结:uni-app维护一套代码即可,RN与flutter则需要维护三套代码(iOS,Android,JS/Dart)。

4.3 动态性

混合开发往往有一个Nation不具备的优势:动态性,即远程动态载入js代码。前端开发者普遍认为动态性是天经地义的,但实际上flutter并不支持。因为它是有编译优化概念的,如果提供动态性支持,会影响它的性能。

业内有些开发者,改造了flutter,用一个独立的v8/jscore来加载动态js代码,去操作flutter布局引擎的渲染,但这一方案会造成性能明显下降,同时还大大增加了包的体积,还不如直接用RN/uni-app。

4.4 技术学习成本

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

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

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

可见在技术学习成本上,flutter > RN > uni-app,而相较于其他二者,uni-app的上手成本太低了,没有任何附加专有技术。

4.5 生态对比

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

对于国外的开发者,RN、flutter的生态肯定比uni-app好,比如Facebook登陆分享、Google地图等。

但对于国内的开发者则相反,中国开发者需要的全端推送(UniPush集成了iOS、华为、小米、OPPO等众多原厂推送)、各种国内登陆、支付、分享SDK、各种国内地图、各种ui库、以及Echart图表等,都是在uni-app体系里,而RN与flutter所提供的部分Google/Facebook服务在国内是无法正常使用的(墙)。uni-app的插件市场有数千款插件,不能说应有尽有,但确实是最丰富的跨端开发框架生态了。

另外uni-app的生态还强在以下方面:

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

参考文档

原生开发、H5开发和混合开发的区别

Flutter之美

浅谈flutter的优点与缺点

flutter框架优缺点

App Store 审核指南

uni-app renderjs

flutter、rn、uni-app比较

Flutter、RN、原生对比(Android端)