戰(zhàn):MethodChannel 與調(diào)試能力落地)
前陣子團(tuán)隊(duì)把主力 App 往 HarmonyOS 上搬我接手的第一件事不是頁(yè)面適配而是把內(nèi)部一直用的 Flutter 調(diào)試輔助庫(kù)dev_pilot跑通在鴻蒙真機(jī)上。這個(gè)庫(kù)在 Android 和 iOS 上幫我們省了太多事線上問(wèn)題復(fù)現(xiàn)時(shí)可以隨手拉起調(diào)試面板看路由棧、查設(shè)備參數(shù)、開(kāi)日志回傳開(kāi)發(fā)階段也能直接在 App 里執(zhí)行一些臨時(shí)調(diào)試命令。到了鴻蒙這邊純 Dart 層的頁(yè)面很快就跑起來(lái)了但凡是涉及原生能力的地方基本是一片空白。dev_pilot本質(zhì)上是一個(gè) Flutter 三方庫(kù)注冊(cè)成了平臺(tái)插件通過(guò) MethodChannel 和 EventChannel 跟原生端打交道。鴻蒙的 Flutter 引擎對(duì)系統(tǒng)服務(wù)的暴露方式和 Android/iOS 不太一樣所以不能指望把 Java 或 OC 代碼直接搬過(guò)來(lái)。這篇文章把我這次從零開(kāi)始做鴻蒙化適配的完整過(guò)程整理出來(lái)包括插件骨架怎么搭、通道怎么改、調(diào)試功能怎么在鴻蒙側(cè)落地以及我在真機(jī)上踩過(guò)的幾個(gè)坑。如果你也正在做 Flutter 庫(kù)的鴻蒙移植或者只是想在鴻蒙 App 里快速接入一個(gè)調(diào)試面板這篇內(nèi)容應(yīng)該能幫你少走不少?gòu)澛贰?. dev_pilot 到底解決了什么問(wèn)題為什么非要上鴻蒙先說(shuō)清楚這個(gè)庫(kù)是干什么的。dev_pilot不是一個(gè)渲染組件庫(kù)也不是網(wǎng)絡(luò)庫(kù)它更像一個(gè)內(nèi)嵌在 App 里的“隨行調(diào)試助手”。平時(shí)開(kāi)發(fā) Flutter 應(yīng)用我們可以靠 IDE、日志和斷點(diǎn)來(lái)查問(wèn)題但一旦到了測(cè)試反饋、線上用戶環(huán)境或者需要在真機(jī)上快速驗(yàn)證一些參數(shù)時(shí)常規(guī)手段就有點(diǎn)笨重了。dev_pilot 提供的是一個(gè)輕量級(jí)調(diào)試 UI通常在 App 內(nèi)通過(guò)懸浮入口或搖一搖手勢(shì)呼出。打開(kāi)之后能看到幾類信息當(dāng)前設(shè)備的基礎(chǔ)參數(shù)、Flutter 引擎版本、路由棧上都有哪些頁(yè)面、最近一段時(shí)間內(nèi)的日志滾動(dòng)、內(nèi)存占用曲線以及一個(gè)可以手動(dòng)輸入的執(zhí)行面板。這個(gè)執(zhí)行面板才是它最值錢的地方你可以在里面跑一些預(yù)先注冊(cè)好的調(diào)試命令比如切換后端環(huán)境、清理緩存、打開(kāi)某個(gè)隱藏頁(yè)面不用重新打包。聽(tīng)起來(lái)這些功能好像也可以自己寫但為什么我強(qiáng)烈建議用一個(gè)庫(kù)并做鴻蒙適配因?yàn)檎{(diào)試工具最怕“不統(tǒng)一”。項(xiàng)目里頁(yè)面越來(lái)越多調(diào)試入口散落在各個(gè)業(yè)務(wù)模塊每次查問(wèn)題都要在不同的頁(yè)面里找不同按鈕效率很低。dev_pilot 把所有調(diào)試能力收攏到一個(gè)面板里無(wú)論是誰(shuí)接手項(xiàng)目只要知道入口就能在五分鐘內(nèi)拿到現(xiàn)場(chǎng)環(huán)境信息。鴻蒙適配的必要性也在這里。Flutter 應(yīng)用跑在鴻蒙上Dart 代碼幾乎不用改但調(diào)試面板里那些從系統(tǒng)層拿數(shù)據(jù)的邏輯就沒(méi)法工作了。比如設(shè)備型號(hào)、系統(tǒng)版本、內(nèi)存使用、日志輸出這些在 Android 上要靠 Platform 通道調(diào)原生代碼在鴻蒙上也需要對(duì)應(yīng)的通道實(shí)現(xiàn)。如果不做適配結(jié)果就是App 能跑但調(diào)試面板里的功能全是空的甚至打開(kāi)就報(bào)MissingPluginException。所以這次適配的核心目標(biāo)很明確讓 dev_pilot 在鴻蒙真機(jī)上提供和 Android 等價(jià)的基礎(chǔ)能力。我不追求把所有插件都移植完但設(shè)備信息、日志回傳、執(zhí)行命令這幾個(gè)最核心的場(chǎng)景必須能穩(wěn)定用起來(lái)。2. 適配前的接口盤點(diǎn)先弄清楚哪些能力依賴原生做鴻蒙化適配最忌諱拿到源碼就開(kāi)始寫代碼。Flutter 插件里通?;熘罅?UI 和業(yè)務(wù)邏輯這些可能不需要?jiǎng)诱嬲枰w移的是那些通過(guò)平臺(tái)通道暴露出來(lái)的原生方法。我的第一步是把 dev_pilot 的插件邊界徹底拆出來(lái)。2.1 從 pubspec 和目錄結(jié)構(gòu)判斷插件形態(tài)dev_pilot 在 pubspec.yaml 里是這樣聲明的flutter: plugin: platforms: android: package: com.devpilot.android pluginClass: DevPilotPlugin ios: pluginClass: DevPilotPlugin插件工程下通常有三個(gè)主要目錄android/、ios/、lib/。lib/里是 Dart 端封裝android/和ios/里是平臺(tái)實(shí)現(xiàn)。鴻蒙化適配要新增的就是一個(gè)ohos/目錄以及在 pubspec 里增加ohos平臺(tái)聲明。拿到源碼后我不急著看實(shí)現(xiàn)而是先把a(bǔ)ndroid/src/main/java里的 MethodChannel 方法列表掃一遍。方法名、參數(shù)、返回值這些就是適配清單的原始素材。iOS 那邊也要看因?yàn)椴簧俜椒ㄔ趦蓚€(gè)平臺(tái)上的行為有細(xì)微差異鴻蒙側(cè)應(yīng)該對(duì)應(yīng)哪個(gè)結(jié)果要以實(shí)際產(chǎn)線使用為準(zhǔn)。2.2 梳理出完整的平臺(tái)接口清單我當(dāng)時(shí)整理了一張接口表只保留跟系統(tǒng)能力相關(guān)的方法。格式大致是通道名方法名入?yún)⒎祷貎?nèi)容原生依賴dev_pilot/channelgetDeviceInfo無(wú)Map型號(hào)、系統(tǒng)版本、內(nèi)核系統(tǒng)屬性dev_pilot/channelstartLogStream無(wú)EventChannel 流系統(tǒng)日志讀取dev_pilot/channelrunCommand命令名、參數(shù)執(zhí)行結(jié)果應(yīng)用上下文dev_pilot/channelgetMemoryInfo無(wú)Mapused、total系統(tǒng)內(nèi)存接口dev_pilot/channelsetEnv環(huán)境標(biāo)識(shí)Boolean本地配置存儲(chǔ)有些方法看起來(lái)是“純 Dart”比如路由棧獲取但底層可能也通過(guò) MethodChannel 去問(wèn)原生側(cè)當(dāng)前顯示的頁(yè)面狀態(tài)。所以不能只看名字要把每個(gè)方法的調(diào)用鏈路都追一下。2.3 把“適配清單”標(biāo)注成“風(fēng)險(xiǎn)清單”整理完接口表后我還做了一步給每個(gè)方法標(biāo)上風(fēng)險(xiǎn)等級(jí)。風(fēng)險(xiǎn)來(lái)自兩塊一是通道名稱和平臺(tái)參數(shù)不一致二是鴻蒙系統(tǒng) API 和 Android API 的邊界差異。比如獲取設(shè)備型號(hào)Android 上常用Build.MODEL但鴻蒙上對(duì)應(yīng)的 API 不一定同名。再比如內(nèi)存信息Android 的Debug.getMemoryInfo可以直接跑鴻蒙側(cè)是否有等價(jià) API 需要查文檔不能盲目映射。那些風(fēng)險(xiǎn)高的方法我會(huì)在適配時(shí)單獨(dú)寫一個(gè) wrapper 做數(shù)據(jù)歸一化而不是直接把 Android 代碼改改就搬過(guò)來(lái)。3. 鴻蒙側(cè)插件骨架從空工程到 MethodChannel 打通接口清單定下來(lái)之后就要在鴻蒙側(cè)把插件骨架建起來(lái)。HarmonyOS 的 Flutter 插件開(kāi)發(fā)思路和 Android 類似也是實(shí)現(xiàn) FlutterPlugin 接口然后再注冊(cè) MethodCallHandler。但細(xì)節(jié)上要注意的地方挺多。3.1 創(chuàng)建 ohos 插件目錄并配置 pubspec我建議先在 Flutter 插件工程下手動(dòng)創(chuàng)建ohos/目錄然后回 pubspec.yaml 增加平臺(tái)聲明flutter: plugin: platforms: android: package: com.devpilot.android pluginClass: DevPilotPlugin ios: pluginClass: DevPilotPlugin ohos: pluginClass: DevPilotPlugin注意這里的插件類名不一定非要和 Android 相同但要保證在鴻蒙側(cè)能找到。實(shí)際項(xiàng)目中我更習(xí)慣于讓宏同減少后續(xù)判斷成本。然后到 DevEco Studio 里創(chuàng)建一個(gè) HarmonyOS 插件模塊或者直接在當(dāng)前工程里添加一個(gè)ohosmodule語(yǔ)言選 Kotlin 或 ArkTS 都可以。我的經(jīng)驗(yàn)是插件工程用 Kotlin 寫會(huì)比較順手因?yàn)?Flutter 引擎暴露出來(lái)的原生接口和 Android 側(cè)認(rèn)知一致。3.2 實(shí)現(xiàn) FlutterPlugin 和 MethodCallHandler核心代碼不長(zhǎng)大致是這個(gè)樣子package com.devpilot.ohos import ohos.flutter.embedding.engine.plugins.FlutterPlugin import ohos.flutter.plugin.common.MethodCall import ohos.flutter.plugin.common.MethodChannel import ohos.flutter.plugin.common.MethodChannel.MethodCallHandler class DevPilotPlugin : FlutterPlugin, MethodCallHandler { private lateinit var channel: MethodChannel override fun onAttachedToEngine(binding: FlutterPluginBinding) { channel MethodChannel( binding.flutterEngine.dartExecutor.binaryMessenger, dev_pilot/channel ) channel.setMethodCallHandler(this) } override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { when (call.method) { getDeviceInfo - result.success(buildDeviceInfo()) getMemoryInfo - result.success(buildMemoryInfo()) else - result.notImplemented() } } override fun onDetachedFromEngine(binding: FlutterPluginBinding) { channel.setMethodCallHandler(null) } }建議把設(shè)備信息、內(nèi)存信息這一類純查詢邏輯單獨(dú)抽到DevPilotNativeBridge類中這樣插件類只負(fù)責(zé)通道分發(fā)后續(xù)加方法也不會(huì)把單個(gè)類撐得太大。3.3 發(fā)布配置和依賴聲明如果只是內(nèi)部工程用不打算發(fā)布到 pub.dev那可以直接在宿主 App 的oh-package.json5里以本地依賴方式引入插件模塊。如果要發(fā)布成鴻蒙原生庫(kù)需要額外配置 HAR 包的描述文件。這個(gè)環(huán)節(jié)最容易漏的是ohos平臺(tái)聲明沒(méi)加進(jìn) pubspec導(dǎo)致 Flutter 工程在鴻蒙側(cè)構(gòu)建時(shí)根本找不到插件。適配完骨架后我習(xí)慣先用一個(gè)最小可運(yùn)行的 Flutter 項(xiàng)目驗(yàn)證鏈路在 Dart 端調(diào)用dev_pilot的getDeviceInfo看能否成功返回?cái)?shù)據(jù)。如果這一步通了后面的玩法就都能往上壘。3.4 別忽視 onDetachedFromEngine 的清理一個(gè)很隱蔽的問(wèn)題插件在頁(yè)面銷毀、引擎重建時(shí)如果沒(méi)有正確釋放通道再次 attach 時(shí)會(huì)出現(xiàn)方法回調(diào)跑丟甚至崩潰。onDetachedFromEngine里必須把 channel 的 handler 置空。我在 Android 上從來(lái)沒(méi)在意過(guò)這件事因?yàn)?Android 端的生命周期相對(duì)穩(wěn)定但鴻蒙的 Flutter 容器在某些場(chǎng)景下會(huì)更頻繁地重建這個(gè)清理動(dòng)作就變得非常必要。4. 核心調(diào)試功能在鴻蒙側(cè)的落地細(xì)節(jié)骨架通了接下來(lái)就是把最常用的幾個(gè)功能真正做扎實(shí)。這里我不展開(kāi)講所有方法只挑三個(gè)對(duì)調(diào)試價(jià)值最高、也最容易出問(wèn)題的模塊分別是設(shè)備信息、日志回傳和命令執(zhí)行。4.1 設(shè)備信息數(shù)據(jù)獲取與字段歸一化設(shè)備信息在調(diào)試面板里看著簡(jiǎn)單實(shí)際坑不少。鴻蒙的系統(tǒng)版本號(hào)、廠商名、設(shè)備型號(hào)和 Android 表述不同如果直接把原始字符串傳給 Dart 端會(huì)導(dǎo)致上層判斷邏輯錯(cuò)亂。我踩過(guò)的真實(shí)例子是鴻蒙設(shè)備的系統(tǒng)版本字段返回了一個(gè)非常長(zhǎng)的字符串前端直接展示沒(méi)問(wèn)題但代碼里靠版本號(hào)判斷分支時(shí)就誤判了。為了避免這種問(wèn)題我在鴻蒙側(cè)做了一個(gè)歸一化層。統(tǒng)一輸出以下字段{ brand: huawei, model: ALN-AL00, systemName: HarmonyOS, systemVersion: 5.0.0, flutterVersion: 3.22.2, deviceType: phone }Dart 端拿到的對(duì)象和 Android 保持一致這樣上層 UI 不用為鴻蒙做特殊處理。鴻蒙系統(tǒng)參數(shù)可以從系統(tǒng) API 獲取不同 API 版本拿到的字段名會(huì)有些出入建議在適配層寫一個(gè)兼容函數(shù)優(yōu)先用新接口拿不到再回落舊接口。4.2 日志回傳EventChannel 的實(shí)時(shí)推送調(diào)試面板最核心的體驗(yàn)是“實(shí)時(shí)”。如果每次拉日志都讓前端輪詢不僅慢還會(huì)漏掉瞬時(shí)崩潰上下文。所以 dev_pilot 在 Android 上是拿 EventChannel 做了主動(dòng)推送。鴻蒙側(cè)也必須走同樣的模式。我在插件里創(chuàng)建了一個(gè) EventChannelclass DevPilotLogHandler : EventChannel.StreamHandler { private var eventSink: EventChannel.EventSink? null override fun onListen(arguments: Any?, events: EventChannel.EventSink?) { eventSink events } override fun onCancel(arguments: Any?) { eventSink null } fun pushLog(line: String) { eventSink?.success(line) } }這里有一個(gè)經(jīng)驗(yàn)不要直接去讀系統(tǒng)全局日志。系統(tǒng)日志量大、格式雜、還涉及權(quán)限問(wèn)題調(diào)試面板要的是“當(dāng)前 App 進(jìn)程里由 Flutter 層產(chǎn)生的日志”。所以我在 Dart 端加了一個(gè)日志攔截器把 debugPrint 統(tǒng)一重定向到一個(gè)本地隊(duì)列再由原生通道定期批量推送。這樣既避免高頻單條 EventChannel 調(diào)用也減少性能損耗。Dart 端的大致思路是void startLogStream() { _eventChannel?.receiveBroadcastStream().listen((event) { _logBuffer.add(event.toString()); }); }日志推送的間隔我用的是每 500 毫秒做一次批量 flush。間隔太長(zhǎng)展現(xiàn)滯后太短又會(huì)頻繁觸發(fā)原生回調(diào)。實(shí)測(cè)下來(lái)調(diào)試場(chǎng)景下 500ms 是交互和性能都比較平衡的值。4.3 命令執(zhí)行做一個(gè)可控的命令注冊(cè)表命令執(zhí)行是 dev_pilot 的殺手級(jí)功能但也是安全隱患最大的一塊。鴻蒙側(cè)適配時(shí)我沒(méi)有直接開(kāi)放一個(gè)任意代碼執(zhí)行的入口而是實(shí)現(xiàn)了一個(gè)命令注冊(cè)表。所有命令必須先在 Dart 層聲明并指定允許調(diào)用的原生動(dòng)作。比如DevPilot.instance.registerCommand( name: switchEnv, action: (args) async { await AppConfig.shared.changeEnv(args[env]); }, );原生側(cè)只負(fù)責(zé)接收命令名和參數(shù)再把它轉(zhuǎn)成回調(diào)。不認(rèn)識(shí)的命令統(tǒng)一返回404。這個(gè)設(shè)計(jì)不是為了炫技而是防止調(diào)試面板被打包到線上后成為攻擊面。鴻蒙側(cè)適配時(shí)我會(huì)額外加一層校驗(yàn)只有 debug 模式下才允許執(zhí)行命令。4.4 懸浮面板別一開(kāi)始就做系統(tǒng)級(jí)懸浮窗最初我想在鴻蒙上沿用 Android 的懸浮球方案結(jié)果發(fā)現(xiàn)系統(tǒng)級(jí)懸浮窗的權(quán)限申請(qǐng)和 Android 不太一樣而且審核和使用成本都會(huì)變高。后來(lái)我把方案調(diào)整成了 Flutter 層 Overlay 實(shí)現(xiàn)在 App 內(nèi)部疊加一個(gè)半透明面板不跨應(yīng)用也不需要特殊權(quán)限。這個(gè)調(diào)整反而讓鴻蒙適配簡(jiǎn)單了不少。因?yàn)?Overlay 是 Flutter 渲染層的能力和原生系統(tǒng)關(guān)系不大整個(gè)調(diào)試面板的 UI 可以完全復(fù)用真機(jī)上實(shí)測(cè)的懸浮和拖拽效果也夠用。如果你的調(diào)試庫(kù)也想支持鴻蒙建議一開(kāi)始就用 Flutter 層實(shí)現(xiàn)面板把系統(tǒng)級(jí)懸浮窗留到確有必要時(shí)再碰。5. 踩坑記錄連接真機(jī)后最容易坑的三件事骨架、通道、功能都寫完并不代表適配結(jié)束。真機(jī)調(diào)試階段我才真正感受到 Flutter 插件在鴻蒙這邊的“脾性”。下面這三件事每一個(gè)都讓我花了小半天時(shí)間排查。5.1 通道名不統(tǒng)一導(dǎo)致 MissingPluginException我最初在鴻蒙側(cè)把 MethodChannel 名稱寫成了dev_pilot/ohos而 Dart 端和 Android 端用的都是dev_pilot/channel。結(jié)果 Flutter 端調(diào)用時(shí)直接報(bào)錯(cuò)。這類問(wèn)題不會(huì)在編譯期暴露只會(huì)在運(yùn)行時(shí)報(bào)MissingPluginException。排查思路是這樣的先在 Dart 端打印每個(gè)調(diào)用的 channel name然后和原生側(cè)注冊(cè)的名字比對(duì)。更穩(wěn)妥的做法是把通道名統(tǒng)一集中到一個(gè)常量文件里Dart 和原生共用一份生成代碼避免各自維護(hù)。5.2 平臺(tái)回調(diào)線程問(wèn)題MethodChannel 的方法回調(diào)默認(rèn)跑在平臺(tái)主線程也就是 UI 線程。我在鴻蒙側(cè)剛開(kāi)始寫日志推送時(shí)直接把文件讀取和字符串處理都放在了回調(diào)里結(jié)果一打開(kāi)日志面板就感覺(jué)頁(yè)面掉幀。后來(lái)把日志采集丟到后臺(tái)協(xié)程通過(guò) Handler 回拋給 UI 線程問(wèn)題立刻緩解。這里想提醒一句不要因?yàn)樵谀M器上看不出問(wèn)題就忽略線程。真機(jī)上調(diào)試面板連著開(kāi)日志、內(nèi)存曲線對(duì)主線程的占用會(huì)非常明顯。所有涉及 IO 和解析的操作盡量從回調(diào)里挪出去。5.3 返回類型和參數(shù)精度的隱形坑鴻蒙側(cè)返回 Map 給 Flutter 時(shí)如果值是Long類型經(jīng)過(guò)二進(jìn)制消息編解碼后可能會(huì)變成Int超過(guò) Int 范圍還會(huì)出現(xiàn)溢出。我在做內(nèi)存信息時(shí)遇到過(guò)內(nèi)存數(shù)值對(duì)不上號(hào)的情況排查下來(lái)是類型精度問(wèn)題。解決辦法很直接在 Dart 端對(duì)關(guān)鍵字段做二次轉(zhuǎn)換比如(json[totalMemory] as num).toDouble()或者在原生側(cè)統(tǒng)一轉(zhuǎn)成字符串返回。我的建議是凡是這類可能溢出的數(shù)值字段原生側(cè)盡量返回字符串Dart 端再解析。損失一點(diǎn)效率換來(lái)穩(wěn)定。5.4 插件沒(méi)有隨包打進(jìn) Release 版本還有一次我在 debug 包上一切正常打贏發(fā)布包后打開(kāi)調(diào)試面板所有通道全部失效。查了半天發(fā)現(xiàn)是鴻蒙側(cè)插件模塊沒(méi)有被打進(jìn) Release 的 HAR 依賴?yán)?。?gòu)建配置里漏了一個(gè)模塊引用編譯期也不報(bào)錯(cuò)運(yùn)行期才暴露。這個(gè)坑特別適合遇到“真機(jī)正常發(fā)版異?!睍r(shí)優(yōu)先排查。檢查oh-package.json5和宿主的模塊依賴確保 plugin 不是只在 debug 配置里生效。6. 適配完成后的驗(yàn)證與交付配置代碼寫完了不代表可以直接交付。我這次做適配最后花了整整一個(gè)下午在真機(jī)上執(zhí)行驗(yàn)證清單很多問(wèn)題都是這個(gè)階段才暴露的。6.1 驗(yàn)證清單與關(guān)鍵場(chǎng)景我不建議只看單個(gè)功能是否正常而是要按真實(shí)調(diào)試流程走一遍。下面這份清單是我的內(nèi)部驗(yàn)收標(biāo)準(zhǔn)你可以直接拿來(lái)用驗(yàn)收?qǐng)鼍安僮鞑襟E預(yù)期結(jié)果插件可加載冷啟動(dòng) App打開(kāi) dev_pilot 面板無(wú) MissingPluginException設(shè)備信息完整在面板里查看設(shè)備型號(hào)與版本字段與系統(tǒng)設(shè)置一致日志實(shí)時(shí)推送在 Flutter 層打印多條日志面板內(nèi) 1 秒內(nèi)出現(xiàn)命令執(zhí)行注冊(cè) switchEnv 命令并執(zhí)行環(huán)境切換生效頁(yè)面銷毀重建反復(fù)進(jìn)出調(diào)試面板通道依然可用Release 包驗(yàn)證構(gòu)建發(fā)布包安裝到真機(jī)調(diào)試面板核心功能正常每項(xiàng)都記錄通過(guò)或不通過(guò)。不通過(guò)項(xiàng)要寫清楚是代碼問(wèn)題、權(quán)限問(wèn)題還是 API 兼容問(wèn)題不要籠統(tǒng)一句“有問(wèn)題”。6.2 交付時(shí)給團(tuán)隊(duì)的幾點(diǎn)配置建議適配完成后我還總結(jié)了幾條給團(tuán)隊(duì)成員的配置建議避免后續(xù)有人重新踩坑。第一dev_pilot 只應(yīng)在 debug 模式下啟用。鴻蒙側(cè)的BuildConfig判斷方式和 Android 略有不同但核心思路是發(fā)布包不要注冊(cè)插件入口或者至少不允許執(zhí)行調(diào)試命令。第二所有通道名不要散落寫死在業(yè)務(wù)代碼里統(tǒng)一收口到庫(kù)的常量文件。第三日志回傳功能默認(rèn)關(guān)閉由調(diào)試面板的開(kāi)關(guān)顯式打開(kāi)防止合入功能后不小心把日志一直掛在線上。第四如果團(tuán)隊(duì)有多個(gè) Flutter 業(yè)務(wù)模塊確認(rèn) dev_pilot 只被主工程引入一次避免多實(shí)例注冊(cè)造成通道沖突。6.3 后續(xù)擴(kuò)展方向這次我只遷移了設(shè)備信息、日志回傳、命令執(zhí)行和內(nèi)存曲線這幾個(gè)能力。dev_pilot 后續(xù)如果要在鴻蒙上做更深入的適配值得考慮的方向還有對(duì)齊 Android 側(cè)的網(wǎng)絡(luò)請(qǐng)求抓包能力、接入鴻蒙的分布式調(diào)試接口、把性能面板擴(kuò)展到 native 層的內(nèi)存統(tǒng)計(jì)以及針對(duì)折疊屏或平板形態(tài)做額外布局適配。我個(gè)人的建議是先保證核心調(diào)試鏈路在鴻蒙上穩(wěn)定跑通再做擴(kuò)展。一個(gè)能穩(wěn)定打開(kāi)、能看日志、能切環(huán)境、能拿設(shè)備信息的調(diào)試面板已經(jīng)可以覆蓋日常 80% 的聯(lián)調(diào)需求了。最后再分享一個(gè)小習(xí)慣適配完 Flutter 三方庫(kù)后記得在項(xiàng)目的 README 里補(bǔ)一張“鴻蒙適配狀態(tài)表”。把已經(jīng)支持的方法、已知問(wèn)題、驗(yàn)證機(jī)型都列出來(lái)。這看起來(lái)是件小事但它能幫后續(xù)接手的人在十分鐘內(nèi)判斷這個(gè)庫(kù)能不能用、缺什么、要改哪里。我這次做完 dev_pilot 的鴻蒙化適配后第一件事就是把這張表補(bǔ)進(jìn)文檔里隨后團(tuán)隊(duì)里再有同事提到鴻蒙調(diào)試需求直接看表就能知道該從哪里入手。