跨平臺(tái)將終結(jié)
近些年,跨領(lǐng)域、跨平臺(tái)、跨專業(yè)類似的詞常常被提起,編程領(lǐng)域也不例外。總有人說跨平臺(tái)編程有多好多好,然而事實(shí)真的是這樣的嗎?跨平臺(tái)編程真的有那么方便嗎?

編譯 | 彎月 責(zé)編 | 張文
頭圖 | CSDN 下載自視覺中國
出品 | CSDN(ID:CSDNnews)原文:https://medium.com/swlh/the-end-of-cross-platform-as-we-know-it-dad658d96b8
跨平臺(tái)號(hào)稱“利用同一套代碼就可以為不同的平臺(tái)構(gòu)建應(yīng)用”,不僅可以節(jié)省時(shí)間和精力,還可以一勞永逸。這個(gè)概念聽起來很誘人,但實(shí)際上究竟如何呢?
近幾年,隨著 React Native、 Flutter 和 Xamarin 的興起,跨平臺(tái)的概念如火如荼。開發(fā)人員惶惶不可終日,仿佛不掌握跨平臺(tái)的技術(shù),就要被淘汰了。
雖然有很多公司都決定嘗試跨平臺(tái),但 React Native 的創(chuàng)建者 Facebook 宣布將其 iOS 應(yīng)用主頁(Newsfeed)換成 ComponentKit (一種創(chuàng)建于 Objective C 之上的框架)。他們大量借用了 React 的聲明式方法,然而在實(shí)現(xiàn)時(shí)卻采用了 Objective C,目的是為了發(fā)揮 iOS 架構(gòu)的真正力量。為了做到這一點(diǎn),他們甚至沒有采用 Swift。
2019 年,Airbnb 放棄了 React Native。這則新聞當(dāng)時(shí)在工程界引起了轟動(dòng),同時(shí)人們也不得不重新考慮跨平臺(tái)。同年,蘋果發(fā)布了 SwiftUI,這是一個(gè)聲明性的 UI 框架,旨在吸引新手開發(fā)人員再給 Swift 一次機(jī)會(huì)(Swift 現(xiàn)在已經(jīng)很穩(wěn)定了)。
如今,最常用的應(yīng)用仍然依賴于 C++ 或其他相關(guān)語言,例如 Android 的 JNI 和 iOS 的Objective C。
一、iOS 和 Android 兩大應(yīng)用市場(chǎng)的交叉需求沒有想象中多
首先,iOS 和 Android 兩大應(yīng)用市場(chǎng)服務(wù)的是不同的用戶群體。蘋果主打高端市場(chǎng),迎合的是高消費(fèi)用戶的需求。而 Android 系統(tǒng)為很多平臺(tái)廠商所采用。
蘋果主要靠硬件銷售,蘋果應(yīng)用開發(fā)人員的收入也主要來自應(yīng)用本身以及應(yīng)用內(nèi)銷售。而服務(wù)于消費(fèi)人群的 Android 應(yīng)用則以廣告為主要收入。
其次,蘋果對(duì)操作系統(tǒng)和硬件的控制更加嚴(yán)格,同時(shí)蘋果非常注重個(gè)人隱私。近來人們?cè)絹碓阶⒅仉[私,整個(gè)軟件生態(tài)系統(tǒng)的很大一部分推動(dòng)力都來自安全與隱私,因此向來注重個(gè)人隱私的蘋果也將繼續(xù)在企業(yè)移動(dòng)解決方案中占據(jù)主導(dǎo)地位。蘋果要求應(yīng)用必須獲得用戶許可才能發(fā)送廣告數(shù)據(jù)。
然而,Google 和 Facebook 的主要收入都來自廣告。而恰恰是 Facebook 推出了 React Native,Google 推出了 Flutter。
對(duì)于應(yīng)用開發(fā)人員來說,從一開始就要想清楚用戶定位。如果你不想靠廣告賺錢,那么可以專心開發(fā)蘋果應(yīng)用。在蘋果平臺(tái)上取得成功后,再考慮 Android。
再者,蘋果芯片進(jìn)一步穩(wěn)固了蘋果的地位。M1 芯片的成功將進(jìn)一步引誘開發(fā)人員使用蘋果的工具(Xcode、Playground 等),以及蘋果芯片加持的 Mac 開發(fā)蘋果應(yīng)用,因?yàn)樗麄兛梢匀珯?quán)控制底層的硬件。至少在最初階段,沒有人會(huì)考慮跨平臺(tái)的問題,而且開發(fā)人員和創(chuàng)業(yè)公司就不會(huì)錯(cuò)失這樣的優(yōu)勢(shì)。
雖然 Google 是一個(gè)強(qiáng)有力的競(jìng)爭(zhēng)者,但其在移動(dòng)領(lǐng)域的主要目的不是銷售軟件,而是用戶數(shù)據(jù)。人們開始逐步認(rèn)清,如果不贏得硬件的支持,就很難得到進(jìn)一步的發(fā)展。是否采用 Android 直接取決于底層的硬件制造商。
二、跨平臺(tái)并非創(chuàng)新
人們希望借助跨平臺(tái)一勞永逸,從多家平臺(tái)同時(shí)攫取利潤。因此,人們一次又一次地嘗試各種跨平臺(tái)工具,希望通過某一款工具解決平臺(tái)之間的各種問題。
然而,拋開底層的硬件,有關(guān)應(yīng)用的討論只是紙上談兵罷了。例如,蘋果和 Windows 這兩家的消費(fèi)群體之間本來就有著不可跨越的鴻溝。
此外,開發(fā)人員愿意嘗試跨平臺(tái)的另一個(gè)原因,不是因?yàn)榭缙脚_(tái)能夠創(chuàng)造更好的體驗(yàn),而是開發(fā)人員對(duì)專有平臺(tái)非常不滿。
跨平臺(tái)就像開源一樣唾手可得,項(xiàng)目的啟動(dòng)速度非常快,你只需要看一段入門教程,或花一百塊錢買一個(gè)模板,開發(fā)人員就可以開始構(gòu)建跨平臺(tái)應(yīng)用了,而且還有一大堆不可思議的功能:
跨平臺(tái)應(yīng)用可以輕易實(shí)現(xiàn)原生應(yīng)用很難做到的功能!(5 行代碼就可以實(shí)現(xiàn)原生的 3 個(gè)類!)然而,別忘了原生應(yīng)用擁有大量的定制潛力,更不用說你根本不知道跨平臺(tái)的 5 行代碼后面隱藏著什么。
跨平臺(tái)具有通用業(yè)務(wù)邏輯的獨(dú)特優(yōu)勢(shì),這是任何一家創(chuàng)業(yè)公司都無法抗拒的優(yōu)勢(shì)。許多收入超過 1000 萬美元的創(chuàng)業(yè)公司中,實(shí)際上負(fù)責(zé)維護(hù)通用代碼庫的移動(dòng)開發(fā)人員都只有一人,最終該代碼庫只能依賴于 GitHub 的貢獻(xiàn)者的支持。然而這些公司沒有意識(shí)到的是,通用的業(yè)務(wù)邏輯必須通過清晰的文檔和簡明的規(guī)范來維護(hù)。
如果這些創(chuàng)業(yè)公司足夠幸運(yùn),收入超過某個(gè)點(diǎn),就會(huì)開始考慮增長戰(zhàn)略,再加上應(yīng)用商店/游戲商店的評(píng)級(jí)不斷下降、投資者的壓力,就會(huì)迫使創(chuàng)始人重新考慮他們的初衷,也就是當(dāng)初那個(gè)快速而不堪一擊的解決方案。這就是為什么后來 LinkedIn、Facebook、Airbnb 以及其他眾多應(yīng)用重新采用了原生開發(fā)的原因。
然而,新興創(chuàng)業(yè)公司的數(shù)量從未減少,跨平臺(tái)開發(fā)人員的市場(chǎng)也不會(huì)枯竭。但是,我們需要認(rèn)清現(xiàn)實(shí):C++(或Objective C及其變體)或 Java 開發(fā)人員在未來幾十年內(nèi)依然炙手可熱。但如果你要蹚跨平臺(tái)這趟渾水,那么請(qǐng)做好心理準(zhǔn)備每隔 3-5 年就面臨一次大洗底的危機(jī)。
三、跨平臺(tái)真的是捷徑嗎?
跨平臺(tái)帶來了各種混亂。
如今的跨平臺(tái)產(chǎn)品都聲稱能夠生成百分百的原生代碼,例如 Xamarin、React Native 和 Flutter(可能 Flutter 并不能生成百分百的原生代碼?) 都承諾可百分百在原生環(huán)境中運(yùn)行。
它們與過去在瀏覽器和 HTML5 中運(yùn)行的 PWA 不同。
然而,從設(shè)計(jì)的角度來看,每個(gè)跨平臺(tái)工具集都違背了代碼的基本組織原則。常見的跨平臺(tái)工具都由 500 多個(gè)軟件包組成,這些軟件包的來源并非完全可靠,而且很多都不在開發(fā)人員控制的服務(wù)器范圍內(nèi),因此在移動(dòng)開發(fā)中采用這些跨平臺(tái)工具所承擔(dān)的風(fēng)險(xiǎn)可想而知。
人們被跨平臺(tái)工具所吸引的主要原因在于,這些工具提供了更容易被初學(xué)者理解的高層抽象。而且它們?nèi)诤狭瞬煌讓釉?API 之間的差異。
假設(shè)跨平臺(tái)提供的某個(gè)函數(shù) F 融合了原生 iOS 和 Android 中的以下兩個(gè)函數(shù):
iOS: function f (int a, int b, int c)
Android: function f (int a, int b, intp, int q, int r)
該跨平臺(tái)提供的函數(shù)如下:
function f (int a, int b)
如果你想同時(shí)兼顧這兩個(gè)平臺(tái),則必須搞清楚原生代碼如何處理 int c、int p、int q、int r。
曾經(jīng)由于現(xiàn)有 Flutter notification 功能的不足,開發(fā)人員不得不開發(fā)了一系列插件:
Dart
iOS plugin
Android plugin
由于 Flutter 開發(fā)人員只熟悉 XCode / Android Studio,而并不熟悉 Objective C / Kotlin API,因此出現(xiàn)了很多錯(cuò)誤。
雖然在移動(dòng)應(yīng)用開發(fā)中采用跨平臺(tái)可以節(jié)約大約 20% 的開發(fā)時(shí)間,然而軟件包管理的工作卻會(huì)吞噬維護(hù)人員 70% 以上的時(shí)間。
ReactNative 應(yīng)用會(huì)遇到一些非常嚴(yán)重的功能與性能相關(guān)的問題,但這些問題往往需要等到開發(fā)后期才能被發(fā)現(xiàn)。
此外,與原生開發(fā)的 IPA 和 APK 相比,flutter 應(yīng)用的規(guī)模往往過大。
有人曾為了解決 Flutter Equatable 實(shí)現(xiàn)的兼容性問題,而修改了 70 多個(gè) DART 文件。直到后來才發(fā)現(xiàn)背后的真正原因:早期的哈希算法在遇到對(duì)象內(nèi)可交換值的屬性時(shí),產(chǎn)生了相同的哈希!
具體來說,早期的實(shí)現(xiàn)有 bug,以下對(duì)象會(huì)產(chǎn)生相同的哈希,除非你明確重寫 Equatable 哈希函數(shù),該函數(shù)在 1.0 之前從來不是強(qiáng)制性要求!
想象一下,你需要檢查 500 多個(gè)軟件包中是否存在相等性檢查漏洞……
當(dāng)問及為什么要在數(shù)據(jù)密集型應(yīng)用中采用 Flutter 時(shí),有架構(gòu)師回答說:“管理層認(rèn)為,敏捷的目標(biāo)之一是盡量避免不會(huì)產(chǎn)生價(jià)值的工作,例如文檔。通用代碼庫就是我們的文檔,以及唯一的可靠信息源。”
造成這些混亂的主要原因,就是平臺(tái)之間的兼容性問題。實(shí)際上,跨平臺(tái)框架試圖解決的不同平臺(tái)的兼容性問題是本質(zhì)上的問題,盡管跨平臺(tái)框架做出了大量努力試圖消弭不同平臺(tái)之間的差異,但一些本質(zhì)上的差異是無法避免的。例如某些平臺(tái)的特有功能,以及一些嚴(yán)重依賴硬件實(shí)現(xiàn)的功能。
通常,跨平臺(tái)框架需要為每個(gè)平臺(tái)提供原生的插件,而這些正是出現(xiàn)混亂的地方,也往往是各種錯(cuò)誤層出不窮的地方。如果你的應(yīng)用程序嚴(yán)重依賴于某個(gè)平臺(tái)特有的功能,或者嚴(yán)重依賴硬件實(shí)現(xiàn),那么顯然跨平臺(tái)并不是個(gè)好主意。
四、跨平臺(tái)的不可靠性
這不是跨平臺(tái)固有的問題,而是因?yàn)樗峭ㄟ^開源代碼共享實(shí)現(xiàn)的。
這個(gè)問題背后的原因有兩個(gè):
GitHub(以及其他平臺(tái))上的內(nèi)容并沒有經(jīng)過精挑細(xì)選,平臺(tái)本身也需要對(duì)當(dāng)?shù)胤韶?fù)責(zé),因此平臺(tái)會(huì)由于法規(guī)變動(dòng)而刪除某些內(nèi)容。
無論代碼庫的規(guī)模有多大,代碼庫主人對(duì)貢獻(xiàn)的代碼擁有無上的權(quán)利。例如在區(qū)塊鏈?zhǔn)澜缰校a庫所有者早已聲名狼藉,因?yàn)閯?chuàng)建代碼庫的人在制定硬幣發(fā)行規(guī)則上擁有絕對(duì)的話語權(quán)。
因此,許多公司在使用開源代碼的時(shí)候,都需要修復(fù)很多 bug 。各個(gè)公司雇用了開發(fā)人員來維護(hù)整個(gè)社區(qū),并根據(jù)受歡迎程度來發(fā)布功能。
然而,對(duì)于跨平臺(tái)提供商而言,情況并非如此。實(shí)際上,他們沒有精力去修復(fù)嚴(yán)重錯(cuò)誤或關(guān)鍵性的提升請(qǐng)求,就算他們對(duì) GitHub 上報(bào)告問題不聞不問,也不會(huì)造成任何后果。
如果 Flutter 出現(xiàn)重大 bug,Google 也不會(huì)面臨 Pixel 銷量或搜索流量下滑。同理,如果 React Native 缺乏某個(gè)功能,F(xiàn)acebook 的廣告收入也不會(huì)縮水。
如果 Android 或 Kotlin 出現(xiàn)嚴(yán)重漏洞,那么 Google 就會(huì)遭受損失,因?yàn)?Google 獲取了許可收入;同樣,如果 iOS 或 Swift 出現(xiàn)嚴(yán)重漏洞,蘋果的 iPhone 銷量也會(huì)下滑。
因此,與那些為發(fā)布修補(bǔ)程序而奮戰(zhàn)到半夜的原生平臺(tái)所有者不同,**跨平臺(tái)開發(fā)商對(duì)開發(fā)人員的要求不屑一顧。**即便你填寫了問題,跨平臺(tái)開發(fā)商也只會(huì)忽視,并不會(huì)采取任何措施。此外,由于沒有文檔,開發(fā)人員學(xué)習(xí)的唯一方法就是更深入地研究軟件包/庫代碼,解決問題并交付應(yīng)用。然而,對(duì)于寄希望于跨平臺(tái)之上的開發(fā)人員,最后卻需要花費(fèi)大量時(shí)間來改 bug 和請(qǐng)求添加某個(gè)新功能。
五、該如何選擇?
想必現(xiàn)在你已經(jīng)知道,跨平臺(tái)并不是解決一切問題的銀彈,也并沒有某些文章吹噓的那么好。那么在開發(fā)一個(gè)新的應(yīng)用時(shí),究竟該如何選擇呢?
開發(fā)周期短;
開發(fā)費(fèi)用低廉;
開發(fā)人員容易招聘。
而缺點(diǎn)是:
很難找到精通框架的人;
框架本身的不成熟;
性能問題;
難以處理平臺(tái)和硬件固有特性。
我們可以總結(jié)出幾條原則,供你在選擇開發(fā)框架時(shí)參考:
如果你的應(yīng)用需要使用大量平臺(tái)固有特性,或者需要大量定制邏輯,那就不要考慮跨平臺(tái)。例如相機(jī)應(yīng)用,需要依靠設(shè)備上的傳感器工作的應(yīng)用,或者需要結(jié)合應(yīng)用程序商店的應(yīng)用等。老老實(shí)實(shí)選擇原生發(fā)吧。
如果你的應(yīng)用有性能、功耗等要求,顯然跨平臺(tái)也不是好的選擇。
如果你的應(yīng)用程序希望長期發(fā)展,并且不想在規(guī)模擴(kuò)大后重寫,那么應(yīng)該在能夠承受的范圍內(nèi),盡量從一開始就選擇原生開發(fā),這樣可以有效避免跨平臺(tái)框架的不可靠性。
實(shí)際上,跨平臺(tái)只適合創(chuàng)業(yè)公司非硬件相關(guān)的應(yīng)用程序(如社交應(yīng)用),避免跨平臺(tái)的劣勢(shì),同時(shí)利用其開發(fā)周期短、費(fèi)用低廉、人員容易招聘的優(yōu)勢(shì),迅速建立原型并推出到市場(chǎng)進(jìn)行驗(yàn)證,然后快速迭代。而對(duì)于其他情況,個(gè)人認(rèn)為選擇原生應(yīng)用會(huì)更好。
