實踐:校園打印店打卡應用落地復盤)
這幾年校園場景里的應用需求越來越多打印店打卡就是其中一個典型學生到店取文件要確認訂單、商家要核銷打印任務、管理員還要統(tǒng)計使用量。我之前做過幾版純原生實現(xiàn)安卓一套、iOS一套、鴻蒙再一套維護成本直接失控。后來換成 Flutter 做跨平臺統(tǒng)一開發(fā)再通過適配分支跑到鴻蒙設(shè)備上整體工作量至少砍了一半。這篇就完整復盤一下這個校園打印店打卡應用從選型到落地的全過程重點放在 Flutter 跨平臺能力在鴻蒙場景下的真實表現(xiàn)、工程改造的細節(jié)以及我在真機調(diào)試時踩過的那些坑。如果你正準備用 Flutter 開發(fā)鴻蒙應用或者想了解 Flutter 技術(shù)棧在鴻蒙設(shè)備上的可行性這篇文章應該能幫你少走不少彎路。我會把工程怎么建、狀態(tài)管理怎么選、組件之間怎么通信、掃碼模塊怎么調(diào)、真機怎么連、打包怎么配全部按實操順序?qū)懬宄⒔o出可以直接抄的代碼和配置。1. 為什么這次打卡應用選了 Flutter 而不是 ArkTS先聊一個繞不開的問題也是團隊里爭論最久的鴻蒙應用開發(fā)到底該用 ArkTS 還是 Flutter當時的情況是打印店打卡應用需要同時覆蓋三類終端學生用的手機安卓、鴻蒙、iOS 都有、打印店商家用的平板以鴻蒙和安卓為主、以及運營后臺供管理員查看的 Web 端。如果全走 ArkTS 原生意味著鴻蒙單獨維護一套代碼安卓和 iOS 又各一套三個人維護三套邏輯光是接口字段對齊就夠喝一壺的。Flutter 這邊的優(yōu)勢很直接一套 Dart 代碼編譯出多端產(chǎn)物UI 層完全自繪不依賴系統(tǒng)控件理論上只要渲染引擎能跑界面的表現(xiàn)就能保持一致。尤其對打卡這種業(yè)務界面邏輯并不復雜核心在掃碼、定位、訂單狀態(tài)流轉(zhuǎn)這些跨端做起來并沒有太大障礙。但 ArkTS 也不是沒有吸引力。鴻蒙原生應用在調(diào)用系統(tǒng)能力比如藍牙、NFC、掃碼攝像頭時最順暢性能也最有保障。問題在于鴻蒙原生生態(tài)目前對第三方庫的支持還不夠全面尤其是地圖、支付、推送這類服務偶爾需要自己去對接鴻蒙 SDK 的原始接口。而 Flutter 社區(qū)生態(tài)里現(xiàn)成的插件更多雖然有些插件在鴻蒙上需要重新編譯適配但至少有現(xiàn)成方案可以參考。最后團隊拍板選 Flutter核心原因有三個團隊現(xiàn)有技能棧以 Dart 和前端為主上 Flutter 的學習成本明顯低于全員轉(zhuǎn) ArkTS。打卡應用的核心邏輯訂單狀態(tài)機、計數(shù)統(tǒng)計、時段計算可以完全復用跨端只換 UI 殼子。未來如果要做微信小程序之外的輕量端Flutter 也能編譯到 Web一套邏輯多個出口。這里補充一點個人看法如果你做的應用強依賴鴻蒙特有的系統(tǒng)能力比如元服務、分布式流轉(zhuǎn)、超級終端聯(lián)動那還是老老實實走 ArkTS。像打卡這種以業(yè)務邏輯為核心的場景Flutter 的跨平臺優(yōu)勢才能發(fā)揮出來。順便回應一下網(wǎng)上常爭論的ArkTS 和 Flutter 誰更流行。我的判斷是短期看鴻蒙原生應用商店里 ArkTS 應用數(shù)量占優(yōu)但跨平臺開發(fā)者群體中 Flutter 的基數(shù)和生態(tài)豐富度更高。兩個技術(shù)棧橫向?qū)Ρ榷ㄎ徊⒉皇腔ハ嗵娲腔パa。對這種中小型校園項目來說哪邊能更快交付、更好維護哪邊就是正確答案。2. 開發(fā)環(huán)境準備讓 Flutter 工程順利跑進鴻蒙設(shè)備環(huán)境和工程配置是整個過程中最容易卡殼的環(huán)節(jié)而且報錯信息經(jīng)常不是直接說你缺了哪個依賴而是編譯編到一半彈出一個看不懂的底層錯誤。先說 Flutter SDK 的版本問題。要跑鴻蒙設(shè)備理論上用官方穩(wěn)定的 Flutter 主分支配合 OpenHarmony 適配版本。這里有個容易踩的坑直接下載官網(wǎng)最新版 Flutter創(chuàng)建工程后連 Ubuntu 的安卓模擬器都沒問題但一連接鴻蒙真機就提示無法識別設(shè)備或者干脆在執(zhí)行構(gòu)建命令時找不到鴻蒙工具鏈。我在實操中采用的是這種方式安裝 OpenHarmony 命令行工具并把hdc的路徑單獨配置到系統(tǒng)環(huán)境變量。在 Flutter 工程中引入鴻蒙平臺的適配 SDK 路徑讓 Flutter 在構(gòu)建時能找到對應的編譯器。創(chuàng)建工程后先執(zhí)行一次flutter doctor確認 Flutter、Dart 和鴻蒙工具鏈的狀態(tài)。Exhibit一個常見的環(huán)境配置示例以 Windows 下為例# 配置鴻蒙工具鏈環(huán)境變量 export DEVECO_SDK_HOME/path/to/ohos-sdk export PATH$PATH:$DEVECO_SDK_HOME/toolchains # 查看 Flutter 環(huán)境狀態(tài) flutter doctor如果flutter doctor檢測不到鴻蒙工具鏈不要急著換版本先手動檢查環(huán)境變量里的路徑是否存在、版本是否匹配。我之前遇到過 SDK 路徑配了但沒生效的情況最后是重啟終端才被正確加載。工程創(chuàng)建這一步有個優(yōu)化小技巧不要用默認的計數(shù)器模板而是直接建一個空工程再從零加入打卡業(yè)務模塊。默認模板會帶一堆演示代碼后面清理起來反而麻煩。我習慣先創(chuàng)建好目錄結(jié)構(gòu)再動手寫業(yè)務。再說組件通信的問題這也是打卡應用里躲不開的設(shè)計點。打印店打卡涉及三個角色的聯(lián)動學生端需要顯示自己的打卡記錄商家端需要看到實時訂單管理端需要統(tǒng)計匯總。三個入口如果各自維護一份狀態(tài)很容易出現(xiàn)數(shù)據(jù)不一致。Flutter 本身的組件通信機制解決了父子組件之間的數(shù)據(jù)傳遞但是兄弟組件、跨頁面組件、甚至是跨模塊之間的狀態(tài)同步還是需要一個統(tǒng)一的狀態(tài)管理層。這個應用我選了 Google 官方推薦的 Provider 方案。原因有兩個一是它的 API 簡潔ChangeNotifier加Consumer就能解決絕大多數(shù)場景沒有引入額外概念上手很快二是它在鴻蒙環(huán)境下的兼容性經(jīng)過驗證不需要特殊適配分支處理。下面具體展開說一下 Provider 在打卡場景里的實際寫法。3. 打卡核心模塊的狀態(tài)管理與組件通信Provider 的工程落地先說需求拆解。打印店打卡應用的核心場景是學生到店后掃碼打卡打卡成功則生成記錄商家在后臺確認訂單屬實管理員可查看今日打卡報表。整個流程中打卡狀態(tài)是全局共享的——學生端打卡后商家端要立刻看到狀態(tài)變化管理端也要同步更新統(tǒng)計數(shù)字。如果只在某個頁面內(nèi)部處理頁面一銷毀狀態(tài)就丟了。所以我把全局狀態(tài)統(tǒng)一放進 Provider 里數(shù)據(jù)模型單獨建一個類來維護。Exhibit 打卡狀態(tài)的數(shù)據(jù)模型class CheckInState extends ChangeNotifier { ListCheckInRecord _records []; // 今日打卡次數(shù) int get todayCount _records.where((r) r.time.isToday()).length; // 最近一條打卡記錄 CheckInRecord? get latestRecord _records.isEmpty ? null : _records.last; void addRecord(CheckInRecord record) { _records.add(record); notifyListeners(); } void checkout(String recordId) { final index _records.indexWhere((r) r.id recordId); if (index ! -1) { _records[index].status confirmed; notifyListeners(); } } }這里的notifyListeners()是關(guān)鍵它通知所有監(jiān)聽該狀態(tài)的組件重新構(gòu)建。學生端打卡按鈕觸發(fā)addRecord商家端頁面通過Consumer監(jiān)聽到列表變化自動刷新訂單列表。這就實現(xiàn)了跨頁面的實時聯(lián)動不需要手動傳參。再聊聊組件通信的具體層級。Flutter 里父子組件通信最簡單的方式就是構(gòu)造函數(shù)傳值和回調(diào)比如打卡頁的按鈕組件接收一個onCheckIn回調(diào)由父頁面決定點擊后的業(yè)務邏輯。但跨頁面的狀態(tài)同步必須走 Provider 或類似方案否則你只能通過路由參數(shù)層層傳遞改起來非常痛苦。我這里把組件通信分成三個層級來設(shè)計頁面內(nèi)組件通信用構(gòu)造參數(shù)和回調(diào)簡單直接。同一模塊內(nèi)跨頁面通信用 Provider 的ChangeNotifierProvider包裹模塊根節(jié)點。跨模塊共享數(shù)據(jù)例如登錄信息、打印訂單用全局 Provider同時配合ProxyProvider做模塊間依賴。實際運行下來這套分層在鴻蒙設(shè)備上的表現(xiàn)和安卓幾乎沒有差別熱重載、狀態(tài)恢復都正常。唯一需要注意的是個別鴻蒙版本對ChangeNotifier的銷毀時機處理不夠及時在退出頁面的時候偶爾會收到notifyListeners回調(diào)的警告。我在代碼里加了一個統(tǒng)一的安全判斷在回調(diào)前先確認組件是否仍然掛在組件樹上。Exhibit 安全判斷的寫法if (mounted) { notifyListeners(); }這個處理看起來微小但真機上避免了很多奇怪的崩潰和紅屏提示。4. 打印店打卡的業(yè)務建模與數(shù)據(jù)設(shè)計一個打卡應用看似簡單但如果數(shù)據(jù)模型設(shè)計得不好等做到報表統(tǒng)計那一層會非常痛苦。尤其是校園打印店這種場景一個學生一天可能多次到店一次打印任務可能涉及多頁文件、多個打印參數(shù)如果不提前預留字段后期擴展就得動表結(jié)構(gòu)。我在設(shè)計數(shù)據(jù)模型時把整個業(yè)務拆成了四個實體用戶學生/商家/管理員用角色字段區(qū)分。打卡記錄每次到店取件生成一條記錄包含時間、地點、訂單號。打印訂單每頁的打印參數(shù)、份數(shù)、顏色模式、是否雙面。統(tǒng)計報表按天、按周匯總的打卡次數(shù)和打印量。打卡記錄和打印訂單是關(guān)聯(lián)關(guān)系一條打卡記錄可以對應多個打印訂單因為學生可能一次取好幾份文件。反過來一個訂單只能對應一條打卡記錄這樣在商家確認環(huán)節(jié)可以直接通過打卡記錄反查訂單詳情。Exhibit 打卡記錄的核心字段設(shè)計字段類型說明idString唯一ID使用時間戳加隨機數(shù)生成userIdString打卡用戶學生IDstoreIdString打印店IDorderIdsListString關(guān)聯(lián)訂單ID列表timeDateTime打卡時間locationString打卡地點通過定位或掃碼獲取statusint狀態(tài)0待確認1已確認2已取消訂單表還會記錄打印頁數(shù)、單價、合計金額等信息。這里有個實際經(jīng)驗打印店的計費規(guī)則很靈活有的按黑白頁收費有的按彩色頁收費還有的包含裝訂費。在設(shè)計金額字段時最好把費用明細做成一個 JSON 字符串存起來而不是拆成多個列。因為計費規(guī)則經(jīng)常變把明細打包成 JSON改計費邏輯時只改前端計算邏輯數(shù)據(jù)表結(jié)構(gòu)不用動。這種設(shè)計在 Flutter 側(cè)就用 JsonSerializable 來序列化寫模型類的時候加注解自動生成 fromJson 和 toJson省掉很多手寫模板。當時我還對比過手寫和 codegen 兩種方式實測直接手寫字段映射在模型少的時候更快模型超過五個字段之后還是 codegen 更穩(wěn)尤其是字段重命名時不容易漏改。打印店的業(yè)務有個特殊性高峰期集中在中午下課前后同一時間可能幾十個學生同時到店取件。數(shù)據(jù)模型設(shè)計好了以后后端接口還需要處理并發(fā)打卡的冪等問題。我的做法是打卡記錄的主鍵用userId 年月日 自增序號的復合格式保證同一個學生同一分鐘內(nèi)的多次打卡不會因為并發(fā)請求造成重復數(shù)據(jù)。5. 打印店打卡的核心界面實現(xiàn)從掃碼到狀態(tài)同步界面這一塊我按用戶角色拆成三個端來做但共享同一套組件庫和主題。為什么強調(diào)共享因為 Flutter 的優(yōu)勢就在于一套組件可以在不同入口復用如果每個端都單獨寫一套頁面那就白用 Flutter 了。學生端的核心頁面是掃碼打卡頁。這個頁面的邏輯其實很簡單一個掃碼窗口一個顯示結(jié)果的狀態(tài)區(qū)域一個手動補卡的入口。我把掃碼能力封裝成了一個獨立的 Widget底層調(diào)用攝像頭權(quán)限并識別二維碼識別結(jié)果回調(diào)到上層。Exhibit 掃碼頁面的骨架class ScanCheckInPage extends StatelessWidget { Futurevoid _handleScanResult(String result) async { // 解析二維碼中的打印店ID和訂單號 final parsed await _parseQrCode(result); // 調(diào)用打卡接口向 Provider 寫入新記錄 _checkInProvider.addRecord(parsed); // 跳轉(zhuǎn)到打卡結(jié)果頁 Navigator.push(...); } override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(掃碼打卡)), body: Column( children: [ ScannerView(onScanned: _handleScanResult), ConsumerCheckInState( builder: (context, state, child) { return Text(今日已打卡 ${state.todayCount} 次); }, ), ], ), ); } }掃碼頁需要注意一個攝像頭權(quán)限的適配問題鴻蒙的權(quán)限彈窗和安卓的權(quán)限請求不是同一套機制直接用現(xiàn)成插件很可能在鴻蒙上拿不到返回結(jié)果。我在鴻蒙真機上遇到的情況是插件可以打開攝像頭畫面但識別到二維碼后回調(diào)遲遲不觸發(fā)。排查下來發(fā)現(xiàn)是插件內(nèi)部對鴻蒙授權(quán)結(jié)果的處理還沒有對齊后面通過修改插件的原生側(cè)代碼才解決。商家端則是訂單確認頁。商家登錄后可以看到待確認的打卡列表每一條都關(guān)聯(lián)具體的打印訂單點擊確認后狀態(tài)從待確認變成已確認統(tǒng)計報表同步刷新。這個頁面用到了 Provider 的Consumer來監(jiān)聽整個打卡列表的狀態(tài)變化當學生端新增打卡記錄時商家端的列表會自動插入新行不需要手動去刷新接口。如果兩個角色所在的設(shè)備不是同一臺就需要后端接口配合長連接或輪詢來同步。我的第一版實現(xiàn)是純前端狀態(tài)管理后來加了 WebSocket 推送才真正做到學生掃碼后商家端秒級顯示。這里如果你用 Provider 只做前端狀態(tài)很容易忽略后端同步的問題我建議在設(shè)計階段就把接口推送納入打卡鏈路不要只圖前端省事。管理員端是報表頁本來打算用圖表庫畫柱狀圖后來發(fā)現(xiàn)打印店的實際需求就是看一張數(shù)字匯總表哪個時段人多、哪個套餐打印量高就夠了。圖表反而花哨且不實用最后我就用簡單的列表加數(shù)字卡片實現(xiàn)了。6. flutter 真機調(diào)試記錄連接、構(gòu)建與熱重載的避坑清單真機調(diào)試是這次開發(fā)里讓我最有收獲的部分也是報錯最多的部分。這里記錄的每一條都是我實際踩到過的不是從文檔里抄來的理論。先說說設(shè)備連接。鴻蒙真機連接電腦調(diào)試和安卓一樣需要開啟開發(fā)者模式但有個細節(jié)鴻蒙系統(tǒng)默認把USB 調(diào)試選項藏在更深的層級里你需要連點版本號進入開發(fā)者選項再額外打開USB 調(diào)試下面的僅充電模式下允許 ADB 調(diào)試開關(guān)。如果不開這個電腦端檢測到的設(shè)備狀態(tài)永遠是 offlineflutter devices里看不到設(shè)備更別提跑項目了。Exhibit 連接檢查的常用命令# 查看已連接的設(shè)備列表 flutter devices # 查看鴻蒙設(shè)備的 hdc 連接狀態(tài) hdc list targets # 如果離線可以嘗試重啟 hdc 服務 hdc kill hdc start連接成功后跑項目大概率會遇到第一個報錯Gradle 或構(gòu)建鏈配置問題。這個報錯在熱搜詞里也出現(xiàn)過you are applying flutters main gradle plugin imperatively using the apply(s,e/flutter (31173))大致意思是 Flutter 的 Gradle 插件和工程中已有的插件配置方式?jīng)_突。這個問題的解決方式很簡單在android/settings.gradle和android/build.gradle中把 Flutter 插件從apply腳本式改成現(xiàn)代插件聲明式。具體來說在settings.gradle里加上pluginManagement的倉庫配置然后在各個模塊的build.gradle里通過plugins { id com.android.application }方式聲明不再使用apply plugin:。Exhibit 關(guān)鍵配置片段pluginManagement { repositories { google() mavenCentral() gradlePluginPortal() } }改完配置文件后記得在命令行執(zhí)行清理構(gòu)建flutter clean flutter pub get flutter run如果只改配置不執(zhí)行flutter clean舊構(gòu)建緩存仍然生效報警也不會消失。熱重載這塊也值得一提。flutter run在鴻蒙真機上的熱重載體驗總體還行但有個小問題改了原生側(cè)代碼比如修改了某個鴻蒙原生模塊的 Kotlin 代碼之后普通的熱重載不會生效必須重新編譯運行。我后來養(yǎng)成習慣純 Dart 邏輯的改動直接熱重載涉及原生能力的改動一律執(zhí)行完整重啟別省那點時間。更隱蔽的是定位權(quán)限。打印店打卡場景里打卡時需要記錄位置學生每次掃碼前要保證定位權(quán)限已開啟。鴻蒙系統(tǒng)在定位權(quán)限上比安卓更嚴格定位服務需要同時在應用層和系統(tǒng)層同時授權(quán)。我在真機上遇到的坑是第一次授權(quán)彈窗點擊允許后應用確實拿到了權(quán)限但一旦切后臺再回前臺權(quán)限狀態(tài)會被重置。最后繞過的辦法是在頁面onResume里周期性地重新檢測權(quán)限狀態(tài)如果沒有權(quán)限就彈窗引導用戶去設(shè)置頁手動開啟。7. 性能優(yōu)化Impeller 渲染引擎在鴻蒙設(shè)備上的表現(xiàn)Flutter 的渲染引擎這幾年的變化很大從 Skia 逐步切換到 Impeller。Impeller 是為高性能圖形渲染設(shè)計的核心優(yōu)勢是預編譯著色器從根本上解決了 Skia 在部分設(shè)備上首次渲染掉幀的問題。打印店打卡應用界面不算復雜動畫也不多但掃碼頁面的相機預覽和結(jié)果頁的列表滾動都依賴穩(wěn)定的渲染幀率Impeller 在這類場景下的表現(xiàn)明顯比 Skia 順滑。鴻蒙真機的 GPU 型號五花八門老款平板的 GPU 驅(qū)動對 Skia 的兼容性尤其差滾動列表時偶爾出現(xiàn)白屏閃爍。切到 Impeller 之后這類問題幾乎消失。切換方式是在main.dart里配置渲染引擎參數(shù)void main() { // 啟用 Impeller 渲染引擎 const String.fromEnvironment(FLUTTER_ENGINE, defaultValue: impeller); runApp(const CheckInApp()); }實際構(gòu)建時也可以在運行命令里指定flutter run --enable-impeller需要說明的是Impeller 對鴻蒙的支持是一個漸進的過程。如果遇到某個鴻蒙版本的驅(qū)動不兼容 Impeller回退到 Skia 也只需要改一個環(huán)境變量不需要動業(yè)務代碼。這算是 Flutter 框架在設(shè)計上給自己留的后路對開發(fā)者來說很友好。另一個性能優(yōu)化點跟列表渲染有關(guān)。打卡記錄會隨著學生使用次數(shù)不斷累積如果直接用ListView.builder渲染全部數(shù)據(jù)長列表一樣會卡。Flutter 的ListView.builder雖然做懶加載但如果不加緩存策略快速滑動時還是會出現(xiàn)空白項。我給打卡列表加了一個cacheExtent參數(shù)并控制每個列表項的高度讓滾動體驗保持在流暢狀態(tài)。Exhibit 列表優(yōu)化代碼ListView.builder( cacheExtent: 500, itemCount: records.length, itemBuilder: (_, index) CheckInListItem(record: records[index]), )這套優(yōu)化在打印店高峰期特別有用。學生掃碼后商家端列表同時插入大量新記錄如果沒有緩存策略滑動到標記位置時頁面會短暫抖動影響操作效率。8. 打包發(fā)布鴻蒙應用簽名的細節(jié)與配置檢查打包發(fā)布是開發(fā)流程的終點但也是問題最多的地方。鴻蒙應用打包有兩種模式調(diào)試包和發(fā)布包。調(diào)試包可以直接運行在真機上但應用圖標、名稱、權(quán)限聲明都受限。發(fā)布包需要簽名簽名配置不對的話應用在部分設(shè)備上會閃退。我按官方文檔配置簽名時遇到了一個細節(jié)問題簽名文件路徑中的反斜杠在 Windows 環(huán)境下被錯誤解析導致簽名失敗。解決辦法是把簽名配置寫到build-profile.json5的signingConfigs節(jié)點里使用相對路徑并在構(gòu)建時打印出的日志中確認生成的哈希值與配置的哈希值一致。發(fā)布前還需要檢查權(quán)限聲明。打卡應用至少需要相機掃碼、位置記錄地點、網(wǎng)絡(luò)同步數(shù)據(jù)這三類權(quán)限。在鴻蒙的配置文件中權(quán)限聲明使用module.json5里的requestPermissions節(jié)點如果忘記聲明某條權(quán)限應用運行時調(diào)用對應功能會直接閃退而且報錯信息未必能指向權(quán)限問題。Exhibit 權(quán)限聲明示例{ module: { requestPermissions: [ { name: ohos.permission.CAMERA }, { name: ohos.permission.LOCATION }, { name: ohos.permission.INTERNET } ] } }打包完成后建議先在一臺舊設(shè)備、一臺新設(shè)備上分別安裝測試。鴻蒙系統(tǒng)版本跨度比較大老機型對 Impeller 和部分原生插件的支持與新機型有差異提前覆蓋能避免上線后被用戶投訴。我還遇到一個跟 WebView 相關(guān)的問題。打卡應用的打印訂單預覽需要在應用內(nèi)展示 PDF 文件我最初用的是 Flutter 自帶的多媒體組件但在鴻蒙上對 PDF 的支持不完整。后來換成一個簡單的原生視圖來承載 PDF 預覽才徹底解決。如果你也有類似的內(nèi)嵌文檔展示需求建議提前確認好鴻蒙平臺是否有對應可用的原生模塊別等到打包階段再返工。發(fā)布到鴻蒙應用商店之前還需要審核應用名稱和圖標是否符合平臺規(guī)范。打卡應用的圖標和名稱可以根據(jù)自己的品牌設(shè)計但要注意不能使用包含誤導性或夸大宣傳的文案審核不通過很常見的就是名稱里出現(xiàn)官方系統(tǒng)級這類字眼需要仔細檢查。9. 常見編譯異常與問題定位思路最后專門整理一下開發(fā)過程中遇到的高頻編譯報錯和定位思路。這部分是純粹的踩坑記錄每一條都可能讓你在排查時多花幾個小時。第一類是 Gradle 倉庫拉取失敗。報錯信息通常是一長串無法解析的依賴路徑。這種問題大多是網(wǎng)絡(luò)環(huán)境導致的配置國內(nèi)鏡像倉庫可以緩解但要注意 Flutter 的公共依賴不僅存在 Maven 倉庫還有 Google 的倉庫需要同時配置多個鏡像源。在國內(nèi)服務器上下載依賴尤其容易出現(xiàn)中斷反復重試不如一次性把鏡像配好。第二類是 Dart 插件與原生模塊的版本不匹配。Flutter 生態(tài)里很多插件在鴻蒙上沒有現(xiàn)成的原生實現(xiàn)需要自己編寫鴻蒙側(cè)的 Module 移植代碼。這個過程中報錯最多的是No implementation found for method之類的錯誤意思是 Dart 側(cè)調(diào)用了一個原生方法但原生側(cè)壓根沒有注冊。排查思路很簡單先檢查原生代碼里是否實現(xiàn)了插件注冊的對應方法再檢查工程里是否遺漏了dependencies塊里的插件引用最后檢查插件名是否與pubspec.yaml中的一致。第三類是第三方 SDK 接入問題時出現(xiàn)的符號沖突。打卡應用的登錄功能接入了第三方認證 SDK在鴻蒙真機上編譯時提示 duplicate class。這個問題的根源是第三方 SDK 與項目里的某個模塊存在同名類按照報錯信息中給出的路徑把其中一個模塊的依賴排除掉即可。定位編譯問題有個通用思路先看最底層的報錯行不要被上面的信息干擾然后定位報錯涉及的是 Dart 層、原生層還是構(gòu)建工具層最后逐層排查。大多數(shù)報錯都是構(gòu)建工具配置引發(fā)的和業(yè)務代碼無關(guān)不要一上來就懷疑自己的業(yè)務邏輯寫錯了。10. 從這次實戰(zhàn)里提煉出的幾點心得Flutter 做鴻蒙開發(fā)的項目實踐到這里基本完整了。最后聊幾個我個人感受最深的地方。第一選好狀態(tài)管理方案能省掉很多組件通信的麻煩。打印店打卡這個業(yè)務說大不大但涉及三個角色共享數(shù)據(jù)只要狀態(tài)設(shè)計不好后期每加一個頁面都要重新捋一遍數(shù)據(jù)流。Provider 在這個規(guī)模下恰到好處再復雜一點的場景我會考慮 Riverpod但普通業(yè)務真的沒必要為了技術(shù)而技術(shù)。第二鴻蒙適配的坑大部分在原生側(cè)不在 Flutter 側(cè)。Flutter 框架本身的跨端能力在鴻蒙平臺上比我預期中可靠真正讓人頭疼的是各種系統(tǒng)權(quán)限、原生插件、簽名打包的問題。在做技術(shù)選型時最好先把接入的第三方能力全部在鴻蒙真機驗證一遍再決定最終方案。第三行動起來比爭論誰更流行更重要。當時團隊內(nèi)部因為技術(shù)選型反復開了好幾次會現(xiàn)在回頭看真正推動項目落地的不是某個框架的壓倒性優(yōu)勢而是團隊在執(zhí)行過程中持續(xù)解決具體問題的能力。如果你手頭正好有類似的校園場景應用要做不妨先建一個空 Flutter 工程把掃碼、定位、列表這些核心能力在鴻蒙真機上跑通再逐步疊加業(yè)務邏輯。前期驗證階段多花點時間后面整體開發(fā)會順很多。