作者视角: 本文面向从 iOS/Android/鸿蒙原生开发转型 uni-app 跨端开发的工程师。你习惯了 CocoaPods、Gradle、OHPM 那套成熟的包管理体系,来到 uni-app 后大概率会困惑: "我的依赖到底该放哪?谁管版本?谁解析传递依赖?" 这篇文章将一次性把这些困惑讲透。
一、为什么 uni-app 的依赖管理"看起来复杂"?
1.1 原生世界的"一平台一管家"
在纯原生开发中,每个平台有唯一、权威的包管理器:
| 平台 | 包管理器 | 核心特征 |
|---|---|---|
| iOS | CocoaPods / SPM / Carthage | 声明式、版本锁定(Podfile.lock)、自动解析传递依赖、支持私有 Spec Repo |
| Android | Gradle (Maven Central / JitPack) | 声明式、版本锁定(gradle.lockfile)、传递依赖自动协商、支持私有 Maven 仓库 |
| 鸿蒙 | OHPM | 声明式、版本锁定(oh-package-lock.json5)、支持私有 Registry |
| H5/前端 | npm / yarn / pnpm | 声明式、版本锁定(lock文件)、Node生态 |
你只需要记住一套规则,所有依赖都走同一条管道。
1.2 跨端框架的"多轨并行"
uni-app 的目标是一套代码 → 多端运行。但各端的原生能力不同、包管理协议不同、运行时环境不同,因此它不可能用"一个包管理器"覆盖所有场景。
最终的结果是:uni-app 用三层并行体系管理依赖,每层解决不同层面的问题。这不是设计缺陷,而是跨端框架的必然选择。
二、三层依赖体系全景图
1┌─────────────────────────────────────────────────────────────────────┐ 2│ 你的 uni-app 项目 │ 3├─────────────────┬──────────────────────┬────────────────────────────┤ 4│ 第一层 │ 第二层 │ 第三层 │ 5│ npm / pnpm │ DCloud 插件市场 │ 各端原生包管理器 │ 6│ (JS/TS 纯逻辑库)│ (uni_modules 规范) │ (CocoaPods/Gradle/OHPM) │ 7├─────────────────┼──────────────────────┼────────────────────────────┤ 8│ • pinia/vuex │ • UI 组件库 │ • iOS: Podfile / SPM │ 9│ • dayjs/lodash │ • 原生能力封装插件 │ • Android: build.gradle │ 10│ • zod/yup │ • UTS 插件 │ • 鸿蒙: oh-package.json5 │ 11│ • vue-router │ • 云函数/Schema │ • H5: npm (浏览器端) │ 12│ • 纯算法库 │ • 页面模板/项目模板 │ • 小程序: 受限 npm │ 13├─────────────────┼──────────────────────┼────────────────────────────┤ 14│ 管理方式: │ 管理方式: │ 管理方式: │ 15│ package.json │ uni_modules/ 目录 │ 嵌入在 uni_modules 插件内 │ 16│ + lock 文件 │ + package.json │ 编译时由构建工具自动调用 │ 17│ CLI: npm install│ GUI: HBuilderX 导入 │ pod install / gradle sync │ 18├─────────────────┼──────────────────────┼────────────────────────────┤ 19│ 版本控制: ✅ │ 版本控制: ⚠️ 无lock │ 版本控制: ✅ (跟随原生体系) │ 20│ 传递依赖: ✅ │ 传递依赖: ⚠️ 仅一层 │ 传递依赖: ✅ │ 21│ 私有源: ✅ │ 私有源: ⚠️ Git/手动 │ 私有源: ✅ │ 22└─────────────────┴──────────────────────┴────────────────────────────┘ 23
核心认知: 这三层不是互斥的,而是互补嵌套的。一个完整的原生能力插件往往同时涉及三层——npm 提供 JS 接口层 → uni_modules 提供跨端胶水代码和目录规范 → 各端原生包管理器提供底层 SDK 实现。
三、第一层:npm/pnpm — 纯 JS/TS 逻辑库
3.1 定位
这一层管理的是不涉及任何原生 API 调用的纯 JavaScript/TypeScript 库。它们运行在 JavaScript 引擎中,与平台无关。
3.2 适用场景与选型
| 类别 | 推荐库 | 跨端兼容性 | 注意事项 |
|---|---|---|---|
| 状态管理 | pinia | ✅ 全端 | Vue3 项目首选 |
| 工具函数 | lodash-es, dayjs, uuid | ✅ 全端 | 必须用 ESM 版本 |
| 数据校验 | zod, yup, valibot | ✅ 全端 | 注意包体积 |
| 数学/加密 | crypto-js, bignumber.js | ✅ 全端 | — |
| 网络请求 | — | ❌ 不用 axios | 小程序无 XHR,用 uni.request |
| DOM 操作 | jquery, d3-dom | ❌ 仅 H5 | 小程序/App 无 DOM |
| 动画 | lottie-web | ⚠️ 仅 H5 | App端用原生插件替代 |
| 图表 | ucharts (uni_modules) | ✅ 全端 | 优先选 uni_modules 版本 |
3.3 使用方式
1# 与标准前端项目完全一致 2npm install dayjs pinia zod 3npm install -D @types/lodash-es 4 5# 或使用 pnpm(推荐,速度快、磁盘省) 6pnpm add dayjs pinia 7
3.4 关键注意事项(踩坑清单)
| 坑点 | 原因 | 解决方案 |
|---|---|---|
| CommonJS vs ESM | 小程序编译器对 CJS 支持不完整,部分 require() 写法会报错 | 优先选择 ESM 版本的库(如 lodash-es 而非 lodash) |
| Node.js 内置模块 | fs、path、Buffer、process 在小程序/App 中不存在 | 检查库的依赖树,避免引入 Node-only 的包 |
| DOM/BOM 全局对象 | window、document、navigator 在非 H5 端不存在 | 用条件编译 #ifdef H5 包裹,或选跨端库 |
| 包体积限制 | 微信小程序主包限 2MB,总包限 20MB | 按需引入 + tree-shaking + 分包 |
| ES2022+ 语法 | 部分新版库使用了 ?.、??、class fields 等语法,低版本小程序基础库不支持 | 配置 babel/vite 转译目标,或降级库版本 |
| 动态 import | 小程序不支持 import() 动态导入 | 使用分包或 require.async(部分平台) |
3.5 与原生类比
把这一层理解为 iOS 中纯 Swift 算法库(如 Swift Algorithms)——不依赖 UIKit,不依赖 Foundation 的平台特有 API,在任何 target 上都能编译运行。如果一个库需要访问摄像头、蓝牙、文件系统,它就不属于这一层,而属于第二层或第三层。
四、第二层:DCloud 插件市场 + uni_modules — 跨端插件体系(核心)
4.1 uni_modules 是什么?
uni_modules 是 DCloud 定义的跨端插件模块化规范(HBuilderX 3.1.0+ 支持)。它是 uni-app 生态的"官方插件标准",相当于 uni-app 自己的 "CocoaPods Spec"。
一个 uni_module 可以包含:Vue 组件、JS SDK、UTS 原生代码、uniCloud 云函数、页面模板、公共模块——一个插件解决一个完整的功能需求。
4.2 标准目录结构
1uni_modules/ 2└── uni-camera-pro/ ← 插件ID(全局唯一标识) 3 ├── package.json ← 🔑 插件元信息 + 依赖声明 4 ├── changelog.md ← 更新日志 5 ├── readme.md ← 使用文档 6 │ 7 ├── components/ ← Vue 组件(跨端) 8 │ └── camera-view.vue 9 │ 10 ├── js_sdk/ ← JS/TS API 封装 11 │ └── index.ts 12 │ 13 ├── utssdk/ ← 🔑 UTS 原生插件代码(新方式) 14 │ ├── interface.uts ← 跨平台统一接口定义 15 │ ├── app-ios/ ← iOS 平台实现 16 │ │ ├── index.uts 17 │ │ └── config.json ← iOS 原生依赖配置 18 │ ├── app-android/ ← Android 平台实现 19 │ │ ├── index.uts 20 │ │ └── config.json ← Android 原生依赖配置 21 │ ├── app-harmony/ ← 鸿蒙平台实现 22 │ │ ├── index.uts 23 │ │ └── config.json ← 鸿蒙原生依赖配置 24 │ ├── mp-weixin/ ← 小程序平台实现 25 │ │ └── index.uts 26 │ └── web/ ← H5 平台实现 27 │ └── index.uts 28 │ 29 ├── uniCloud-aliyun/ ← 云函数(可选) 30 │ └── cloudfunctions/ 31 │ 32 └── pages/ ← 页面模板(可选) 33 └── demo/ 34
4.3 package.json 核心字段
1{ 2 "id": "uni-camera-pro", 3 "displayName": "专业相机插件", 4 "version": "2.3.1", 5 "description": "支持HDR、慢动作、多摄切换的相机组件", 6 "keywords": ["camera", "拍照", "录像"], 7 "repository": "https://github.com/xxx/uni-camera-pro", 8 "engines": { 9 "HBuilderX": "^4.0.0" 10 }, 11 "dcloudext": { 12 "type": "uts", 13 "sale": { 14 "regular": { "price": "0.00" }, 15 "sourcecode": { "price": "199.00" } 16 }, 17 "contact": { "qq": "" }, 18 "declaration": { 19 "ads": "无广告", 20 "data": "插件不采集任何数据", 21 "permissions": "需要相机、麦克风、存储权限" 22 }, 23 "npmurl": "" 24 }, 25 "uni_modules": { 26 "dependencies": [ 27 "uni-permission-helper" 28 ], 29 "encrypt": [], 30 "platforms": { 31 "cloud": { "tcb": "y", "aliyun": "y" }, 32 "client": { 33 "App": { "app-vue": "y", "app-nvue": "y", "app-uvue": "y" }, 34 "H5-mobile": { "Safari": "y", "Android Browser": "y" }, 35 "H5-pc": { "Chrome": "y" }, 36 "小程序": { "微信": "y", "支付宝": "y" }, 37 "快应用": { "华为": "n" } 38 } 39 } 40 } 41} 42
4.4 安装方式
方式一:HBuilderX 插件市场导入(推荐)
1HBuilderX → 工具 → 插件安装 → 浏览插件市场 2→ 搜索插件名 → 点击"导入插件" → 选择目标项目 → 完成 3
优势: 自动创建目录结构、自动安装子依赖、自动合并 pages.json 配置。
方式二:CLI 项目手动安装
1# 从插件市场下载 zip 包 2# 解压到项目的 uni_modules/ 目录下 3# HBuilderX 或编译器会自动识别 4 5# 如果是 Git 仓库形式的插件 6git clone https://github.com/xxx/uni-camera-pro.git uni_modules/uni-camera-pro 7
方式三:直接复制源码
从插件市场下载 → 解压 → 拖入 uni_modules/ 目录 → 编辑器自动识别。
4.5 依赖安装
当插件声明了 npm 依赖或其他 uni_modules 依赖时:
1HBuilderX → 右键 uni_modules/插件名 → 安装插件依赖 2
或在 CLI 项目中:
1cd uni_modules/uni-camera-pro 2npm install 3
4.6 uni_modules 的局限性(与 CocoaPods/Gradle 对比)
| 特性 | CocoaPods / Gradle | uni_modules |
|---|---|---|
| 版本锁定文件 | ✅ Podfile.lock / gradle.lockfile | ❌ 无 lock 文件 |
| 传递依赖自动解析 | ✅ 递归解析所有层级 | ⚠️ 仅解析一层,嵌套需手动 |
| 版本冲突自动协商 | ✅ 自动选择兼容版本 | ❌ 手动处理 |
| 私有源/仓库 | ✅ Spec Repo / Maven Repo | ⚠️ 需 Git 或手动拷贝 |
| CI/CD 自动化 | ✅ 命令行全自动 | ⚠️ 依赖 HBuilderX GUI |
| 离线缓存 | ✅ 本地 Cache | ❌ 每次重新下载 |
| 付费/加密保护 | N/A | ✅ DCloud 提供版权保护 |
4.7 应对策略(团队/CI 场景)
1# .gitignore 配置 2node_modules/ 3 4# ⚠️ 不要忽略 uni_modules! 5# uni_modules/ ← 不要写这行! 6 7# 但可以忽略插件内部的临时文件 8uni_modules/*/node_modules/ 9uni_modules/*/.DS_Store 10
核心建议: 将
uni_modules目录完整纳入 Git 版本管理。这样所有团队成员和 CI 服务器使用的插件版本完全一致,弥补了没有 lock 文件的缺陷。这也是 DCloud 官方推荐的做法。
五、第三层:各端原生包管理器 — 插件的"引擎室"
当一个 uni_modules 插件需要调用原生 SDK(如高德地图、支付宝支付、推送服务)时,它内部会嵌入各端的原生依赖配置。这才是真正对接 CocoaPods/Gradle/OHPM 的地方。
5.1 两种原生插件形态(重要区分)
| 形态 | 状态 | 说明 |
|---|---|---|
| App 原生语言插件 | ⚠️ 已停止维护(2025年5月起) | 用 ObjC/Swift/Java/Kotlin 直接编写,放在 nativeplugins/ 目录 |
| UTS 插件 | ✅ 官方主推,持续发展 | 用 UTS 语言编写,放在 uni_modules/插件名/utssdk/ 目录 |
⚠️ 重要: 自 2025 年 5 月 1 日起,DCloud 官方已限制 App 原生语言插件的迭代。新项目一律使用 UTS 插件。已有原生语言插件仍可运行,但建议逐步迁移到 UTS。
5.2 UTS 插件中各端原生依赖配置(config.json)
UTS 插件的每个平台目录下都有一个 config.json,用于声明该平台的原生依赖。这是 uni-app 对接原生包管理器的核心桥梁。
iOS 端:utssdk/app-ios/config.json
1{ 2 "deploymentTarget": "12.0", 3 "dependencies": { 4 "pods": { 5 "SDWebImage": { 6 "version": "~> 5.18" 7 }, 8 "Lottie": { 9 "version": "~> 4.4" 10 }, 11 "AFNetworking": { 12 "version": "~> 4.0" 13 } 14 }, 15 "frameworks": [ 16 "AVFoundation", 17 "Photos", 18 "CoreLocation" 19 ] 20 }, 21 "privacyDescription": { 22 "NSCameraUsageDescription": "需要使用相机拍摄照片", 23 "NSPhotoLibraryUsageDescription": "需要访问相册保存图片" 24 } 25} 26
构建流程: HBuilderX 打包时 → 读取此 config.json → 自动生成 Podfile → 执行 pod install → 编译进 IPA。你不需要手动运行 pod install。
Android 端:utssdk/app-android/config.json
1{ 2 "minSdkVersion": "21", 3 "dependencies": [ 4 "com.squareup.okhttp3:okhttp:4.12.0", 5 "com.google.code.gson:gson:2.10.1", 6 "com.airbnb.android:lottie:6.3.0" 7 ], 8 "abis": [ 9 "arm64-v8a", 10 "armeabi-v7a" 11 ], 12 "permissions": [ 13 "<uses-permission android:name="android.permission.CAMERA"/>", 14 "<uses-permission android:name="android.permission.RECORD_AUDIO"/>" 15 ], 16 "parameters": { 17 "applicationId": "" 18 }, 19 "libs": [ 20 "custom-sdk.aar" 21 ] 22} 23
构建流程: HBuilderX 打包时 → 读取此 config.json → 自动注入到 Gradle 的 build.gradle → Gradle Sync → 编译进 APK。
鸿蒙端:utssdk/app-harmony/config.json
1{ 2 "dependencies": { 3 "@cashier_alipay/cashiersdk": "^15.8.17", 4 "@ohos/lottie": "^2.0.9", 5 "@ohos/axios": "^2.2.0" 6 }, 7 "permissions": [ 8 "ohos.permission.CAMERA", 9 "ohos.permission.MICROPHONE" 10 ] 11} 12
构建流程: HBuilderX 编译时 → 读取此 config.json → 自动生成/合并 oh-package.json5 → OHPM install → 编译进 HAP。
5.3 完整对照:config.json 如何映射到原生包管理器
1┌─────────────────────────────────────────────────────────────────┐ 2│ UTS 插件 config.json │ 3├───────────────────┬──────────────────┬──────────────────────────┤ 4│ app-ios/ │ app-android/ │ app-harmony/ │ 5│ config.json │ config.json │ config.json │ 6├───────────────────┼──────────────────┼──────────────────────────┤ 7│ "pods": {...} │ "dependencies": │ "dependencies": {...} │ 8│ ↓ │ [...] │ ↓ │ 9│ 自动生成 Podfile │ ↓ │ 合并到 oh-package.json5 │ 10│ ↓ │ 注入 build.gradle│ ↓ │ 11│ pod install │ ↓ │ ohpm install │ 12│ ↓ │ gradle sync │ ↓ │ 13│ 编译进 .ipa │ ↓ │ 编译进 .hap │ 14│ │ 编译进 .apk │ │ 15└───────────────────┴──────────────────┴──────────────────────────┘ 16
5.4 私有 SDK 的接入方式
| 场景 | iOS | Android | 鸿蒙 |
|---|---|---|---|
| 私有 CocoaPod | config.json 中指定 :git 或 :path | — | — |
| 本地 .framework | 放入插件目录 + config.json 引用 | — | — |
| 私有 Maven 仓库 | — | 在 config.json 或项目级 build.gradle 中配置 repositories | — |
| 本地 .aar | — | 放入 libs/ + config.json 的 "libs" 字段 | — |
| 私有 OHPM 包 | — | — | 配置私有 Registry 或 file: 本地引用 |
| 本地 .har | — | — | 放入 libs/ + "file:./libs/xxx.har" |
5.5 如何查看一个插件用了哪些原生依赖?
- 查看插件源码中的 config.json(最直接)
- 查看插件的 package.json 中
dcloudext字段的permissions描述 - 查看插件的 readme.md(作者通常会列出所需权限和三方库)
- 在 HBuilderX 中:导入插件后 → 打自定义基座 → 查看构建日志中的 pod/gradle 输出
六、UTS 插件深度解析 — 新一代跨端原生开发方式
6.1 UTS 是什么?
UTS(Uni Type Script) 是 DCloud 自研的跨平台强类型语言,语法接近 TypeScript,但能编译为各平台的原生语言:
| 目标平台 | UTS 编译产物 |
|---|---|
| iOS | Swift 代码 |
| Android | Kotlin 代码 |
| 鸿蒙 | ArkTS 代码 |
| H5/Web | JavaScript |
| 小程序 | 各平台 JS |
6.2 UTS 插件 vs 旧版原生语言插件
| 维度 | App 原生语言插件(已停维) | UTS 插件(主推) |
|---|---|---|
| 开发语言 | ObjC/Swift + Java/Kotlin | UTS(类 TS) |
| 目录位置 | nativeplugins/ | uni_modules/插件名/utssdk/ |
| 跨平台 | ❌ 每端单独写 | ✅ 一套接口,各端实现 |
| 依赖声明 | Podfile + build.gradle 分散 | config.json 统一 |
| uni-app x 兼容 | ❌ 不支持 | ✅ 完全支持 |
| 调试体验 | 需切换 Xcode/AS | HBuilderX 内直接调试 |
| 未来方向 | ❌ 已停止维护 | ✅ 持续迭代 |
6.3 UTS 插件的完整目录结构
1uni_modules/my-payment-sdk/ 2├── package.json ← 插件元信息 3├── readme.md 4├── changelog.md 5│ 6├── utssdk/ 7│ ├── interface.uts ← 🔑 跨平台统一接口(类型约束) 8│ │ 9│ ├── app-ios/ 10│ │ ├── index.uts ← iOS 实现(编译为 Swift) 11│ │ └── config.json ← CocoaPods 依赖 + Framework 12│ │ 13│ ├── app-android/ 14│ │ ├── index.uts ← Android 实现(编译为 Kotlin) 15│ │ ├── config.json ← Maven 依赖 + 权限 16│ │ └── libs/ ← 本地 aar 文件 17│ │ └── alipay-sdk.aar 18│ │ 19│ ├── app-harmony/ 20│ │ ├── index.uts ← 鸿蒙实现(编译为 ArkTS) 21│ │ └── config.json ← OHPM 依赖 22│ │ 23│ ├── mp-weixin/ 24│ │ └── index.uts ← 微信小程序实现(调 wx.requestPayment) 25│ │ 26│ └── web/ 27│ └── index.uts ← H5 实现(调 JS-SDK) 28│ 29└── components/ ← 可选:配套 UI 组件 30 └── payment-sheet.vue 31
6.4 interface.uts — 跨平台契约
1// utssdk/interface.uts 2// 这个文件定义了所有平台必须实现的统一接口 3 4export type PaymentResult = { 5 code: number; 6 message: string; 7 transactionId?: string; 8} 9 10export interface PaymentSDK { 11 /** 12 * 发起支付 13 */ 14 pay(orderId: string, amount: number): Promise<PaymentResult>; 15 16 /** 17 * 查询支付状态 18 */ 19 queryStatus(orderId: string): Promise<PaymentResult>; 20 21 /** 22 * 是否已安装支付App(仅App端有效) 23 */ 24 isInstalled(): boolean; 25} 26
6.5 各平台实现示例
iOS 实现(app-ios/index.uts)
1// utssdk/app-ios/index.uts 2// 编译产物:Swift 代码 3// 可直接调用所有 iOS 原生 API 4 5import { PaymentResult, PaymentSDK } from '../interface.uts' 6 7// 直接引用 iOS 原生类 8import { AlipaySDK } from 'AlipaySDK' // 来自 config.json 中声明的 pod 9 10export class PaymentSDKImpl implements PaymentSDK { 11 12 async pay(orderId: string, amount: number): Promise<PaymentResult> { 13 return new Promise((resolve, reject) => { 14 // 调用支付宝 iOS SDK 原生方法 15 AlipaySDK.defaultService().payOrder( 16 orderString, 17 fromScheme: "myapp", 18 callback: (result: NSDictionary) => { 19 resolve({ 20 code: result["resultStatus"] as number, 21 message: result["memo"] as string ?? "", 22 transactionId: result["trade_no"] as string ?? "" 23 }) 24 } 25 ) 26 }) 27 } 28 29 isInstalled(): boolean { 30 return UIApplication.shared.canOpenURL( 31 URL(string: "alipay://")! 32 ) 33 } 34} 35
Android 实现(app-android/index.uts)
1// utssdk/app-android/index.uts 2// 编译产物:Kotlin 代码 3// 可直接调用所有 Android 原生 API 4 5import { PaymentResult, PaymentSDK } from '../interface.uts' 6 7// 直接引用 Android SDK 类 8import { PayTask } from 'com.alipay.sdk.app.PayTask' 9import { UTSAndroid } from 'io.dcloud.uts' 10 11export class PaymentSDKImpl implements PaymentSDK { 12 13 async pay(orderId: string, amount: number): Promise<PaymentResult> { 14 return new Promise((resolve, reject) => { 15 val activity = UTSAndroid.getUIActivity() 16 val payTask = PayTask(activity) 17 18 // 异步调用支付宝 Android SDK 19 payTask.payV2(orderString, true, object : Map<String, String>() { 20 override fun onResult(result: Map<String, String>) { 21 resolve(PaymentResult( 22 code = result["resultStatus"]?.toInt() ?: -1, 23 message = result["memo"] ?: "", 24 transactionId = result["trade_no"] ?: "" 25 )) 26 } 27 }) 28 }) 29 } 30 31 isInstalled(): boolean { 32 val context = UTSAndroid.getApplicationContext() 33 return context?.packageManager 34 ?.getPackageInfo("com.eg.android.AlipayGphone", 0) != null 35 } 36} 37
鸿蒙实现(app-harmony/index.uts)
1// utssdk/app-harmony/index.uts 2// 编译产物:ArkTS 代码 3// 可直接调用所有鸿蒙原生 API 4 5import { PaymentResult, PaymentSDK } from '../interface.uts' 6import { alipay } from '@cashier_alipay/cashiersdk' 7 8export class PaymentSDKImpl implements PaymentSDK { 9 10 async pay(orderId: string, amount: number): Promise<PaymentResult> { 11 return new Promise((resolve, reject) => { 12 alipay.pay(orderString, (result: string) => { 13 const parsed = JSON.parse(result) 14 resolve({ 15 code: parsed.resultStatus ?? -1, 16 message: parsed.memo ?? '', 17 transactionId: parsed.trade_no ?? '' 18 }) 19 }) 20 }) 21 } 22 23 isInstalled(): boolean { 24 // 鸿蒙通过 bundleManager 检查 25 try { 26 bundleManager.getBundleInfoForSelfSync( 27 bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT 28 ) 29 return true 30 } catch { 31 return false 32 } 33 } 34} 35
6.6 UTS 插件中引用原生依赖的核心机制
你不需要写 Podfile、不需要写 build.gradle、不需要写 oh-package.json5。
你只需要:
- 在各平台的
config.json中声明依赖 - 在 UTS 代码中
import对应的类 - HBuilderX 编译时自动完成依赖安装和代码生成
1你写的:config.json + index.uts 2 ↓ HBuilderX 编译器 3自动完成:pod install / gradle sync / ohpm install 4 ↓ 5编译产物:Swift / Kotlin / ArkTS 原生代码 6 ↓ 7打包进:IPA / APK / HAP 8
6.7 UTS 插件的调试
| 调试方式 | 说明 |
|---|---|
| HBuilderX 真机运行 | 连接真机 → 运行到 App → 自动编译 UTS → 支持断点调试 |
| 自定义基座 | 涉及原生依赖时必须打自定义基座(标准基座不含你的三方库) |
| Android Studio 联调 | UTS 编译为 Kotlin 后,可在 AS 中打断点(HBuilderX 4.71+) |
| Xcode 联调 | 类似,编译产物为 Swift,可在 Xcode 中调试 |
⚠️ 重要: 任何涉及原生 SDK 依赖的 UTS 插件,标准基座无法运行。必须先打自定义基座:
HBuilderX → 运行 → 运行到手机或模拟器 → 制作自定义调试基座。
七、实战决策流程
当你在 uni-app 项目中需要引入一个三方能力时,按以下流程决策:
1需要某个三方能力(如支付、地图、推送、蓝牙...) 2 │ 3 ▼ 4① 去 DCloud 插件市场搜索(ext.dcloud.net.cn) 5 │ 6 ┌─── 找到了 ───┐ 没找到 7 ▼ ▼ │ 8② 是 UTS 插件? │ 9 ┌─YES─┐ NO │ 10 ▼ ▼ │ │ 11 直接用 是原生语言插件? │ 12 ✅推荐 (已停维,谨慎) │ 13 │ │ 14 ▼ ▼ 15 ③ 该能力是否需要原生 API? 16 ┌──YES──┐ NO 17 ▼ ▼ │ 18 自己写 直接用 npm │ 19 UTS插件 纯 JS 库 │ 20 │ ✅ │ 21 ▼ │ 22 ④ 各端是否都有对应 SDK? │ 23 ┌──YES──┐ NO │ 24 ▼ ▼ │ 25 全端实现 部分端实现 │ 26 │ + 降级方案 │ 27 ▼ │ 28 ⑤ 配置 config.json │ 29 声明各端原生依赖 │ 30 │ │ 31 ▼ │ 32 ⑥ 打自定义基座验证 │ 33 │ │ 34 ▼ │ 35 完成 ✅ ◄──────────────┘ 36
八、工程化最佳实践
8.1 项目依赖管理 Checklist
1# 项目根目录结构(关键部分) 2my-uni-app/ 3├── package.json ← npm 依赖(第一层) 4├── package-lock.json ← npm 版本锁定 5├── pnpm-lock.yaml ← 或用 pnpm 6│ 7├── uni_modules/ ← 🔑 纳入 Git!不要 .gitignore 8│ ├── uni-ui/ 9│ ├── uni-camera-pro/ 10│ └── my-payment-sdk/ 11│ 12├── src/ 13│ ├── manifest.json ← App 权限、模块配置 14│ └── pages.json ← 页面路由配置 15│ 16└── nativeplugins/ ← ⚠️ 旧版原生语言插件(不推荐新增) 17
8.2 .gitignore 推荐配置
1# 忽略 npm 依赖(通过 lock 文件恢复) 2node_modules/ 3 4# 🔑 不要忽略 uni_modules!它是项目的一部分 5# uni_modules/ ← 绝对不要写这行 6 7# 忽略插件内部的 npm 依赖(如果有) 8uni_modules/*/node_modules/ 9 10# 忽略构建产物 11unpackage/ 12dist/ 13 14# 忽略系统文件 15.DS_Store 16*.log 17
8.3 CI/CD 中的依赖恢复
1# .gitlab-ci.yml 示例 2stages: 3 - install 4 - build 5 6install_dependencies: 7 stage: install 8 script: 9 # npm 依赖 10 - npm ci 11 12 # uni_modules 已在 Git 中,无需额外安装 13 # 但如果插件有内部 npm 依赖: 14 - | 15 for dir in uni_modules/*/; do 16 if [ -f "$dir/package.json" ]; then 17 cd "$dir" && npm install && cd - 18 fi 19 done 20 21build_android: 22 stage: build 23 script: 24 # HBuilderX CLI 打包(或使用 DCloud 云打包 API) 25 - cli publish --platform app-android --project ./ 26
8.4 版本管理策略
| 依赖类型 | 版本管理方式 |
|---|---|
| npm 依赖 | package.json + lock 文件,npm ci 精确恢复 |
| uni_modules 插件 | Git 提交快照(目录整体纳入版本控制) |
| 原生 SDK(config.json 中) | 语义化版本范围(如 ~> 5.18),由原生包管理器解析 |
| 本地二进制(.aar/.framework/.har) | Git LFS 管理大文件 |
8.5 团队协作规范
1## 插件引入规范(团队约定) 2 31. 新增插件前先在插件市场搜索,优先使用官方(uni- 前缀)或高下载量插件 42. 付费插件统一购买源码授权版,便于后续修改 53. 引入插件后必须: 6 - 测试所有目标平台(iOS/Android/鸿蒙/H5/小程序) 7 - 检查 config.json 中的权限声明是否合理 8 - 确认无隐私合规风险 94. Fork 修改的插件在 readme.md 头部标注修改记录 105. 禁止在 uni_modules 中引入未经评审的第三方原生 SDK 11
九、与原生包管理器的完整对照总结
| 维度 | CocoaPods/SPM | Maven/Gradle | OHPM | npm/pnpm | uni_modules |
|---|---|---|---|---|---|
| 定位 | iOS 依赖管理 | Android 依赖管理 | 鸿蒙依赖管理 | JS 生态依赖管理 | 跨端插件管理 |
| 声明文件 | Podfile / Package.swift | build.gradle | oh-package.json5 | package.json | package.json + config.json |
| 锁文件 | Podfile.lock / .resolved | gradle.lockfile | oh-package-lock.json5 | package-lock.json | ❌ 无(用 Git 替代) |
| 安装命令 | pod install | gradle sync | ohpm install | npm install | HBuilderX GUI / 手动复制 |
| 私有源 | ✅ Spec Repo / Git | ✅ Maven Repo | ✅ 私有 Registry | ✅ npm Registry | ⚠️ Git / 手动 |
| 跨端能力 | ❌ | ❌ | ❌ | ⚠️ 仅 JS 层 | ✅ 全端 |
| 原生能力 | ✅ | ✅ | ✅ | ❌ | ✅(通过 config.json) |
| CI/CD | ✅ 命令行 | ✅ 命令行 | ✅ 命令行 | ✅ 命令行 | ⚠️ 需 Git 纳管 |
| 版本协商 | ✅ 自动 | ✅ 自动 | ✅ 自动 | ✅ 自动 | ❌ 手动 |
| IDE 集成 | Xcode | Android Studio | DevEco Studio | VSCode | HBuilderX |
十、给原生工程师的心态转换指南
10.1 不要试图找"一个命令解决所有依赖"
在原生世界,你习惯了 pod install 一条命令搞定一切。在 uni-app 中,你需要接受:
- JS 层依赖 →
npm install(你熟悉的) - 跨端插件 → 从插件市场导入到
uni_modules/(新操作) - 原生 SDK → 在 config.json 中声明(构建时自动处理,你不用手动 pod install)
10.2 把 config.json 当作你的"Podfile/build.gradle"
当你需要给 UTS 插件添加原生依赖时:
- iOS 开发者:编辑
app-ios/config.json的pods字段(等价于在 Podfile 中加 pod) - Android 开发者:编辑
app-android/config.json的dependencies数组(等价于在 build.gradle 中加 implementation) - 鸿蒙开发者:编辑
app-harmony/config.json的dependencies对象(等价于在 oh-package.json5 中加依赖)
10.3 自定义基座 = 你的"Debug 原生工程"
在原生开发中,你直接在 Xcode/AS 中 Run 就能调试。在 uni-app 中:
- 标准基座 = DCloud 预编译的通用壳(不含你的三方库)
- 自定义基座 = 包含你所有原生依赖的专属壳(等价于你本地编译的原生工程)
每次修改 config.json 中的原生依赖后,都需要重新打自定义基座。
10.4 条件编译是你的"平台判断"
1// 类似原生的 #if os(iOS) / BuildConfig / #ifdef 2// #ifdef APP-IOS 3// 仅 iOS App 端执行的代码 4// #endif 5 6// #ifdef APP-ANDROID 7// 仅 Android App 端执行的代码 8// #endif 9 10// #ifdef APP-HARMONY 11// 仅鸿蒙 App 端执行的代码 12// #endif 13 14// #ifdef MP-WEIXIN 15// 仅微信小程序端执行的代码 16// #endif 17 18// #ifdef H5 19// 仅 H5 端执行的代码 20// #endif 21
十一、常见问题 FAQ
Q1:uni_modules 和 node_modules 能共存吗?
A:能,且经常共存。node_modules 存放纯 JS 库,uni_modules 存放跨端插件。两者互不干扰。
Q2:能不能用 npm 安装 uni_modules 插件?
A:不能。uni_modules 有自己的目录规范和识别机制,不通过 npm registry 分发。必须通过插件市场导入或手动复制。
Q3:UTS 插件支持热更新吗?
A:UTS 编译为原生代码的部分不支持热更新(wgt 更新只能更新 JS/Vue 层)。如果原生 SDK 有更新,必须重新发版。
Q4:一个 UTS 插件能只实现部分平台吗?
A:可以。比如只在 app-ios/ 和 app-android/ 下有实现,没有 app-harmony/。调用时通过条件编译判断平台,对不支持的平台提供降级方案。
Q5:插件市场的付费插件如何管理版本?
A:购买后绑定 DCloud 账号,HBuilderX 中可检查更新。建议锁定版本号,不要盲目升级。源码授权版可 Fork 后自行管理。
Q6:如何在 CI/CD 中自动打包含 UTS 插件的包?
A:使用 DCloud 云打包 API 或 HBuilderX CLI。UTS 插件的编译在云端完成,本地 CI 只需确保 uni_modules 目录完整(Git 中已有)。
十二、总结
uni-app 的依赖管理不是一套体系,而是三层协作:
| 层次 | 解决什么问题 | 你该怎么做 |
|---|---|---|
| npm | 纯 JS 逻辑(工具、状态、校验) | npm install,和前端项目一样 |
| uni_modules | 跨端组件/插件的目录规范和分发 | 从插件市场导入,Git 纳管 |
| config.json → 原生包管理器 | 各端原生 SDK 的依赖声明和安装 | 编辑 config.json,构建时自动处理 |
UTS 插件是连接这三层的桥梁,也是 DCloud 未来的主推方向。旧的 App 原生语言插件已停止维护,新项目请一律使用 UTS。
最后一句话:uni-app 没有试图"取代" CocoaPods/Gradle/OHPM,而是在它们之上加了一层跨端编排。你的原生包管理知识没有白费,只是换了一个入口。
本文基于 uni-app 官方文档(2026年8月)、DCloud 插件市场规范、UTS 插件开发指南整理。如有版本更新导致细节变化,请以官方最新文档为准。
《uni-app 三方库与插件管理体系全解析:从原生开发者视角彻底讲透》 是转载文章,点击查看原文。