1. 程式人生 > >將 75000 行原生 iOS 應用程式移植到 Flutter 後,結果太驚訝!

將 75000 行原生 iOS 應用程式移植到 Flutter 後,結果太驚訝!

640?wx_fmt=gif

【CSDN編者按】很少有文章,介紹如何將大型應用,移植到Flutter。而本文的作者——一位來自澳洲的Native iOS & Flutter的開發者,嘗試這樣做了,結果讓他十分驚訝。到底是什麼情況?一起來看文章吧!

640?wx_fmt=jpeg

澳大利亞有一個名為Easy Diet Diary的原生iOS應用程式。

該應用:

• 已被下載120萬次;

• 用Objective-C和Swift編寫,後端是Amazon AWS;

• 程式碼統計工具CLOC,報告該應用包含75,000行程式碼。

我在這家小公司工作了很長一段時間,他們的任務列表上一直有個安卓版本,但我們一直沒有開發,因為:

• 支援兩個程式碼庫需要太多精力且難以管理。

• 跨平臺開發的主要選擇Xamarin和React Native都有重要缺陷(這是另一個故事)。

最後,我們選擇進入Flutter的世界!

Flutter的速度很快,並且可以保證使用者介面體驗,而且一切都與原生應用沒有區別(特別是有了2018年9月加入的iOS小窗體之後)。

以下是本文的主幹:

• 程式碼行數與開發速度

• 架構

• 社群

• 效能

• 語言

• 還缺少什麼?

• 結論

640?wx_fmt=png

程式碼行數與開發速度

第一階段我預估需要6個人月。但是,專案進度居然領先了!對我來說,這簡直太不可思議了。

為什麼?

Flutter的佈局並不是像iOS那樣,使用的不是Storyboard,或者像安卓那樣使用XML,而是在程式碼中將窗體組合成窗體樹,即可建立應用程式的使用者介面。這對我來說聽起來有點可怕,但是我做了嘗試,雖然花了一些時間來習慣,但不久我就可以靈活地使用這些窗體樹了。

然後,大約第一個階段進展到第三個月的時候,發生了一件很奇怪的事情。隨著我越來越熟練、越來越快地移植功能,專案中的程式碼行卻開始迅速減少了。這很奇怪,因為我移植的業務邏輯數量非常龐大,這些邏輯在程式碼數量上的比例幾乎是一比一。

事情的真相是,我可以通過建立類和編寫函式來重用使用者介面部分的程式碼,這比使用原生iOS更容易。通常,我可以利用幾個額外的引數,簡單地重構使用者介面的窗體就可以重用它們。如果這樣不行,我還可以簡單地在現有的窗體周圍再包上另一個窗體,就可以實現需要的行為了。這簡直太讚了!

最終我預計程式碼行數將少於30,000(而原生iOS版本為75,000行)。當然,原生iOS版本包含一些雖然當時開發了最終卻被取代或未被使用的程式碼。我估計未使用的程式碼佔15,000行。換句話說,需要移植的程式碼量為60,000行。

因此,總的來說,Flutter的程式碼量只有原生iOS原有程式碼的一半!

此外,Flutter專案不包含任何Storyboard XML。Storyboard中有很多XML。原生iOS專案包含:

• 15個Storyboard;

• 47個Nib檔案;

• 92個View Controllers。

我與Storyboard鬥爭了很多年,一直在嘗試遵循最佳實踐,最後感覺在Flutter中構建使用者介面非常自由而且速度很快。

以前我沒有意識到自己的大部分時間都用在了編寫與使用者介面相關的程式碼,還要忍受大量的Storyboard和自動佈局限制。

我無數次聽人說應該將使用者介面佈局與程式碼分開,我非常同意,但就我的Flutter經驗而言,這一點未必是真的。而且關於使用者介面分離的這種概念也不僅僅是原生iOS的最佳實踐。

我記得自己在微軟WPF中與XML作鬥爭,也見過Quora上有人問《為什麼安卓使用XML來定義使用者介面而不僅僅是Java程式碼?》

Storyboard是一種自上至下的佈局方式(適用於桌面應用程式),而窗體採用自下而上的方法,在構建移動應用程式時,窗體可以極大地簡化程式設計。我聽說這種方式類似於React Native和CSS flex-boxes的佈局方式。Wm Leler在Hacker Noon上發表的文章《Flutter帶來了哪些創新》很好地解釋了這個問題。

以下方式對於利用窗體構建使用者介面很有幫助性:

• 大多數情況下,Flutter中支援狀態的“熱過載”功能可以在幾秒鐘內,將程式碼更改無縫地整合到正在執行的應用程式中;

