在原生和跨平台移动前端编程框架之间进行选择

开发移动应用时,您首先面临的决策之一是使用哪一种前端技术堆栈。

从历史上看,技术堆栈分类两类:原生堆栈(意味着能够在 iOS 或 Android 中开发应用)和基于 HTML 和 JavaScript 等 Web 技术的混合堆栈(iOS 和 Android)。在做出决定时,需要考虑到的主要因素包括性能(应用运行的速度有多快)和代码复用(在编写最少代码的情况下,可以支持多少个平台)。

这在当时是有意义的,因为在几年前,微软 (Microsoft) 和黑莓 (BlackBerry) 还努力通过各自的操作系统在智能手机市场上占据一席之地,而且,为了能够覆盖尽可能广泛的受众,开发者必须至少支持三个平台。自从宣布不再支持 Windows Mobile 和黑莓操作系统之后,现在,在 iOS 和 Android 上发布一款应用就足以覆盖 99% 以上的智能手机用户。

在 2015 年之前,混合一词指的是用 HTML、JavaScript 和 CSS 编写的移动应用,然后包装在一个原生外壳中,这样就可以将它们打包以在 Apple App Store 或 Google Play Store 上发布。人们认为,这种方法的主要缺点是性能问题,因为 Web 代码是在原生外壳提供的嵌入式 Web 浏览器 (WebView) 中运行的。2015 年 React Native 技术面世,该技术将 JavaScript 作为编程语言并绑定到原生 UI 小部件;2016 年微软收购并开源了 Xamarin,该技术被编译为平台运行时(AOT 或 JIT);由此,跨平台工具经历了戏剧性的加速发展,在纯性能方面缩小了与原生工具的差距。

这就是为什么今天在决定移动前端技术堆栈时,除了代码复用和性能维度,开发者、团队领导和架构师需要考虑更多的方面。

编码与执行

为了便于比较,我们先来弄清一些新概念:原生与跨平台编程和原生与混合执行

我们所说的原生和跨平台编程是什么意思?

  • 原生(编程)应用是指开发时采用了由开发平台和运行平台的操作系统的公司提供的编程语言和工具。例如,原生 iOS 应用将主要使用 Objective-C 和 Swift 编写,而原生 Android 应用则使用 Java 或 Kotlin 编写。
  • 跨平台(编程)应用是开发时采用了由开发平台和运行平台的操作系统的公司提供的开发工具之外的编程语言和工具。这包括很多种类的语言和工具,包括 Ionic、Xamarin、React Native、Apache Cordova、Flutter 等堆栈和框架。

现在让我们看一下原生执行和混合执行之间的区别。

  • 原生(执行)应用是用原生或跨平台编程语言编写的应用,然后要么编译为程序集代码预编译 (AOT),要么编译为即时编译 (JIT),后者仍然利用原生 UI 小部件。例如,用 Xamarin、React Native 和 Flutter 编写的应用都属于这一类。这是一个最近才出现的概念,因为这些框架都是最近发布的(Flutter 在 2018 年 12 月发布了第一个稳定版本),或者处于成熟的早期阶段(虽然在生产中经常使用,但 React Native 最新版本距离版本“1.0”还很遥远,因为在编写本文时的最新版本是 0.59)。
  • 混合(执行)应用是用跨平台的基于 Web 的编程语言(HTML、CSS 和 JavaScript/ECMAScript 或它们的超集,如 SCSS 和 TypeScript)编写的,并在原生外壳中执行,通常是 WebView 之类。用 Cordova 和 Ionic 编写的应用就属于这一类。

您可以在“全栈移动开发入门”的表 2 中看到对每种原生和跨平台前端技术堆栈的 IDE、CLI、OS 和编程语言的比较。值得注意的是,本文把重点放在全代码开发堆栈上,所以参数比较假设需要编写代码,而不是使用低代码或无代码的应用构建工具。

选择移动开发框架时的权衡

首先也是最重要的,我们先假设采用完全原生技术堆栈是移动开发框架的零妥协解决方案。如果您正在考虑使用跨平台的技术堆栈来开发移动应用,那么很可能还有其他考虑因素推动您做出这个决定(比如开发时间和代码复用),这可能需要您做出一些权衡。这些权衡不一定与性能有关,但一定涵盖了移动开发的其他方面,如工具的升级路径和时间安排,以及对移动 OS 更新的语言支持。

性能

原生和非原生移动应用之间的主要权衡是性能,混合移动应用的性能要低于原生移动应用。说到性能,我指的只是 2D 的移动应用,而不是需要 3D 引擎的 3D 应用。

