庫(kù)精簡(jiǎn)深度實(shí)戰(zhàn)——從鉆石依賴(lài)治理到 HSP 動(dòng)態(tài)共享的全鏈路優(yōu)化方案)
文章目錄每日一句正能量一、前言依賴(lài)庫(kù)是應(yīng)用體積的沉默膨脹器二、HarmonyOS 依賴(lài)庫(kù)精簡(jiǎn)技術(shù)全景圖三、鉆石依賴(lài)問(wèn)題與 overrides 版本統(tǒng)一3.1 鉆石依賴(lài)問(wèn)題的本質(zhì)3.2 overrides強(qiáng)制統(tǒng)一依賴(lài)版本3.3 本地包替換臨時(shí)修復(fù)四、HAR → HSP消除重復(fù)代碼拷貝4.1 HAR 與 HSP 的本質(zhì)差異4.2 HAR → HSP 替換實(shí)戰(zhàn)4.3 DevEco Studio 6.0 自動(dòng)去重五、ohpm 依賴(lài)分析工具鏈5.1 ohpm list查看完整依賴(lài)樹(shù)5.2 ohpm prune清理未使用依賴(lài)5.3 ohpm outdated檢測(cè)過(guò)期依賴(lài)5.4 --analyze編譯性能分析5.5 app-check-tool重復(fù)依賴(lài)掃描六、傳遞依賴(lài)優(yōu)化與循環(huán)依賴(lài)檢測(cè)6.1 傳遞依賴(lài)限制6.2 循環(huán)依賴(lài)檢測(cè)七、Feature HAP 按需加載終極依賴(lài)優(yōu)化八、實(shí)戰(zhàn)案例中型應(yīng)用依賴(lài)庫(kù)精簡(jiǎn)8.1 項(xiàng)目概況8.2 優(yōu)化步驟與效果8.3 優(yōu)化配置匯總九、CI/CD 集成自動(dòng)化依賴(lài)治理十、總結(jié)與最佳實(shí)踐每日一句正能量求木之長(zhǎng)者必固其根本欲流之遠(yuǎn)者必浚其泉源。無(wú)論是個(gè)人成長(zhǎng)、事業(yè)建設(shè)還是關(guān)系經(jīng)營(yíng)追逐枝葉的繁茂速成、表象不如深耕根本能力、品德、健康想要源遠(yuǎn)流長(zhǎng)就必須疏通源頭初心、動(dòng)機(jī)、系統(tǒng)。一切長(zhǎng)久的美好都離不開(kāi)扎實(shí)的基礎(chǔ)。一、前言依賴(lài)庫(kù)是應(yīng)用體積的沉默膨脹器在 HarmonyOS 應(yīng)用開(kāi)發(fā)中依賴(lài)庫(kù)的管理是一個(gè)容易被忽視但影響深遠(yuǎn)的環(huán)節(jié)。隨著業(yè)務(wù)迭代項(xiàng)目中的依賴(lài)數(shù)量會(huì)不斷增長(zhǎng)——三方 SDK、內(nèi)部工具庫(kù)、UI 組件庫(kù)、網(wǎng)絡(luò)請(qǐng)求庫(kù)、數(shù)據(jù)存儲(chǔ)庫(kù)……每一個(gè)依賴(lài)的引入都看似微不足道但累積起來(lái)卻能讓?xiě)?yīng)用的包體積膨脹到難以控制的程度。更隱蔽的是鉆石依賴(lài)問(wèn)題當(dāng)多個(gè)模塊依賴(lài)同一個(gè)庫(kù)的不同版本時(shí)包管理器OHPM默認(rèn)選擇最近版本這可能導(dǎo)致編譯失敗或運(yùn)行時(shí)崩潰。而對(duì)于包含 Native 代碼C的依賴(lài)版本不兼容會(huì)直接引發(fā)符號(hào)表錯(cuò)誤造成應(yīng)用啟動(dòng)即崩潰。HarmonyOS 提供了完整的依賴(lài)治理工具鏈從ohpm list查看依賴(lài)樹(shù)、ohpm prune清理未使用依賴(lài)、overrides統(tǒng)一版本到deduplicateHar自動(dòng)去重、HAR→HSP 動(dòng)態(tài)共享替換。本文將系統(tǒng)講解這些技術(shù)的原理、配置方法和實(shí)戰(zhàn)技巧幫助開(kāi)發(fā)者實(shí)現(xiàn)依賴(lài)體積減少45%、整體包體積減少35%的目標(biāo)。二、HarmonyOS 依賴(lài)庫(kù)精簡(jiǎn)技術(shù)全景圖HarmonyOS 的依賴(lài)庫(kù)精簡(jiǎn)可分為三大維度依賴(lài)去重、版本治理、按需加載每個(gè)維度都有對(duì)應(yīng)的官方工具支持。優(yōu)化維度核心技術(shù)工具支持預(yù)期效果依賴(lài)去重ohpm 依賴(lài)去重、HAR→HSP 替換、deduplicateHarapp-check-tool、Build Analyzer減少 30-50% 重復(fù)依賴(lài)體積版本治理overrides 統(tǒng)一版本、resolutionStrictness、鉆石依賴(lài)消除ohpm list、ohpm outdated消除版本沖突提升編譯穩(wěn)定性按需加載Feature HAP 拆分、動(dòng)態(tài) import、延遲初始化hvigor、app-check-tool減少 60-70% 初始包體積三、鉆石依賴(lài)問(wèn)題與 overrides 版本統(tǒng)一3.1 鉆石依賴(lài)問(wèn)題的本質(zhì)鉆石依賴(lài)Diamond Dependency是多模塊工程中最常見(jiàn)的問(wèn)題之一。當(dāng)兩個(gè)不同的模塊分別依賴(lài)同一個(gè)庫(kù)的不同版本時(shí)包管理器需要決定使用哪個(gè)版本——這個(gè)決定可能引發(fā)連鎖反應(yīng)。典型場(chǎng)景MyApp ├── Entry HAP → ohos/aki1.0.0 ├── Feature Pay HAP → ohos/aki1.1.0 └── Feature Chat HAP → ohos/aki1.0.0在這個(gè)場(chǎng)景中Entry 和 Feature Chat 依賴(lài)aki1.0.0Feature Pay 依賴(lài)aki1.1.0OHPM 默認(rèn)選擇最近版本1.1.0但aki1.1.0的 Native 符號(hào)表與aki1.0.0不兼容結(jié)果Entry 和 Feature Chat 在調(diào)用aki的 Native 方法時(shí)發(fā)生符號(hào)解析失敗應(yīng)用崩潰3.2 overrides強(qiáng)制統(tǒng)一依賴(lài)版本overrides是 OHPM 提供的版本覆蓋機(jī)制可以在工程級(jí)oh-package.json5中強(qiáng)制指定所有模塊包括傳遞依賴(lài)使用的版本。// 工程級(jí) oh-package.json5項(xiàng)目根目錄 { name: MyHarmonyApp, version: 1.0.0, description: 示例 HarmonyOS 應(yīng)用, // overrides: 強(qiáng)制所有模塊使用指定版本 overrides: { ohos/aki: 1.1.0, // 統(tǒng)一使用 1.1.0 ohos/net: 1.2.0, // 統(tǒng)一使用 1.2.0 ohos/crypto: 2.0.1, // 統(tǒng)一使用 2.0.1 ohos/file.picker: 1.0.5 // 統(tǒng)一使用 1.0.5 }, // strict 模式強(qiáng)制嚴(yán)格匹配版本不一致時(shí)直接報(bào)錯(cuò) resolutionStrictness: strict }overrides 的優(yōu)先級(jí)規(guī)則最高優(yōu)先級(jí)overrides中的聲明次優(yōu)先級(jí)模塊級(jí)dependencies中的聲明最低優(yōu)先級(jí)傳遞依賴(lài)的默認(rèn)版本strict 模式的作用# 若某個(gè)模塊的 dependencies 中聲明了與 overrides 不一致的版本# strict 模式下 OHPM 會(huì)直接報(bào)錯(cuò)而不是靜默覆蓋# 示例報(bào)錯(cuò)信息# ERROR: Module feature_pay depends on ohos/aki1.0.0,# but overrides requires ohos/aki1.1.0.# Please update the dependency version.3.3 本地包替換臨時(shí)修復(fù)當(dāng)某個(gè)三方庫(kù)存在 bug 但官方尚未修復(fù)時(shí)可以通過(guò)overrides指定本地修改后的版本{ overrides: { ohos/file.photoPicker: file:./local_patches/photoPicker_fixed } }local_patches/ └── photoPicker_fixed/ ├── oh-package.json5 ├── index.ets └── ...注意事項(xiàng)overrides僅在工程級(jí)oh-package.json5中生效修改overrides后需要重新執(zhí)行ohpm install本地包替換僅適用于臨時(shí)修復(fù)長(zhǎng)期應(yīng)推動(dòng)官方修復(fù)四、HAR → HSP消除重復(fù)代碼拷貝4.1 HAR 與 HSP 的本質(zhì)差異特性HAR靜態(tài)共享包HSP動(dòng)態(tài)共享包復(fù)用時(shí)機(jī)編譯時(shí)代碼復(fù)制到每個(gè)模塊運(yùn)行時(shí)動(dòng)態(tài)加載進(jìn)程中僅一份包體積影響增加重復(fù)代碼減少共享代碼編譯產(chǎn)物每個(gè)模塊獨(dú)立包含 HAR 代碼HSP 獨(dú)立打包模塊僅保留引用適用場(chǎng)景三方庫(kù)分發(fā)、獨(dú)立工具類(lèi)應(yīng)用內(nèi)多模塊共享代碼以一個(gè)包含 Entry HAP 3 個(gè) Feature HAP 的工程為例若utils.har100KB、network.har200KB和chart.har300KB被多個(gè)模塊引用使用 HAR總包體積 各模塊自身代碼 utils×3 network×3 chart×3 3000KB使用 HSP總包體積 各模塊自身代碼 utils×1 network×1 chart×1 1800KB體積減少1200KB40%4.2 HAR → HSP 替換實(shí)戰(zhàn)步驟一創(chuàng)建 HSP 模塊// shared_utils/module.json5 { module: { name: shared_utils, type: shared, description: 公共工具類(lèi)動(dòng)態(tài)共享包, mainElement: SharedUtilsAbility, abilities: [ { name: SharedUtilsAbility, srcEntry: ./ets/utilsability/UtilsAbility.ets } ] } }步驟二修改各模塊的依賴(lài)引用// entry/oh-package.json5 { dependencies: { // 原 HAR 依賴(lài)編譯時(shí)拷貝 // myapp/utils: file:./utils.har // 改為 HSP 依賴(lài)運(yùn)行時(shí)共享 myapp/utils: file:./shared_utils } }步驟三HSP 混淆白名單配置由于 HAP 和 HSP 是獨(dú)立編譯的混淆后導(dǎo)出名稱(chēng)可能不一致需要配置白名單// shared_utils/consumer-rules.txt-keep-global-name formatDate parseUrl deepClone NetworkManager StorageManager// shared_utils/obfuscation-rules.txt-keep-global-name formatDate parseUrl deepClone NetworkManager StorageManager4.3 DevEco Studio 6.0 自動(dòng)去重從 DevEco Studio 6.0.1 Beta1 開(kāi)始支持在構(gòu)建 APP/HAP/HSP 時(shí)自動(dòng)去除 HSP 中重復(fù)的 HAR// 工程級(jí) build-profile.json5 { apiType: stageMode, buildOption: { packOptions: { deduplicateHar: true // 去除 HSP 中重復(fù)的 HAR } }, useNormalizedOHMUrl: true }效果當(dāng)多個(gè) HSP 引用了同一個(gè) HAR 時(shí)構(gòu)建工具會(huì)自動(dòng)去重確保最終包中該 HAR 僅存在一份。五、ohpm 依賴(lài)分析工具鏈HarmonyOS 提供了完整的依賴(lài)分析工具鏈幫助開(kāi)發(fā)者全面了解項(xiàng)目的依賴(lài)狀況。5.1 ohpm list查看完整依賴(lài)樹(shù)# 查看當(dāng)前模塊的依賴(lài)樹(shù)包含傳遞依賴(lài)ohpm list--depth3# 輸出示例# MyHarmonyApp# ├── ohos/aki1.1.0# │ └── ohos/crypto2.0.1# ├── ohos/net1.2.0# │ ├── ohos/aki1.1.0 (dedup)# │ └── ohos/utils1.0.0# ├── ohos/chart3.0.0# │ └── ohos/aki1.1.0 (dedup)# └── ohos/file.picker1.0.5# 查找特定依賴(lài)的所有版本ohpm list--depth3|grepohos/aki# 查看依賴(lài)樹(shù)并標(biāo)記重復(fù)項(xiàng)ohpm list--depth3--duplicates5.2 ohpm prune清理未使用依賴(lài)# 清理當(dāng)前模塊中未使用的依賴(lài)ohpm prune# 清理所有模塊的未使用依賴(lài)ohpm prune--all# 清理并更新 oh-package-lock.json5ohpm prune--update# 清理并顯示詳細(xì)信息ohpm prune--verbose注意事項(xiàng)ohpm prune基于oh-package-lock.json5分析依賴(lài)使用關(guān)系清理前建議備份oh-package-lock.json5清理后需要重新構(gòu)建驗(yàn)證功能完整性5.3 ohpm outdated檢測(cè)過(guò)期依賴(lài)# 檢測(cè)所有過(guò)期依賴(lài)ohpm outdated# 輸出示例# Package Current Wanted Latest# ohos/net 1.1.0 1.2.0 1.2.0# ohos/crypto 1.5.0 2.0.1 2.0.1# ohos/chart 2.5.0 3.0.0 3.0.0# 導(dǎo)出 JSON 格式報(bào)告ohpm outdated--jsonoutdated-report.json# 僅檢測(cè)安全更新ohpm outdated--security5.4 --analyze編譯性能分析# 生成編譯性能依賴(lài)圖hvigorw assembleRelease--analyze# 分析結(jié)果保存在 build/reports/analyze/# 包含# - 各模塊編譯耗時(shí)# - 依賴(lài)解析耗時(shí)# - 循環(huán)依賴(lài)檢測(cè)# - 冗余依賴(lài)警告5.5 app-check-tool重復(fù)依賴(lài)掃描# 掃描 HAP/HSP 包中的重復(fù) HARjava-jar$OHOS_SDK/toolchains/lib/app-check-tool.jar\--modehap\--inputbuild/outputs/default/packaging/entry-default-signed.hap\--output./scan-report/# 掃描結(jié)果中的重復(fù)依賴(lài)示例# {# duplicateAnalysis: [# {# fileName: libnetwork.so,# occurrences: 4,# wastedSize: 25794972,# suggestion: 建議將包含 libnetwork.so 的 HAR 包改為 HSP 動(dòng)態(tài)共享包# }# ]# }六、傳遞依賴(lài)優(yōu)化與循環(huán)依賴(lài)檢測(cè)6.1 傳遞依賴(lài)限制默認(rèn)情況下OHPM 會(huì)安裝所有傳遞依賴(lài)即依賴(lài)的依賴(lài)。對(duì)于大型項(xiàng)目這可能導(dǎo)致依賴(lài)樹(shù)深度膨脹。// oh-package.json5 - 限制傳遞依賴(lài) { dependencies: { ohos/net: { version: 1.2.0, transitive: false // 不安裝 net 的傳遞依賴(lài) } } }使用場(chǎng)景當(dāng)某個(gè)依賴(lài)的傳遞依賴(lài)與項(xiàng)目已有依賴(lài)沖突時(shí)當(dāng)只需要依賴(lài)的核心功能不需要其附屬庫(kù)時(shí)當(dāng)傳遞依賴(lài)體積過(guò)大且功能非必需時(shí)6.2 循環(huán)依賴(lài)檢測(cè)循環(huán)依賴(lài)A → B → C → A會(huì)導(dǎo)致編譯時(shí)依賴(lài)解析死循環(huán)或運(yùn)行時(shí)初始化異常。# 使用 hvigor 的 --analyze 選項(xiàng)檢測(cè)循環(huán)依賴(lài)hvigorw assembleRelease--analyze# 循環(huán)依賴(lài)報(bào)錯(cuò)示例# ERROR: Circular dependency detected:# module_a - module_b - module_c - module_a## Solution: Extract common code into a new HSP module.循環(huán)依賴(lài)的解決方案提取公共代碼將循環(huán)依賴(lài)中的公共部分提取為獨(dú)立的 HSP 模塊接口隔離使用接口Interface解耦模塊間的直接依賴(lài)事件總線使用事件機(jī)制替代直接的模塊調(diào)用// 解耦前循環(huán)依賴(lài)// module_a/ets/A.etsimport{B}frommyapp/module_b;// A → B// module_b/ets/B.etsimport{C}frommyapp/module_c;// B → C// module_c/ets/C.etsimport{A}frommyapp/module_a;// C → A (循環(huán))// 解耦后事件總線// shared_events/ets/EventBus.etsexportclassEventBus{privatestaticlisteners:Mapstring,Array(data:any)voidnewMap();staticon(event:string,callback:(data:any)void):void{if(!this.listeners.has(event)){this.listeners.set(event,[]);}this.listeners.get(event)!.push(callback);}staticemit(event:string,data:any):void{this.listeners.get(event)?.forEach(cbcb(data));}}// module_a/ets/A.etsimport{EventBus}frommyapp/shared_events;EventBus.emit(module_a_ready,{status:ok});// module_c/ets/C.etsimport{EventBus}frommyapp/shared_events;EventBus.on(module_a_ready,(data){console.log(Module A is ready:,data);});七、Feature HAP 按需加載終極依賴(lài)優(yōu)化對(duì)于非核心功能模塊如客服聊天、地圖導(dǎo)航、支付功能可以拆分為獨(dú)立的 Feature HAP通過(guò)動(dòng)態(tài)導(dǎo)入按需加載。// 動(dòng)態(tài)導(dǎo)入 Feature 模塊asyncfunctionopenCustomerService(){try{// 首次調(diào)用時(shí)下載并加載 Feature HAPconstmoduleawaitimport(myapp/feature_customer_service);module.launchCustomerService();}catch(err){console.error(模塊加載失敗:,err);promptAction.showToast({message:功能加載失敗請(qǐng)檢查網(wǎng)絡(luò)});}}// 工程級(jí) build-profile.json5 配置{modules:[{name:entry,srcPath:./entry},{name:feature_customer_service,srcPath:./feature_customer_service,targets:[{name:default,applyToProducts:[default]}]},{name:feature_map,srcPath:./feature_map,targets:[{name:default,applyToProducts:[default]}]}]}效果初始安裝包僅包含 Entry HAP 和必要的 HSPFeature HAP 在用戶(hù)首次觸發(fā)功能時(shí)下載典型場(chǎng)景下初始包體積減少60-70%八、實(shí)戰(zhàn)案例中型應(yīng)用依賴(lài)庫(kù)精簡(jiǎn)8.1 項(xiàng)目概況模塊數(shù)量Entry HAP ×1 Feature HAP ×3 HAR ×8三方依賴(lài)15 個(gè)初始依賴(lài)體積28.5 MB初始總包體積156.3 MB8.2 優(yōu)化步驟與效果優(yōu)化項(xiàng)優(yōu)化前優(yōu)化后減少比例具體措施overrides 版本統(tǒng)一依賴(lài) 28.5MB依賴(lài) 20.0MB30%統(tǒng)一 5 個(gè)沖突庫(kù)版本HAR→HSP 替換重復(fù) 12MB重復(fù) 0MB100%3 個(gè) HAR 改為 HSPohpm prune未使用 8MB未使用 0MB100%清理 4 個(gè)未使用依賴(lài)deduplicateHar重復(fù) HAR 6MB重復(fù) HAR 3MB50%DevEco 6.0 自動(dòng)去重傳遞依賴(lài)限制傳遞依賴(lài) 15MB傳遞依賴(lài) 9MB40%限制 3 個(gè)庫(kù)的傳遞依賴(lài)過(guò)期依賴(lài)升級(jí)舊版本 5MB新版本 4MB20%升級(jí) 2 個(gè)過(guò)期庫(kù)Feature HAP 拆分初始包 156MB初始包 48MB70%2 個(gè)功能模塊按需加載循環(huán)依賴(lài)修復(fù)編譯不穩(wěn)定編譯穩(wěn)定—提取公共 HSP 解耦合計(jì)156.3MB48.0MB69%—8.3 優(yōu)化配置匯總// 工程級(jí) oh-package.json5 { name: MyHarmonyApp, version: 2.0.0, overrides: { ohos/aki: 1.1.0, ohos/net: 1.2.0, ohos/crypto: 2.0.1, ohos/file.picker: 1.0.5, ohos/chart: 3.0.0 }, resolutionStrictness: strict }// 工程級(jí) build-profile.json5 { apiType: stageMode, buildOption: { packOptions: { deduplicateHar: true } }, useNormalizedOHMUrl: true, modules: [ { name: entry, srcPath: ./entry }, { name: shared_utils, srcPath: ./shared_utils }, { name: shared_network, srcPath: ./shared_network }, { name: feature_pay, srcPath: ./feature_pay }, { name: feature_chat, srcPath: ./feature_chat } ] }九、CI/CD 集成自動(dòng)化依賴(lài)治理# .github/workflows/dependency-check.ymlname:Dependency Governanceon:[push,pull_request]jobs:check:runs-on:ubuntu-lateststeps:-uses:actions/checkoutv4-name:Check dependency conflictsrun:|ohpm list --depth3 --json dependency-tree.json conflicts$(cat dependency-tree.json | jq [.. | objects | select(has(version)) | {name: keys[0], version: .version}] | group_by(.name) | map(select(length 1))) if [ $conflicts ! [] ]; then echo ? 發(fā)現(xiàn)依賴(lài)版本沖突: echo $conflicts | jq . exit 1 fi echo ? 依賴(lài)沖突檢查通過(guò)-name:Check outdated dependenciesrun:|ohpm outdated --json outdated.json outdated_count$(cat outdated.json | jq length) if [ $outdated_count -gt 5 ]; then echo ?? 發(fā)現(xiàn) $outdated_count 個(gè)過(guò)期依賴(lài)建議升級(jí) cat outdated.json | jq .[] | {name, current, latest} fi-name:Check for unused dependenciesrun:|ohpm prune --all --dry-run-name:Build with analyzerun:|hvigorw assembleRelease --analyze-name:Check bundle sizerun:|size$(stat -c%s build/outputs/default/packaging/app-signed.app) limit$((50 * 1024 * 1024)) # 50MB if [ $size -gt $limit ]; then echo ? 包體積超標(biāo): $size bytes $limit bytes exit 1 fi echo ? 包體積檢查通過(guò)-name:Generate dependency reportrun:|echo ## 依賴(lài)治理報(bào)告 dependency-report.md echo dependency-report.md echo ### 依賴(lài)樹(shù)概覽 dependency-report.md ohpm list --depth2 dependency-report.md echo dependency-report.md echo ### 過(guò)期依賴(lài) dependency-report.md ohpm outdated dependency-report.md || true十、總結(jié)與最佳實(shí)踐本文從鉆石依賴(lài)治理出發(fā)系統(tǒng)講解了 HarmonyOS 依賴(lài)庫(kù)精簡(jiǎn)的全鏈路方案涵蓋版本統(tǒng)一、重復(fù)消除、未使用清理、按需加載等核心技術(shù)。核心最佳實(shí)踐清單工程級(jí) overrides所有多模塊工程必須在根目錄oh-package.json5中配置overrides統(tǒng)一關(guān)鍵依賴(lài)版本HAR→HSP 優(yōu)先被多模塊引用的共享代碼優(yōu)先使用 HSP消除重復(fù)拷貝定期 prune每月執(zhí)行ohpm prune --all清理未使用依賴(lài)過(guò)期檢測(cè)每季度執(zhí)行ohpm outdated檢測(cè)并升級(jí)過(guò)期依賴(lài)傳遞限制對(duì)于體積大的依賴(lài)評(píng)估是否需要限制其傳遞依賴(lài)循環(huán)檢測(cè)每次新增模塊依賴(lài)時(shí)使用--analyze檢測(cè)循環(huán)依賴(lài)按需加載非核心功能拆分為 Feature HAP減少初始包體積依賴(lài)庫(kù)精簡(jiǎn)不是一次性的大掃除而是需要持續(xù)監(jiān)控的日常工程實(shí)踐。通過(guò)建立規(guī)范化的依賴(lài)治理體系和自動(dòng)化的檢查機(jī)制可以確保應(yīng)用始終保持輕量、穩(wěn)定、易維護(hù)的依賴(lài)結(jié)構(gòu)。轉(zhuǎn)載自https://blog.csdn.net/u014727709/article/details/164003986歡迎 點(diǎn)贊?評(píng)論?收藏歡迎指正