• Android Studio的快捷鍵Alt + Enter可以插入或刪除使用者介面的窗體(行、列或容器)。請檢視這篇文章《使用Android Studio開發Flutter應用程式的小竅門》(https://medium.com/@liewjuntung/tips-on-using-android-studio-to-develop-flutter-apps-9e42c047b7f4)。

我覺得VS Code中應該有類似的東西。這似乎微不足道,但我覺得這個快捷鍵十分有用。使用熱過載和Alt + Enter,我可以在幾分鐘內做好一個畫面,甚至可以在使用者介面上做實驗。

• 將debugPaintSizeEnabled設定為true。這會在所有使用者介面的窗體周圍顯示鮮豔的邊框。實際上這個功能用得並不如想象得多,但是當佈局出現問題時該功能確實非常有用。

640?wx_fmt=png

架構

我在選擇架構時做了如下幾件事:

• 看了幾遍Brian Egan的這個演講《保持簡單、有狀態:Flutter應用的架構》(https://www.youtube.com/watch?v=zKXz3pUkw9A&feature=youtu.be)。

• 讀了幾遍Eric Windmill的這篇文章《有效地使用Flutter的繼承窗體》(https://ericwindmill.com/posts/inherited_widget/)。

• 閱讀Flutter架構示例:http://fluttersamples.com/。

最終,我按照Eric的建議使用了一種名為Lifting State Up的架構模式,這是Redux的第一步,看起來非常誘人。然而,Redux對我來說遙不可及。由於開發時間緊迫,學習和嘗試Redux似乎太令人生畏了。

一路走來,我從Stack Overflowers上的人解答的關於架構的問題中得到了許多幫助。這讓我想到了社群。

640?wx_fmt=png

社群

有關Flutter的開源社群非常多元化,並且非常樂於助人,讓我看到了人類的希望(特別是在這些瘋狂的時期)。

舉個例子,當時我正在使用Romain Rastel編寫的flutter_slidable軟體包,而且我還提了一個改善建議,僅僅48小時之內他就實現了一個比我想象的更好的解決方案......類似這樣的事情比比皆是。

我唯一遺憾的是,我一直忙於移植工作,與我收到的幫助相比,我給予別人的遠遠不夠。

640?wx_fmt=png

效能

總的來說,參加了內部測試的使用者對Flutter的“活潑”非常滿意。在同一臺iOS裝置上,同時並排執行iOS應用與Flutter應用時,並沒有看到效能明顯下降。

我們的應用沒有很多需要大量圖形的任務,但有一個功能需要從數百個JSON檔案讀取資料,然後對該資料進行一系列浮點計算,在該功能中Flutter的應用明顯更快。

我沒有花時間去研究導致差異的究竟是是讀取檔案的功能、還是JSON解析或者是日期處理等等,因此我無法做出類別上的判斷,但我感覺這無疑是Flutter桂冠上的一顆明珠。

很期待看到其他人能給出怎樣的效能測試資料。

640?wx_fmt=png

語言

Flutter使用Dart,這種語言已經在Google之外萎靡不振,直到最近才隨著Flutter再次興起。

然而,這門語言很成熟且易於學習。幸運的是,我在加入Dart隊伍時,擁有更強大的型別功能的Dart 2.0剛剛出現,所以無需再在程式碼中不斷地敲“new”關鍵字了。

Dart可能沒有Swift和Kotlin所擁有的Null和非Null型別,但我很喜歡它的簡單性。 例如:

• 以下劃線開頭的函式為私有;

• 自動格式化意味著不必再頭疼我的習慣問題——我喜歡在末尾加上逗號將引數分行;

• 包管理很簡單。

還有很多很多。我喜歡這些功能,也許其他人可能不喜歡。對我而言,最重要的是我可以更快地(用奇怪但很愉悅的方式)實現功能。

640?wx_fmt=png

還缺少什麼?

沒有太多缺少的東西。在原生iOS應用中:

• 我在XCode中使用了很多Targets,並結合一堆#define建立bundle ID不同的各種版本的應用。我不知道在Flutter中怎麼處理這個問題;

• 我在iOS中使用了一個很好的第三方日誌框架,叫做CocoaLumberjack。還沒找到能代替它的東西;

• 我使用UIKit框架中的WKWebView來載入並渲染本地的HTML檔案(如使用條款、隱私政策等)。我在Flutter中沒找到正確的包來實現這個功能。最後只能使用一個包HTML2MD將HTML轉換成Markdown再使用另一個包flutter_markdown來渲染;

• 我使用AVFoundation框架,在單一的全屏檢視中實現條碼掃描、QR二維碼掃描和拍照。在Flutter中我還不能如此細緻地進行控制,雖然它的Camera包很適合拍照,另一個由facundomedica編寫的包fast_qr_reader_view很適合掃描條碼。在安卓裝置上,這個包與Firebase的ML Kit配合從Camera包中獲取實時影象。

640?wx_fmt=png

結論

讀到這裡,你肯定不會驚訝為什麼我如此讚美Flutter。到目前為止:

• Flutter的使用者介面幾乎與原生安卓和原生iOS的使用者介面沒有區別;

• 得益於Flutter使用者介面的構建方式,利用Flutter製作新功能比原生程式碼更快;

• 測試沒有收到有關效能劣化的報告;

• iOS版和安卓版之間的程式碼共享目前達到了90%以上。我還沒有整合蘋果的HealthKit或Google Fit,但我覺得共享率應該不會下降太多。

儘管Flutter還不成熟(2018年5月才釋出正式版),但對於我來說它已經足夠強壯了。

我遇到的唯一問題就是Dart同步讀取目錄的函式List Sync在最近的一次釋出中出現了崩潰。我將它加到了Flutter在Github上的程式碼庫中,然後改用非同步版本。

原文:https://medium.com/flutter-community/porting-a-75-000-line-native-ios-app-to-flutter-57c6571c57b4

作者:Gary Hunter,Native iOS & Flutter的開發者。

譯者:彎月,責編:胡巍巍

推薦閱讀:

640?wx_fmt=gif

640?wx_fmt=gif