即使没有 3D 图形,您也希望您的移动应用 UI 保持流畅,即使在处理大量数据时也依然如此,以提供顺畅的用户体验。因为移动处理器是多线程的,所以您不希望移动应用 UI 逻辑与数据处理在同一线程上运行。虽然代码质量不高的移动应用在任何堆栈上都会执行得很慢,但原生移动开发框架具有内置的功能,并提供了 API 来微调不同线程上的操作调度。然而,基于 Web 技术的 Web 应用和混合应用需要在嵌入式 Web 浏览器上运行其内容,并执行繁重的处理,例如解析浏览器内的大型 API 响应,导致 UI 卡顿(或者显示全屏“正在加载”指示符,以防止用户与用户界面交互)。

最近的大多数跨平台移动开发框架都以不同的方式解决了性能限制,其中一些在运行时方面符合原生应用的要求。

  • Reaction Native 使用 JavaScriptCore 引擎来执行 Javascript 代码和 UI 的原生小部件,使得 Javascript 代码不会让 UI 卡顿。
  • Xamarin 以“预编译 (AOT)”方式将代码编译为 ARM 程序集语言(针对 iOS)和 MonoVM 虚拟机(针对 Android),后者与 Kernel 上的 JVM 处于同一级别。
  • Flutter 便以为针对 iOS 和 Android 的 32 位和 64 位 ARM 代码。

上述所有方法都有一定的局限性,这取决于不同的平台,在设计移动应用时,您应该仔细查看有关局限性的页面,看看是否有这样复杂的需求,其中某个框架可能不适合您。

人员配备或资源

如果您决定使用跨平台移动开发框架,您将获得的优势是:能够以同样的技能针对多个平台(iOS、Android 甚至 Universal Windows Platform 和 Web)开发应用。人员配备或资源方面的潜在权衡是,您将会建立一个“泛型人才”团队。“泛型”设计师将面临的风险是不知道每个目标平台的能力,会构建不伦不类的 UI。“泛型”开发者可能不知道某些特定于目标平台的 API,并试图利用另一个工具包“重来一遍”。您将希望确保您的团队在为跨平台移动应用配备人力资源时具有强有力的设计和架构指导。

此外,不要轻易相信跨平台移动开发框架比原生框架更容易使用的传言。通常情况下,如果您正在构建一个复杂的应用,那么就必须使用某些设备原生特性(使用仅以原生代码编写的插件或桥接工具)。因此,您将需要具备高水平专业知识的高级开发者。

开发时间和代码复用

在新移动项目中,始终至关重要的是上市时间,公司总是在寻找方法来尽可能地缩减开发移动应用所需的时间。虽然可以同时在 iOS 和 Android 上构建双原生应用并同时发布,但这种方法可能需要您要么延长开发时间,要么扩大团队规模。

跨平台移动开发框架,再加上良好的应用架构,可以通过提高代码复用率来帮助缩短开发时间。对于没有广泛使用框架的应用,比较现实的做法是,考虑在 Xamarin、React Native 和 Ionic 框架中实现 90% 的代码复用。有些工具(如 Ionic)不仅允许在移动平台上重复使用相同的代码,而且还允许在 Web 应用中重复使用相同的代码(通过构建渐进式 Web 应用)。

试图最大限度提高代码复用的潜在风险是,您可能会忽略每个平台的特定优势,因为您的开发目标普普通通,不会利用特定于平台的框架。

未来升级路径

移动平台格局不断变化,您需要考虑一下将要开发的移动应用的生命周期。您越是希望您的应用在不需要大量重写的情况下在市场上生存更长时间,就越会选择一个提供清晰升级路径的堆栈。如果您选择了一个没有长期路线图或支持社区非常小的技术堆栈,那么您将面临在未来某个时候不得不重写应用的风险,而这会耗费大量资金。 如果您选择原生移动开发堆栈,供应商很可能会提供清晰的迁移路径、指南和自动迁移工具。即使发生了重大迁移(比如,从 Objective-C 迁移到 Swift,或者从 Java 迁移到 Kotlin),每个平台供应商都提供了针对新语言的工具和支持指南。 对于跨平台移动开发技术,这种风险更高。为了降低这种风险,您需要选择背靠大社区或大公司的工具。在这种情况下,支持费用可以发挥作用,但如果供应商是一家小众公司,那么支持费用反而不是最重要的因素。

OS 更新 – 支持、时间安排和工作量

这方面意味着要解决“新版 OS 发布后会发生什么情况?”以及一些相关问题,比如“我的框架最快多久能够支持最新功能?”

