Flutter 教學:從零開始 一步一步學會使用跨平台套件 Flutter


本篇原文(標題:EntrenaPro — From Zero To Flutter )刊登於作者 Medium,由 Muhammad Ahmed 所著,並授權翻譯及轉載。

此篇文章旨在分享我的歷程、並啟發其他科技公司選擇使用 Flutter。

開始的契機

這一切源自於一位過去與我工作過的專案主管 Peri。當時,他問我是否有可能在四個月內為 EntrenaPro 的 iOS 和 Android App 重做雛形。他分享了專案的 invision 連結給我。而且他對我們使用哪種跨平台套件持開放態度,只要可以幫助我們快速完成就可以。EntrenaPro 這個 App 為教練和運動員提供平台,以規劃多於 40 種西班牙盛行的運動個人或是公開運動課程,

Flutter 簡介

在 2015 年看過上面這段影片後,我非常喜歡它的概念,但一直沒有機會嘗試使用。直到遇上這個時間緊迫的專案,而且這個 App 需要建置於兩個平台上,我就趁著可以自由選擇套件的機會,選擇了 Flutter。自 2015 年到今天,Flutter 已經發展了一段時間。

為什麼我選擇了 Flutter,而不是 React Native

我完全沒有用過 Flutter,而 React Native 也只是用過一個星期(我嘗試過構建一個 App,但最後沒有完成),當要從兩者之中選擇時,我考慮過這些因素:

  1. 交付專案的速度、開發人員的產能,我在許多地方閱讀過相關議題。
  2. 當 Flutter 繪製畫面時,它使用自己的表層,然後將 Widgets(視圖、按鈕、文字)繪在表層上,所以 Flutter 可以控制視窗上的每個像素。Flutter 並非使用原生 OEM Widget 的;而 React Native 則是使用 OEM Widget 在畫面上繪製元件。這表示當你使用 Flutter 來繪製 Widgets 時,不論平台的原生 OEM Widget 是否支援,繪畫出來的 Widgets 在每個平台上看起來都會是一模一樣的。而且,Flutter 還具有平台 Widget 感測與平台物理感測。
  3. Flutter 使用 Dart 語言,它具有資料型別(之前是非必要的,但是從 2.0 版開始改為強資料型別)。我是從 Java/Swift 語言開始寫程式的,所以對我來說 Dart 比 Javascript 還要吸引。我讀了使用 TypeScript(我也愛這個語言)或是 Flow 的工程師所寫的文章,但是它比建於語言中的資料型別來的好,幫助了 IDE 了解程式碼,並讓 IDE 能夠提供程式碼補齊建議。
  4. 我偏心於 Google 的產品。

我不希望讓你覺的 React Native 就是不好。無庸置疑地,許多成功的 App 都是以 React Native 來開發,而且它們看起來棒極了。但是我對 React Native 的六天初接觸並不太好(試試著建立一個陰影參數為 x = 0、y = 2、blur = 6、spread = 0 的視圖、並在兩個平台上測試,你就會明白我的意思),所以我就試試這個新玩意。Flutter 與 React Native 以不同的方式提供跨平台開發,而我個人比較喜歡 Flutter。

Flutter 的旅程

安裝

安裝過程對我來說十分簡單。如果是 Android 開發者,你應該已經安裝了 Android Studio。

  1. 選擇 Clone Flutter repo
  2. 設定環境參數
  3. 執行 flutter doctor 指令
  4. 在 Android Studio 裡安裝 Flutter Plugin

就是這麼簡單!如果還不清楚安裝步驟,你可以看看官方指南。雖然我從未試過在安裝時遇到困難,但是亦看過其他人在安裝時會碰上一些難題,在這個情況下,它的社群就非常有幫助了。

上手 Dart 和 Flutter

我過去是撰寫 Java 語言的,所以在我第一天開始撰寫基本的 Dart 時,發現它們的語法十分相似;而繼續撰寫後,我的語法亦開始不斷進步。Dart 內建支援 Streams 及 Future。我的 RxJava 經驗有助我了解 Streams,而在 ES6 Promise 方面的經驗則有助我理解 Futures 和 Async/Await 的概念。我的工作效率從第一天開始就非常高。我認為有強型別語言經驗的開發者會很快上手,而擁有動態語言經驗的開發者就可能會遇到一點困難。

