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

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

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

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

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

該應用:

• 已被下載120萬次;

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

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

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

• 支持兩個代碼庫需要太多精力且難以管理。

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

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

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

以下是本文的主幹:

• 代碼行數與開發速度

• 架構

• 社區

• 性能

• 語言

• 還缺少什麼?

• 結論

1代碼行數與開發速度

第一階段我預估需要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。這會在所有用戶界面的窗體周圍顯示鮮豔的邊框。實際上這個功能用得並不如想象得多,但是當佈局出現問題時該功能確實非常有用。

2架構

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

• 看了幾遍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上的人解答的關於架構的問題中得到了許多幫助。這讓我想到了社區。

3社區

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

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

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

4性能

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

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

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

很期待看到其他人能給出怎樣的性能測試數據。

5語言

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

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

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

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

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

• 包管理很簡單。

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

6還缺少什麼?

沒有太多缺少的東西。在原生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包中獲取實時圖像。

7結論

讀到這裡,你肯定不會驚訝為什麼我如此讚美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的開發者。

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

“徵稿啦!”

CSDN 公眾號秉持著「與千萬技術人共成長」理念,不僅以「極客頭條」、「暢言」欄目在第一時間以技術人的獨特視角描述技術人關心的行業焦點事件,更有「技術頭條」專欄,深度解讀行業內的熱門技術與場景應用,讓所有的開發者緊跟技術潮流,保持警醒的技術嗅覺,對行業趨勢、技術有更為全面的認知。

如果你有優質的文章,或是行業熱點事件、技術趨勢的真知灼見,或是深度的應用實踐、場景方案等的新見解,歡迎聯繫 CSDN 投稿,聯繫方式:微信(guorui_1118,請備註投稿+姓名+公司職位),郵箱([email protected])。

相關推薦

推薦中...