原生语言和工具将从发布之日起就得到支持,而对于跨平台工具,从发布稳定版 OS 到跨平台框架自身支持相同功能,不可避免地会有延迟。您可以通过考虑以下问题来解决这种权衡:“对于您的应用来说,在发布当天立即支持新功能有多重要?”“您是否打算在苹果或谷歌的会议上展示即将发布的应用功能?”如果这些问题的答案是肯定的,您将更喜欢原生堆栈。

您还需要考虑这样一种可能性:最新 OS 版本可能会引入 API 更改或构建工具箱更改,而 API 更改要求修改应用代码以使应用在最新 OS 更新中高效率运行,而构建工具箱的更改可能会导致构建失败。例如,Xcode 10 发布时,包含了一个新的构建工具,导致基于 Cordova 的 Ionic Framework 应用无法在 iOS 上正确地打包。虽然解决方案通常很简单(在本例中,您必须添加一个“build flag”),但还是需要我们团队的 DevOps 专家努力来确定问题,并在社区内寻求解决方案。还是那句话,如果您选择一个具有广泛社区支持或供应商“推送”的跨平台堆栈,就不用花费太多心思做权衡了。

选择移动开发框架时的开发考虑因素

在澄清了上述几个方面之后,让我们来看看可能推动您在原生与跨平台移动开发框架之间做出选择的几个因素。这些考虑因素的主要驱动力是您正在构建的应用程序类型、受众群体以及您计划支持的设备。我假设,作为最佳实践,您是以敏捷方式工作,那么对于所有的应用类型,您都应该有快速的发布周期,并且在所有场景中,最佳用户体验都是目标。

您在构建什么类型的应用?(受众、设备、复杂性)

首先,您选择哪种移动开发框架取决于您正在构建的应用的类型:

  • 面向员工 B2E 的企业应用,如审计工具或工厂维护应用。这些应用预计生命周期很长,在业务逻辑上可能会相当复杂,但您可能不需要立即支持新的 OS 功能。使用企业应用,您的公司可能有一个设备策略,规定所有应用将只在一个平台上开发。
  • 面向 B2C 客户的生产力应用,如购物应用。您可以预料到这些应用相当复杂,在应用商店中的生命周期很长,并且您希望性能尽可能高,因为您的公司名称将显示在应用商店评分旁边。您可以假设您需要瞄准市场上两个主要平台,目前是 iOS 和 Android。
  • 面向 B2C 的营销应用,例如用于营销活动或会议的应用。这些应用可能相对简单,但它们需要包装吸引眼球的功能。有一些例外,这些应用不需要在应用商店中停留很长时间,只在营销活动或活动期间出售。因为这些应用是面向消费者的,所以它们需要提供给市场上的所有平台,您甚至可以考虑 Web 版本。
  • 面向业务合作伙伴 B2B 的生产力应用,如批发订单跟踪应用或检验应用。从复杂性和用例的角度来看,这类应用非常类似于员工应用(相当复杂且寿命长),但两者主要的区别在于,您的公司将无法控制业务业务伙伴的设备策略,因此您需要针对多个平台构建应用。

您的团队对移动开发工具的熟悉程度如何?

在为移动应用项目进行人员配备时,您需要知道您的团队中有哪些移动开发技能。如果您的工作环境中有人精通某种语言或某些工具,那么一些跨平台移动开发框架可能会满足您的需求。例如,Xamarin 提供的工具可用于针对 Android 和 iOS 构建完全原生应用(从处理器架构的角度来看)。或者,React Web 开发者团队可能更习惯于构建 React Native 应用,而不是切换到原生开发语言。

除了编程语言的不同之外,许多跨平台移动开发框架的一个共同特点是支持“热重加载”或“实时重加载”开发方法。使用这种方法,因为更改不是直接编译到原生代码中,所以在开发环境中对文件进行更改时,应用将立即在用于开发的模拟器上更新。开发者喜欢这种功能。

无论您的团队熟悉哪种跨平台移动开发框架,都需要原生平台专家的指导。另外,如果跨平台堆栈没有为您的应用所需的功能提供开箱即用的插件,那么您可能需要依赖外部资源来实现这些功能。

您的应用的复杂性如何?

可以通过多种方式来衡量应用的复杂性,但要确定是采用原生还是跨平台移动开发堆栈,包含的框架/SDK 和设备特性的数量无疑是一种不错的衡量方法。有时候,应用复杂性是以“应用页面数量”(或屏幕)来衡量的,但您可能不希望这样衡量:一个小的应用可能需要复杂的平台集成,所以在解决方案设计阶段时就应该评估复杂性,这样,您的首席开发者或移动架构师将在移动平台的框架和功能方面做出技术决策,以交付所需的业务功能。

