前言
前些日子朋友諮詢可否爬網站資料,並製作一Windows程式。作為開發iOS/Android/MacOS/WatchOS/...的我沒接觸過C++/C#,用Java開發也不現實,重新認識Windows元件、網路、資源管理還是比較耗時的,於是打算推薦其使用眾包平臺釋出任務。轉念一想,大Flutter豈不是最合適之選,「Write once, Run anywhere」,可以避免平臺相容難、學習成本高等眾多問題,最終在筆者挖坑填坑之旅中更加確定,Flutter會是移動端的未來。
本文為筆者利用下班和週末時間邊學邊做專案的歷程,希望對於Flutter入門者有所幫助。其中大多為開發建議、推薦和思路,並非程式碼級的指引。閱讀本文大約需20分鐘。
一、準備工作
1、Flutter開發環境、開發工具、學習資料
① 工欲善其事,必先利其器。 開發Flutter如果想要同時打包iOS&Android,必須要有一臺Mac電腦,沒有怎麼辦?發揮你程式設計師的優勢,安裝MacOS虛擬機器並在蘋果官網下載Xcode安裝包。 建議使用Android Studio(AS)開發,下載Flutter和Dart外掛即可,更好相容安卓模擬器。 筆者電腦安裝有Xcode和AS,所以只需安裝Flutter SDK即可,安裝後使用萬能指令,flutter doctor,發現問題,解決問題。 注:Android license status unknown的警告是因為我本地java版本過高,不影響開發,可以忽略。 當然,也可以使用Visual Studio開發,開發Windows程式必選。並且編譯打包EXE檔案時,必須在Windows10電腦環境執行。 (所以筆者在專案收尾階段安裝Windows10虛擬機器並安裝VS後才能打包,佔用我電腦40G的儲存。???)
②推薦一些學習Flutter的學習資料網站:
- Flutter中文網:flutterchina.club
位元組跳動-幸福裡FE團隊某大神製作,入門最佳選擇,保姆級資料。
- Flutter官網:flutter.dev,官網中文:flutter.cn
官網資料,最為可靠。版本新,資源全,手把手視訊教學及線上練習體驗。
- 未曾相識的老孟大哥:laomengit.com
最全的中文控制元件庫,使用與需求更貼切的良心官方控制元件,省時省心又省力。 吐槽一下用Android寫UI,Android(ListView,RecycleView)輸於iOS(UITableView,UICollectionView)的原因,就是iOS基本不需要自定義介面卡。但Android使用XML寫UI,非常方便,強於Xib。
- 第三方控制元件庫:pub.flutter-io.cn
相當於iOS之Cocoapods,Android之jcenter。常用第三方庫可在中文網資料中獲取,這裡不一一列舉。 強調一下,第三方庫的疊加依賴會導致相容失敗,一般情況下,使用any版本即可,pub管理工具會自動下載不造成衝突的版本。特殊情況需要下載離線庫進行配置。某些工具庫在編譯時需要註釋掉,例如hive_generator,自動生成model屬性轉換方法時需要新增,編譯時不註釋會報錯Dart Error: error: import of dart:mirrors is not supported in the current Dart runtime
- 阿里Flutter-GO:github.com/alibaba/flu…
值得推薦,以成品介紹元件。可惜的是可能是因為《閒魚》App效能問題,阿里內部對Flutter熱情不再,2年前已暫停維護。關於效能問題,目前的Flutter2.2已經有不小的效能提升和生態支援完善。
- 推薦高仿專案:my.oschina.net/u/4493374/b…
含高仿抖音,鬥魚,豆瓣,開源中國。基本包含市場App所有功能板塊。
2、瞭解分析需求,爬取需求資料,確定開發流程
①需求
- 表格展示專業列表,可操作、可分頁。
- 多維度多條件查詢
- 方案列表,編輯、切換方案
- 按需匯出Excel表格
- 註冊,登入,Token
②爬取網站資料
凡是爬取網站裡面不讓爬取資料的行為都是不道德/違法的。
實際上,各公司之間有很多資料都是相互爬。但這也沒有抵消筆者愧疚之心。況且此網站要爬取的介面都是有經過MD5加密後的動態Token的,所以再次打算推薦其使用眾包平臺。
在JS除錯視窗,除標頭還有預覽頁面。驚喜的是,網站的資料按500條/頁展示在預覽中,也就是說,我們只需要拷貝50頁資料即可。???
用命令列touch data{0..49}.json
建立50個檔案,依次貼上文字。製作一個小工具,融合50個json檔案得到1個20M的json檔案,這樣我們就得到原始資料。
當然,後續對資料查詢和效能的優化過程中,按照本科、專科、體育、藝術、提前型別分為5個json檔案,查詢速度從原來的600ms提高到400ms以內。
你問我為什麼不直接貼上在一個json檔案裡?有興趣的朋友可以試用任何編輯器開啟20M的json檔案。
~~
③開發流程
- 建立新Flutter App,預設已勾選iOS、Android,選擇MacOS及Windows平臺,若不能勾選,
flutter config --enable-macos-desktop
及flutter config --enable-windows-desktop
,重新建立。所有的開發都可以在Mac上進行,最後打包的時候再無縫移植到Windows。 - UI,資料庫,互動,邏輯,工具等。
- 平臺相容,原生開發,Flutter與原生通訊互動。
- 完善應用資訊,規正許可權,提交稽核。
- 應用已上架Mac App Store,應用地址為《選校方案》,Windows版稍後釋出在雲盤中。
二、功能模組
遍歷《選校方案》的功能模組,分析其中使用的Flutter知識,從iOS和Android開發者視角來解釋。
1、UI:萬物基於Widget。通俗來講,StatefulWidget是可變的控制元件,StatelessWidget是不可變的控制元件。單從建立UI來講,Android dev更有優勢一些,因為XML也是巢狀模式。iOS dev接觸過SwiftUI或者Rx系列或者RAC更容易理解,巢狀型UI是把iOS中所有約束,屬性,控制元件,引數,互動、動畫融合在一起,不以控制元件為主要物件,形成的響應式UI。從開發便利性來說,筆者感覺Hot Reload和響應式程式設計是所有移動端的趨勢。 ①避免巢狀,以封裝治理地獄式套娃
- 不論是單人還是多人開發,如果無休止的新增單個自定義Widget,一個複雜頁面動輒幾千行。對於後期維護者來說,結構調整困難,邏輯互動入口混雜難以分辨,簡直難受至極。
- 常用UI模組進行封裝,減少程式碼量,使結構清晰。
- 在這裡推薦Bloc模式<可理解為MVP>,簡單頁面還是以StatefulWidget為主,如有多個頁面共享同一資料的業務場景,就非常適合。
- 整個UI佈局封裝後在Bulid內也只有25行程式碼。
@override
Widget build(BuildContext context) {
passValue = ModalRoute.of(context).settings.arguments;
return Scaffold(
body: Column(
children: [
_getTopSearchView(context), //頂部搜尋欄
Container(
height: 40,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int position) {
return getTitleColumn(position, Global.titles[position]);
},
itemCount: Global.titles.length,
controller: firstRowController,
),
),//資料表頭
Expanded(child: Container(child: _getCoreListView())),//資料核心區
_getPageView()getPageView()//分頁區
],
),
);
}
複製程式碼
- 以部分UI舉例,將寬度、邊框屬性、居中資料、背景顏色進行封裝。程式碼篇幅較長,以圖片替代展示。
②整體佈局的思路
- 標題搜尋欄以外層Wrap巢狀,流式佈局可以使控制元件居中並設定行/列間距,自動適配整體視窗寬度。Dropdown、TextFiled、Button在iOS、Android中也有類似控制元件,唯一不同的是,獲取控制元件的動態值時,並不是直接以控制元件的屬性值來獲取,而是通過TextEditingController監聽、動態字串變數等方式。
Wrap(
alignment: WrapAlignment.center,
spacing: 20,
runSpacing: 10,
children: [])
複製程式碼
- 資料表頭設定為橫向ListView,新增ScrollController,與資料展示區的ScrollController相互監聽,完成同步滾動功能。
//監聽第一行變動
firstRowController.addListener(() {
double offset = secondedRowController.offset;
double offset1 = firstRowController.offset;
if (offset1 != offset) {
secondedRowController.jumpTo(offset1);
}
});
//監聽第二行變動
secondedRowController.addListener(() {
double offset = secondedRowController.offset;
double offset1 = firstRowController.offset;
if (offset != offset1) {
firstRowController.jumpTo(offset);
}
});
複製程式碼
- 資料展示區的UI相當複雜,既要保證橫豎向都能滾動,又要考慮滾動效能,還要展示{500條/頁}資料懶載入。
筆者耗時整整兩天才搞定此功能,一開始使用官方控制元件DataTable,發現在自定義單元格展示不同UI時,需大量程式碼匹配其代理方法;滾動效能極差;不可懶載入,遂程式碼全部廢棄,重新佈局。 受益於iOS構建UI時的靈活性處理,筆者突發奇想,使用橫向SingleChildScrollView內部巢狀豎向ListView,ListView使用itemBuilder構建。這樣一來,橫豎向滾動,效能,懶載入全部擁有。 單條item最後的“新增/刪除”按鈕操作,重新整理UI幾乎無卡頓。
- **分頁區:**若為固定長度,會導致Flutter UI的經典(Overflow)螢幕溢位問題,黃黑斜條紋顯示區域為UI警告(駕考寶典中為立面標記,一般在隧道口?),所以外層以SingleChildScrollView巢狀,視窗較小時,不會出現此警告。
更換100條/頁或其他頁碼時,使用例項變數來標記單頁條數,陣列的getRange方法重新分割資料,重新整理ListView與頁碼數。
2、資料庫
Hive,pub上1.8KLike,GitHub上2.3kStar,在Flutter中算是歡迎度比較高的。
- 配合hive_generator使用,可儲存模型,使用方便。
- 不必寫SQL語句,可直接按陣列/Map形式儲存
- CURD速度極快
專案中建表方式:
- 建立方案列表庫,與專業資料庫相互關聯。在每個方案中包含專業列表。
- 方案model中增加isCurrentPlan屬性,切換現有方案時正反賦值。
- 建立使用者屬性庫,儲存使用者手機號、密碼、暱稱、角色許可權(普通角色只能看到1000條資料)、已登入狀態
shared_preferences,類似於iOS之NSUserDefaults,Android之SharedPreferences,可用於本地小資料儲存。
3、第三方庫、全域性檔案及資源庫
- 麻雀雖小五臟俱全,專案小但功能全,新增第三方庫時,使用flutter pub get/upgrade等命令,本App整合的第三方庫有:
- 常用功能及第三方庫列表
- pubspec.yaml是Flutter專案的核心配置檔案,iOS dev需要能接受非視覺化配置,這點Android dev習以為常,與build.gradle相似。包含本地圖片,本地檔案,第三方庫,字型等。
- 建立Global類檔案,存放常用常量/變數,便於程式呼叫。
4、與原生通訊,原生適配。
- 用Xcode/AS單獨開啟各自平臺資料夾中的專案,應用名稱、圖示、啟動圖等需原生適配,iOS在Info.plist檔案中新增許可權,Android在Manifest.xml中配置許可權等。如果有Flutter實現不了的功能或者因平臺特殊要求,還是需要去做原生開發。關於Theme,偏向iOS/Android,都有相應的風格元件,還可以統一設定全域性Theme。只需要此時就需要一個Flutter交流群,互相幫助,隨時能夠解決平臺開發者在iOS/Android的原生適配開發問題,希望有號召力的大佬搞一個。
- 與JS原生互動的原理基本相同,無非是建立相同命名的通道,A傳送方法名稱和引數,B通過回撥接收。網上資料很多,自行百度吧,沒必要在這裡重複造輪子。
本App有匯出Excel檔案的需求(MacOS與iOS通訊方式相同),此時就需要做平臺相容(Platform.isAndroid or Platform.isIOS etc.)。對於Windows平臺來說,沒有強制規定向使用者請求許可權,所以直接儲存至任何普通檔案地址,觸發Flutter事件後呼叫原生SavePanel方法。對於MacOS來說,需要請求User Selected File-Read/Write,而不是下面的Folder許可權,並啟動原生檔案儲存視窗。這也是稽核被拒的重要原因。
5、macOS App Store上架歷程(由於App Store的嚴格稽核機制,一定要把握住許可權,連續5天幾個版本的拒審你懂的。Android dev可以略過)
- Debug階段,開啟Incoming Connections(Server)是必需的,因為Hot Reload基於此許可權,但Release時,一定要關閉,因為App普遍沒有作為伺服器的型別,會被拒審。
- 避免在任何地方顯示**“安卓,Android,三星,華為,微軟”**等蘋果在各方面對手的名稱,一旦發現,肯定拒審。尤其是筆者開發過的IT新聞類App,上線時需要新增多個“蘋果競爭對手”過濾關鍵詞。筆者在填寫應用介紹時把自己的技術開發經驗寫進去,“兩年安卓開發經驗”直接被拒,只能寫為“兩年卓卓經驗”???。
- 由於資料的保密性,為保證通過稽核,App採用假註冊模式,本地註冊儲存模擬登入。註冊成功後與遊客登入後許可權相同。
- 憑藉筆者多年拒審?過審經驗,總結一個原則。**一定不要和蘋果硬懟,讓你改你就改,讓你怎麼改就怎麼改。**實在不過就使一些障眼法唄。例如當年避免蘋果內購也是用盡渾身解數,最終也是隻用支付寶支付,微信支付確實沒法避免。當年慕課網App可以完全規避,有沒有大佬指導如何做到的。
三、Flutter、SwiftUI、Android(鴻蒙)的簡單思考
筆者打算將Flutter、iOS、Android、鴻蒙、小程式、快應用、RN等移動開發的未來發展單獨介紹分析,奈何篇幅不夠,現只做簡單闡述,稍後會發布另一篇文章仔細分析。
- Flutter: 混合開發,我願稱你為最強!從Flutter2.2效能提升來看,如果效能再有進一步提升,必定成為移動端開發主流,未來可期。稍微吐槽下Dart,比Swift還是差點意思。
- iOS: SwiftUI,又快又靚又牛x。成品效果驚豔,蘋果可謂是移動產品和技術的領導者。兩個缺點:①支援iOS 13以上,國內開發環境來說,還有一段路要走。②成熟度不夠,雖然Swift已經穩定,寫起來十分便利,但誰能知道SwiftUI會不會成為下一個SwiftUI。筆者從Swift2.2開始接觸,一個版本一個新語言的痛苦至今猶在。
- Android: 移動市場最大蛋糕分割者。不限於手機,目前最火的智慧汽車市場也是以Android為主,選擇它肯定沒錯。國外Android流暢度接近iOS,但國內安卓你懂的,希望國內推送統一聯盟儘快落地實用的標準和機制,避免社會資源的浪費。
- 鴻蒙: Fuchsia沒來,鴻蒙它來了。鑑於昨天OPPO公關評論鴻蒙事件,我只能?。前一陣與同事閒聊時,談論過鴻蒙,我只是講出了一些實事,但他卻說我侮辱國產?,這麼大的罪名,我可擔待不起。畢竟用著國產的衣服鞋子桌子椅子食物水,以後可不敢瞎評論。