【编者按】近些年,跨领域、跨平台、跨专业类似的词常常被提起,编程领域也不例外。总有人说跨平台编程有多好多好,然而事实真的是这样的吗?跨平台编程真的有那么方便吗?
编译 | 弯月 责编 | 张文
头图 | CSDN 下载自视觉中国
出品 | CSDN(ID:CSDNnews)
跨平台号称“利用同一套代码就可以为不同的平台构建应用”,不仅可以节省时间和精力,还可以一劳永逸。这个概念听起来很诱人,但实际上究竟如何呢?
近几年,随着 React Native、 Flutter 和 Xamarin 的兴起,跨平台的概念如火如荼。开发人员惶惶不可终日,仿佛不掌握跨平台的技术,就要被淘汰了。
虽然有很多公司都决定尝试跨平台,但 React Native 的创建者 Facebook 宣布将其 iOS 应用主页(Newsfeed)换成 ComponentKit (一种创建于 Objective C 之上的框架)。他们大量借用了 React 的声明式方法,然而在实现时却采用了 Objective C,目的是为了发挥 iOS 架构的真正力量。为了做到这一点,他们甚至没有采用 Swift。
2019 年,Airbnb 放弃了 React Native。这则新闻当时在工程界引起了轰动,同时人们也不得不重新考虑跨平台。同年,苹果发布了 SwiftUI,这是一个声明性的 UI 框架,旨在吸引新手开发人员再给 Swift 一次机会(Swift 现在已经很稳定了)。
如今,最常用的应用仍然依赖于 C++ 或其他相关语言,例如 Android 的 JNI 和 iOS 的Objective C。
跨平台应用有其固有的缺点。如今,随着市场的变化,跨平台是时候需要展开自救了,否则将面临消亡危机。而造成如今这个局面的主要原因有以下几个。
一、iOS 和 Android 两大应用市场的交叉需求没有想象中多
首先,iOS 和 Android 两大应用市场服务的是不同的用户群体。苹果主打高端市场,迎合的是高消费用户的需求。而 Android 系统为很多平台厂商所采用。
苹果主要靠硬件销售,苹果应用开发人员的收入也主要来自应用本身以及应用内销售。而服务于消费人群的 Android 应用则以广告为主要收入。
其次,苹果对操作系统和硬件的控制更加严格,同时苹果非常注重个人隐私。近来人们越来越注重隐私,整个软件生态系统的很大一部分推动力都来自安全与隐私,因此向来注重个人隐私的苹果也将继续在企业移动解决方案中占据主导地位。苹果要求应用必须获得用户许可才能发送广告数据。
然而,Google 和 Facebook 的主要收入都来自广告。而恰恰是 Facebook 推出了 React Native,Google 推出了 Flutter。
对于应用开发人员来说,从一开始就要想清楚用户定位。如果你不想靠广告赚钱,那么可以专心开发苹果应用。在苹果平台上取得成功后,再考虑 Android。
再者,苹果芯片进一步稳固了苹果的地位。M1 芯片的成功将进一步引诱开发人员使用苹果的工具(Xcode、Playground 等),以及苹果芯片加持的 Mac 开发苹果应用,因为他们可以全权控制底层的硬件。至少在最初阶段,没有人会考虑跨平台的问题,而且开发人员和创业公司就不会错失这样的优势。
虽然 Google 是一个强有力的竞争者,但其在移动领域的主要目的不是销售软件,而是用户数据。人们开始逐步认清,如果不赢得硬件的支持,就很难得到进一步的发展。是否采用 Android 直接取决于底层的硬件制造商。
二、跨平台并非创新
人们希望借助跨平台一劳永逸,从多家平台同时攫取利润。因此,人们一次又一次地尝试各种跨平台工具,希望通过某一款工具解决平台之间的各种问题。
然而,抛开底层的硬件,有关应用的讨论只是纸上谈兵罢了。例如,苹果和 Windows 这两家的消费群体之间本来就有着不可跨越的鸿沟。
此外,开发人员愿意尝试跨平台的另一个原因,不是因为跨平台能够创造更好的体验,而是开发人员对专有平台非常不满。
跨平台就像开源一样唾手可得,项目的启动速度非常快,你只需要看一段入门教程,或花一百块钱买一个模板,开发人员就可以开始构建跨平台应用了,而且还有一大堆不可思议的功能:
跨平台应用可以轻易实现原生应用很难做到的功能!(5 行代码就可以实现原生的 3 个类!)然而,别忘了原生应用拥有大量的定制潜力,更不用说你根本不知道跨平台的 5 行代码后面隐藏着什么。
跨平台具有通用业务逻辑的独特优势,这是任何一家创业公司都无法抗拒的优势。许多收入超过 1000 万美元的创业公司中,实际上负责维护通用代码库的移动开发人员都只有一人,最终该代码库只能依赖于 GitHub 的贡献者的支持。然而这些公司没有意识到的是,通用的业务逻辑必须通过清晰的文档和简明的规范来维护。
如果这些创业公司足够幸运,收入超过某个点,就会开始考虑增长战略,再加上应用商店/游戏商店的评级不断下降、投资者的压力,就会迫使创始人重新考虑他们的初衷,也就是当初那个快速而不堪一击的解决方案。这就是为什么后来 LinkedIn、Facebook、Airbnb 以及其他众多应用重新采用了原生开发的原因。
然而,新兴创业公司的数量从未减少,跨平台开发人员的市场也不会枯竭。但是,我们需要认清现实:C++(或Objective C及其变体)或 Java 开发人员在未来几十年内依然炙手可热。但如果你要蹚跨平台这趟浑水,那么请做好心理准备每隔 3-5 年就面临一次大洗底的危机。
三、跨平台真的是捷径吗?
跨平台带来了各种混乱。
如今的跨平台产品都声称能够生成百分百的原生代码,例如 Xamarin、React Native 和 Flutter(可能 Flutter 并不能生成百分百的原生代码?) 都承诺可百分百在原生环境中运行。
它们与过去在浏览器和 HTML5 中运行的 PWA 不同。
然而,从设计的角度来看,每个跨平台工具集都违背了代码的基本组织原则。常见的跨平台工具都由 500 多个软件包组成,这些软件包的来源并非完全可靠,而且很多都不在开发人员控制的服务器范围内,因此在移动开发中采用这些跨平台工具所承担的风险可想而知。
人们被跨平台工具所吸引的主要原因在于,这些工具提供了更容易被初学者理解的高层抽象。而且它们融合了不同底层原生 API 之间的差异。
假设跨平台提供的某个函数 F 融合了原生 iOS 和 Android 中的以下两个函数:
iOS: function f (int a, int b, int c)
Android: function f (int a, int b, intp, int q, int r)
该跨平台提供的函数如下:
function f (int a, int b)
如果你想同时兼顾这两个平台,则必须搞清楚原生代码如何处理 int c、int p、int q、int r。
曾经由于现有 Flutter notification 功能的不足,开发人员不得不开发了一系列插件:
- Dart
- iOS plugin
- Android plugin
由于 Flutter 开发人员只熟悉 XCode / Android Studio,而并不熟悉 Objective C / Kotlin API,因此出现了很多错误。
虽然在移动应用开发中采用跨平台可以节约大约 20% 的开发时间,然而软件包管理的工作却会吞噬维护人员 70% 以上的时间。
ReactNative 应用会遇到一些非常严重的功能与性能相关的问题,但这些问题往往需要等到开发后期才能被发现。
此外,与原生开发的 IPA 和 APK 相比,flutter 应用的规模往往过大。
有人曾为了解决 Flutter Equatable 实现的兼容性问题,而修改了 70 多个 DART 文件。直到后来才发现背后的真正原因:早期的哈希算法在遇到对象内可交换值的属性时,产生了相同的哈希!
具体来说,早期的实现有 bug,以下对象会产生相同的哈希,除非你明确重写 Equatable 哈希函数,该函数在 1.0 之前从来不是强制性要求!
对象A:
x = 3,y = 4
对象B:
x = 4,y = 3
想象一下,你需要检查 500 多个软件包中是否存在相等性检查漏洞……
当问及为什么要在数据密集型应用中采用 Flutter 时,有架构师回答说:“管理层认为,敏捷的目标之一是尽量避免不会产生价值的工作,例如文档。通用代码库就是我们的文档,以及唯一的可靠信息源。”
造成这些混乱的主要原因,就是平台之间的兼容性问题。实际上,跨平台框架试图解决的不同平台的兼容性问题是本质上的问题,尽管跨平台框架做出了大量努力试图消弭不同平台之间的差异,但一些本质上的差异是无法避免的。例如某些平台的特有功能,以及一些严重依赖硬件实现的功能。
通常,跨平台框架需要为每个平台提供原生的插件,而这些正是出现混乱的地方,也往往是各种错误层出不穷的地方。如果你的应用程序严重依赖于某个平台特有的功能,或者严重依赖硬件实现,那么显然跨平台并不是个好主意。
四、跨平台的不可靠性
这不是跨平台固有的问题,而是因为它是通过开源代码共享实现的。
这个问题背后的原因有两个:
- GitHub(以及其他平台)上的内容并没有经过精挑细选,平台本身也需要对当地法律负责,因此平台会由于法规变动而删除某些内容。
- 无论代码库的规模有多大,代码库主人对贡献的代码拥有无上的权利。例如在区块链世界中,代码库所有者早已声名狼藉,因为创建代码库的人在制定硬币发行规则上拥有绝对的话语权。
因此,许多公司在使用开源代码的时候,都需要修复很多 bug 。各个公司雇用了开发人员来维护整个社区,并根据受欢迎程度来发布功能。
然而,对于跨平台提供商而言,情况并非如此。实际上,他们没有精力去修复严重错误或关键性的提升请求,就算他们对 GitHub 上报告问题不闻不问,也不会造成任何后果。
如果 Flutter 出现重大 bug,Google 也不会面临 Pixel 销量或搜索流量下滑。同理,如果 React Native 缺乏某个功能,Facebook 的广告收入也不会缩水。
如果 Android 或 Kotlin 出现严重漏洞,那么 Google 就会遭受损失,因为 Google 获取了许可收入;同样,如果 iOS 或 Swift 出现严重漏洞,苹果的 iPhone 销量也会下滑。
因此,与那些为发布修补程序而奋战到半夜的原生平台所有者不同,**跨平台开发商对开发人员的要求不屑一顾。**即便你填写了问题,跨平台开发商也只会忽视,并不会采取任何措施。此外,由于没有文档,开发人员学习的唯一方法就是更深入地研究软件包/库代码,解决问题并交付应用。然而,对于寄希望于跨平台之上的开发人员,最后却需要花费大量时间来改 bug 和请求添加某个新功能。
五、该如何选择?
想必现在你已经知道,跨平台并不是解决一切问题的银弹,也并没有某些文章吹嘘的那么好。那么在开发一个新的应用时,究竟该如何选择呢?
先来总结一下跨平台的优点和缺点。
跨平台的优点主要有:
- 开发周期短;
- 开发费用低廉;
- 开发人员容易招聘。
而缺点是:
- 很难找到精通框架的人;
- 框架本身的不成熟;
- 性能问题;
- 难以处理平台和硬件固有特性。
我们可以总结出几条原则,供你在选择开发框架时参考:
- 如果你的应用需要使用大量平台固有特性,或者需要大量定制逻辑,那就不要考虑跨平台。例如相机应用,需要依靠设备上的传感器工作的应用,或者需要结合应用程序商店的应用等。老老实实选择原生发吧。
- 如果你的应用有性能、功耗等要求,显然跨平台也不是好的选择。
- 如果你的应用程序希望长期发展,并且不想在规模扩大后重写,那么应该在能够承受的范围内,尽量从一开始就选择原生开发,这样可以有效避免跨平台框架的不可靠性。
实际上,跨平台只适合创业公司非硬件相关的应用程序(如社交应用),避免跨平台的劣势,同时利用其开发周期短、费用低廉、人员容易招聘的优势,迅速建立原型并推出到市场进行验证,然后快速迭代。而对于其他情况,个人认为选择原生应用会更好。
参考链接:https://medium.com/swlh/the-end-of-cross-platform-as-we-know-it-dad658d96b8