在 Flutter,所有東西都是 Widget;這與我舊有的經驗非常不同,但是不同的文件和教學幫了我很多。我在頭兩三天感到非常困惑,因為有太多新的概念,佈局 (layouting)、樣式 (styling)、內距 (padding) 等所有東西都是一個 Widget。但了解 Android UI 系統與 Flutter UI 系統間的概念後,事情就開始變得簡單了,我亦開始更有自信。而且我非常喜歡當中的宣告式 UI (Declarative UI)。

Flutter Hot Reload 和 Hot Restart 功能的概念就是減少測試時間,每次 UI 變動只需花上 0.7 秒(多數時間)至 2 秒(有時)來在專案畫面上顯示。加上,Flutter 也保留 Widget 的狀態。假設你輸入了文字並勾選了幾個 CheckBox,當你改變 CheckBox 的顏色時,只有顏色會被更改, CheckBox 會繼續保持勾選狀態;這樣提高了我的工作效率。如果要去計算的話,我認為它與原生開發測試相比節省了超過 40% 的時間。

就如其他的程式語言一樣,Dart 也有套件管理解決方案,他們稱之為 Pub。由 Dart 官方支援,與 NPM 十分相似。

第一週、第一個畫面、適應性、重用性

在我開始的第一週,我完成了登入和註冊畫面,且成果非凡,適應性非常棒。當我傳送裝置畫面截圖給設計師時,他也認同畫面非常和諧。

Flutter Login screen adaptability on different screen sizes

Flutter 使用宣告式 UI,大大增加了 Widget 的重用性。同時,我建立了一個 “Bonus” Widget,並且在多個地方使用它,而 “User Avatar” 也是如此。將任何東西提取到 Widget 都十分容易,而且這個 Widget 還可以在任何地方重用。

享受挑戰

在 Flutter,你不會「面對」挑戰,但你會「享受」它們。

Flutter Athlete on boarding sequence on OPPO F7

舉個例子,根據畫面的設計,我需要一個月份選擇器,但卻沒有可用的套件。PageView Widget 是最接近可以組成的 UI。我深入理解程式碼架構後,創建了自己的 Widget,並發佈到 Pub

然後在另一個畫面,我需要一個雙邊範圍滑桿 (range slider),但它只有單邊的 Slider 可用。我又探索了 Cupertino Slider 的程式碼,然後創建一個新的雙邊範圍滑桿 Widget,並發佈到 Pub

Flutter Some random screens from the app on OPPO F7

Flutter Coach creating sport session sequence on OPPO F7

整合 Stripe

這可說是項挑戰,因為 Stripe 在 Dart 內並沒有官方支援 。在 Pub 上是有幾個可用的套件,但是我們需要更細緻的整合,所以我決定為此寫個 Plugin(一種 Dart 套件,包含了以 Dart 撰寫的 API,當中整合了特定平台的實作像是 Android 的 Java 或 Kotlin、和 iOS 的 Objective-C 或 Swift)。但是當我在 Github 上檢查 iOS 與 Android 的 Stripe SDK 時,我發現它們的程式碼並不相似。在 Android SDK,它們一個函式會回傳結果,但相對在 iOS SDK,函式卻不會回傳結果。所以我打消了這個念頭,並開始嘗試另一個方法:閱讀它們的文件,並以文件和 Android SDK 為參考,來完成 App 所需要的整套功能。

推播通知

Flutter Left OPPO F7, Right IPHONE 7

我在 iOS 與 Android 上都使用了 Firebase Cloud Messing。Flutter 上有官方插件可以使用,所以我首先使用該插件來整合推播功能。但是後來的有些需求改變了,而且我們需要在螢幕上依據推播通知的資料作即時內容更新,所以我們必須在專案中加入 Platform Channels。我移除了官方插件後,開始為撰寫 Android (Java) 與 iOS (Swift) 自己的 Firebase 整合程式碼。使用 Platform Channels,無論何時在平台端收到推播,我都可以推送資料到 Dart。這樣一來,當使用者點擊推播時,我就可以依據推播型別開啟特定的視窗。

程式碼架構

在大型專案裡,程式碼的架構非常重要。開始一個專案時有幾個熱門選擇:1. Redux、2. Scoped Model。雖然我一開始是採用 Redux 架構的,但我個人不太喜歡 Redux,我不太喜歡將所有東西全部存放在一個地方。幸運的是,在 Google I/O 2018 中,他們有談及到這部分,然後我就將架構轉換為 BLOC 模式,它滿足了我所有的需求,我現在仍在學習 BLOC 模式的最佳實踐。

翻譯

期限逼近,此時專案主管認為我們需要多增加一位開發者,讓他可以同時負責翻譯工作。在開發期間,大概因為我還是個新手,所以犯了個錯誤,沒有從 App 的在地化檔案中將字串提取出來,所以要由其他開發者負責將字串提取出來並完成翻譯檔案。這花了他一個星期時間來完成翻譯。