如果您的应用需要包括特定于平台的功能(例如,用于增强现实的 ARKit、用于机器学习的 CoreML 或 iOS 上的 ApplePay),那么您需要深入研究和验证是否值得构建一个跨平台应用,然后为这些技术采用或开发插件/桥接工具,或者完全采用原生方式。

另外,根据您将在全栈应用中使用的后端技术,您需要为数据库、通知或 API 集成添加集成 SDK。例如,如果您为 Salesforce 构建了一个应用,那么需要 Salesforce SDK。您打算使用的后端系统是否存在相应的 SDK,这是在决定是否采用某种特定技术时的关键因素。虽然所有原生工具都有对应的 SDK,但有些跨平台框架却没有。

您将在应用发布后如何支持应用?

向最终用户发布的所有软件都需要某种形式的支持,从修复缺陷到确保应用在新 OS 版本上正常运行。此外,移动应用的发展进程永无止境,您可能会迭代构建您的应用,随时间推移而不断添加功能。

如果您正在采用敏捷和 DevOps 最佳实践,那么修复缺陷和功能增强将是日常任务一部分,并由构建应用的开发团队在后续版本中解决。要减少解决缺陷所花费时间,共享代码库可能是一个很有帮助的方法,因为您的团队可以在一个地方修复问题。此外,如果您的公司决定将支持外包给单独的团队(不建议这样做),那么共享代码库将有助于减少分配给支持活动的资源。

您的应用的预期寿命是多长?

在开始开发您的下一个移动应用之前,必须考虑一下您期望该应用在市场中的保留时间。虽然与许多传统解决方案相比,移动应用的寿命确实很短,但我相信,为您的移动应用预期 3 年的寿命是比较现实的(在考虑进行重大重新编写之前),特别是在面向员工的企业环境中。

对于那些寿命很长的应用来说,关键是选择一种技术来确保您可以随时升级到移动平台提供的最新支持级别,但对于营销活动或事件应用来说,则不存在这个问题,因为在达到目后,这些应用可能会被重写或丢弃。虽然一些跨平台堆栈得到了大公司的支持,比如 Facebook 对 React Native 的支持,但是支持有可能随时会被取消,并且没有提前通知。当然,背靠足够庞大的社区,这个项目就会继续存在,但是如果您计划开发一个寿命很长的应用,跨平台堆栈很难成为一个卖点。

结束语

在本文中,我提供了在原生和混合移动开发框架之间进行选择时要考量的权衡和开发考虑因素。

曾经被称为“混合”的方法在最近几年逐渐演变成为更成熟的跨平台开发工具。早期的混合(基于 Web)方法的许多缺点已经成为过去,并且出现了更聪明的方法来提供跨平台的开发体验,从而交付性能卓越的原生代码。

在某些情况下,跨平台框架提供了比原生工具更高级的功能。想一想热重加载或实时重加载:虽然 Android 上的“即时运行”和 iOS 中的 SwiftUI 也能实现类似功能,但这个特性是原生平台从混合平台移植的。

跨平台开发堆栈非常强大。如您所知,能力越大,责任越大。过去,跨平台移动开发框架(尤其是基于 Web 的框架)主要用来加速初级开发者的技能提升过程,或者为 Web 开发者提供一条快速获得移动技能的途径。现在,随着当今移动操作系统日臻成熟,以及大量的功能和框架不断涌现,您需要高级的跨平台开发者和强大的原生开发指导,来交付利用设备最新功能的解决方案。

构建原生应用是一个零错误选择:您将有一个清晰的升级路径,在新操作系统发布后立即获得支持工具,并且无需进行任何性能权衡。 总之,在决定是使用原生还是跨平台移动开发框架时,这里提到的都是一些经验法则。涉及到技术决策时,没有非黑即白的答案,理想情况下,您应该始终记录所有推动您做出选择的因素:

  • 您是在构建一个严重依赖于原生框架的复杂移动应用,或是依赖最新技术的“同类首款”移动应用?那么使用原生堆栈进行构建。就这么简单。
  • 您是否正在构建针对商店的 B2C 应用,预期寿命将很长?使用原生堆栈进行构建。您的团队仍然可以尝试在跨平台工具中构建部分功能(例如,Airbnb 和 Facebook 一直在尝试以这种方式使用 React Native)。
  • 您是否做了功课,是否有信心维持合理的解决方案复杂性,以及代码复用、人员配置和上市时间是否是您做出抉择的主要推动因素?那么考虑跨平台框架,根据需要引入高级原生开发者/架构师/设计人员的指导。

成功的主要推动因素永远都是您的团队:虽然选择最合适的堆栈肯定会发挥重要作用,但一个充满动力且真正敏捷的团队才是成功的决定性因素。

本文翻译自:Deciding between native and cross-platform mobile frontend programming frameworks(2019-07-02)