之後專案主管要求我更改 App 裡的一些翻譯,好讓它的意思更具體。因此我才了解與 Android 相比,在 Flutter 裡翻譯是多麼的麻煩。我們用了 Dart 的 intl 工具來產生 .arg 檔案,然後在轉回 .dart 檔案。

建置版本與發佈

建置版本非常簡單,在建置一個釋出版本時,官方文件幫了我很大的忙。如果你對在 Xcode 及 Android 上建置版本有信心的話,那麼你會覺得得心應手。要產生 Dart 執行程式碼,我們只需要輸入幾個額外指令。在 Xcode 中,我們只需要照著一般程序來建置/打包/上傳到 App Store;而在 Android 中,按下幾個鍵盤按鍵就可以產生一個釋出建置。

App Store 只需要一天就完成審核,並上架到商店。現在,App 在 App StoreAndriod 都可以下載了。

我的下一步是?

現在,我正專注在 Animations/Hero Animation 和客製 Widget 上。我必須深入探索程式碼裡的說明,並學習一些進階的東西。Isolates 是我下一個題目,我們必須在背景執行緒中執行一些沈重的工作。整個時間表可說是非常緊湊,且我們需要盡快完成 App,所以我們無法專注於測試方面。接下來,我們就要了解 Flutter 裡的測試。最後,我也必須學習持續整合 (Continuous Integration) 與持續發佈 (Continuous Delivery)。

總結

我認為 Flutter 是商業 App 的最佳選擇,它幫助我在緊迫的時間內完成了第一版的 App。它可以讓 App 的 UI 在 iOS 看起來非常漂亮,而且在 Andriod 上亦會維持同一狀態,這一點為我帶來了非常大的滿足感。如果你需要取用特定平台上的功能,Flutter 也有提供機制來輕鬆處理。Dart 語言很容易學習;Flutter 的 HotReload 功能也為我節省了大量時間,並提升了我的生產力;它的社群也正蓬勃發展;再加上,Flutter 的工具及 IDE 支援更好。

綜覽 App 功能

在讀過這篇很長的文章後,如果你還想知道使用 Flutter 建置的這個 App 有甚麼功能的話,讓我簡單說明一下 EntreaPro App 目前提供的功能:

  • 兩個不同角色(運動員與教練)有不同的選項、付款細節、側邊欄和功能。
  • 定位搜尋教練與運動員(使用 Place Suggest API)。
  • 已預定體育課程的總覽,當中分類為待決、已接受、和取消。
  • Stripe Connect (使用 WebView 來處理重新導向)讓每位運動員可以使用信用卡付課程費用予教練
  • Stripe(使用建置在 Dart 的客製 API),讓教練可以付費訂閱 EntrenaPro。
  • 體育課程折扣,由教練販售,其中有一部分已經準備好在課程後使用。
  • 新課程請求、接受、取消、付款等的實時更新與通知(使用 Firebase Push Notification)。
  • 日曆選擇,以為各個專業項目篩選可選時間。
  • 評價系統,提供星級評比、評論、和回應。
  • 教練筆記本,讓他能夠持續追蹤他提供的課程和運動員表現。
  • 教練個人資料共享(使用 Firebase Dynamic Links)。
本篇原文(標題:EntrenaPro — From Zero To Flutter)刊登於作者 Medium,由 Muhammad Ahmed 所著,並授權翻譯及轉載。
作者簡介: Muhammad Ahmed,一名 Android、Flutter 開發者,主要接受合約工作、開源項目和 Side Project 等。
Twitter: https://twitter.com/mahmed8003
譯者簡介:楊敦凱-目前於科技公司擔任 iOS Developer,工作之餘開發自有 iOS App同時關注網路上有趣的新玩意、話題及科技資訊。平時的興趣則是與自身專業無關的歷史、地理、棒球。來信請寄到:[email protected]

此文章為客座或轉載文章,由作者授權刊登,AppCoda編輯團隊編輯。有關文章詳情,請參考文首或文末的簡介。

blog comments powered by Disqus
訂閲電子報

訂閲電子報

AppCoda致力於發佈優質iOS程式教學,你不必每天上站,輸入你的電子郵件地址訂閱網站的最新教學文章。每當有新文章發佈,我們會使用電子郵件通知你。

已收你的指示。請你檢查你的電郵,我們已寄出一封認證信,點擊信中鏈結才算完成訂閱。

Shares
Share This