作者视角: 本文面向从 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 用三层并行体系管理依赖,每层解决不同层面的问题。这不是设计缺陷,而是跨端框架的必然选择。
二、三层依赖体系全景图
yaml
┌─────────────────────────────────────────────────────────────────────┐
│ 你的 uni-app 项目 │
├─────────────────┬──────────────────────┬────────────────────────────┤
│ 第一层 │ 第二层 │ 第三层 │
│ npm / pnpm │ DCloud 插件市场 │ 各端原生包管理器 │
│ (JS/TS 纯逻辑库)│ (uni_modules 规范) │ (CocoaPods/Gradle/OHPM) │
├─────────────────┼──────────────────────┼────────────────────────────┤
│ • pinia/vuex │ • UI 组件库 │ • iOS: Podfile / SPM │
│ • dayjs/lodash │ • 原生能力封装插件 │ • Android: build.gradle │
│ • zod/yup │ • UTS 插件 │ • 鸿蒙: oh-package.json5 │
│ • vue-router │ • 云函数/Schema │ • H5: npm (浏览器端) │
│ • 纯算法库 │ • 页面模板/项目模板 │ • 小程序: 受限 npm │
├─────────────────┼──────────────────────┼────────────────────────────┤
│ 管理方式: │ 管理方式: │ 管理方式: │
│ package.json │ uni_modules/ 目录 │ 嵌入在 uni_modules 插件内 │
│ + lock 文件 │ + package.json │ 编译时由构建工具自动调用 │
│ CLI: npm install│ GUI: HBuilderX 导入 │ pod install / gradle sync │
├─────────────────┼──────────────────────┼────────────────────────────┤
│ 版本控制: ✅ │ 版本控制: ⚠️ 无lock │ 版本控制: ✅ (跟随原生体系) │
│ 传递依赖: ✅ │ 传递依赖: ⚠️ 仅一层 │ 传递依赖: ✅ │
│ 私有源: ✅ │ 私有源: ⚠️ Git/手动 │ 私有源: ✅ │
└─────────────────┴──────────────────────┴────────────────────────────┘
核心认知: 这三层不是互斥的,而是互补嵌套的。一个完整的原生能力插件往往同时涉及三层------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 使用方式
bash
# 与标准前端项目完全一致
npm install dayjs pinia zod
npm install -D @types/lodash-es
# 或使用 pnpm(推荐,速度快、磁盘省)
pnpm add dayjs pinia
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 标准目录结构
lua
uni_modules/
└── uni-camera-pro/ ← 插件ID(全局唯一标识)
├── package.json ← 🔑 插件元信息 + 依赖声明
├── changelog.md ← 更新日志
├── readme.md ← 使用文档
│
├── components/ ← Vue 组件(跨端)
│ └── camera-view.vue
│
├── js_sdk/ ← JS/TS API 封装
│ └── index.ts
│
├── utssdk/ ← 🔑 UTS 原生插件代码(新方式)
│ ├── interface.uts ← 跨平台统一接口定义
│ ├── app-ios/ ← iOS 平台实现
│ │ ├── index.uts
│ │ └── config.json ← iOS 原生依赖配置
│ ├── app-android/ ← Android 平台实现
│ │ ├── index.uts
│ │ └── config.json ← Android 原生依赖配置
│ ├── app-harmony/ ← 鸿蒙平台实现
│ │ ├── index.uts
│ │ └── config.json ← 鸿蒙原生依赖配置
│ ├── mp-weixin/ ← 小程序平台实现
│ │ └── index.uts
│ └── web/ ← H5 平台实现
│ └── index.uts
│
├── uniCloud-aliyun/ ← 云函数(可选)
│ └── cloudfunctions/
│
└── pages/ ← 页面模板(可选)
└── demo/
4.3 package.json 核心字段
css
{
"id": "uni-camera-pro",
"displayName": "专业相机插件",
"version": "2.3.1",
"description": "支持HDR、慢动作、多摄切换的相机组件",
"keywords": ["camera", "拍照", "录像"],
"repository": "https://github.com/xxx/uni-camera-pro",
"engines": {
"HBuilderX": "^4.0.0"
},
"dcloudext": {
"type": "uts",
"sale": {
"regular": { "price": "0.00" },
"sourcecode": { "price": "199.00" }
},
"contact": { "qq": "" },
"declaration": {
"ads": "无广告",
"data": "插件不采集任何数据",
"permissions": "需要相机、麦克风、存储权限"
},
"npmurl": ""
},
"uni_modules": {
"dependencies": [
"uni-permission-helper"
],
"encrypt": [],
"platforms": {
"cloud": { "tcb": "y", "aliyun": "y" },
"client": {
"App": { "app-vue": "y", "app-nvue": "y", "app-uvue": "y" },
"H5-mobile": { "Safari": "y", "Android Browser": "y" },
"H5-pc": { "Chrome": "y" },
"小程序": { "微信": "y", "支付宝": "y" },
"快应用": { "华为": "n" }
}
}
}
}
4.4 安装方式
方式一:HBuilderX 插件市场导入(推荐)
arduino
HBuilderX → 工具 → 插件安装 → 浏览插件市场
→ 搜索插件名 → 点击"导入插件" → 选择目标项目 → 完成
优势: 自动创建目录结构、自动安装子依赖、自动合并 pages.json 配置。
方式二:CLI 项目手动安装
bash
# 从插件市场下载 zip 包
# 解压到项目的 uni_modules/ 目录下
# HBuilderX 或编译器会自动识别
# 如果是 Git 仓库形式的插件
git clone https://github.com/xxx/uni-camera-pro.git uni_modules/uni-camera-pro
方式三:直接复制源码
从插件市场下载 → 解压 → 拖入 uni_modules/ 目录 → 编辑器自动识别。
4.5 依赖安装
当插件声明了 npm 依赖或其他 uni_modules 依赖时:
HBuilderX → 右键 uni_modules/插件名 → 安装插件依赖
或在 CLI 项目中:
bash
cd uni_modules/uni-camera-pro
npm install
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 场景)
bash
# .gitignore 配置
node_modules/
# ⚠️ 不要忽略 uni_modules!
# uni_modules/ ← 不要写这行!
# 但可以忽略插件内部的临时文件
uni_modules/*/node_modules/
uni_modules/*/.DS_Store
核心建议: 将
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
json
{
"deploymentTarget": "12.0",
"dependencies": {
"pods": {
"SDWebImage": {
"version": "~> 5.18"
},
"Lottie": {
"version": "~> 4.4"
},
"AFNetworking": {
"version": "~> 4.0"
}
},
"frameworks": [
"AVFoundation",
"Photos",
"CoreLocation"
]
},
"privacyDescription": {
"NSCameraUsageDescription": "需要使用相机拍摄照片",
"NSPhotoLibraryUsageDescription": "需要访问相册保存图片"
}
}
构建流程: HBuilderX 打包时 → 读取此 config.json → 自动生成 Podfile → 执行 pod install → 编译进 IPA。你不需要手动运行 pod install。
Android 端:utssdk/app-android/config.json
swift
{
"minSdkVersion": "21",
"dependencies": [
"com.squareup.okhttp3:okhttp:4.12.0",
"com.google.code.gson:gson:2.10.1",
"com.airbnb.android:lottie:6.3.0"
],
"abis": [
"arm64-v8a",
"armeabi-v7a"
],
"permissions": [
"<uses-permission android:name="android.permission.CAMERA"/>",
"<uses-permission android:name="android.permission.RECORD_AUDIO"/>"
],
"parameters": {
"applicationId": ""
},
"libs": [
"custom-sdk.aar"
]
}
构建流程: HBuilderX 打包时 → 读取此 config.json → 自动注入到 Gradle 的 build.gradle → Gradle Sync → 编译进 APK。
鸿蒙端:utssdk/app-harmony/config.json
perl
{
"dependencies": {
"@cashier_alipay/cashiersdk": "^15.8.17",
"@ohos/lottie": "^2.0.9",
"@ohos/axios": "^2.2.0"
},
"permissions": [
"ohos.permission.CAMERA",
"ohos.permission.MICROPHONE"
]
}
构建流程: HBuilderX 编译时 → 读取此 config.json → 自动生成/合并 oh-package.json5 → OHPM install → 编译进 HAP。
5.3 完整对照:config.json 如何映射到原生包管理器
lua
┌─────────────────────────────────────────────────────────────────┐
│ UTS 插件 config.json │
├───────────────────┬──────────────────┬──────────────────────────┤
│ app-ios/ │ app-android/ │ app-harmony/ │
│ config.json │ config.json │ config.json │
├───────────────────┼──────────────────┼──────────────────────────┤
│ "pods": {...} │ "dependencies": │ "dependencies": {...} │
│ ↓ │ [...] │ ↓ │
│ 自动生成 Podfile │ ↓ │ 合并到 oh-package.json5 │
│ ↓ │ 注入 build.gradle│ ↓ │
│ pod install │ ↓ │ ohpm install │
│ ↓ │ gradle sync │ ↓ │
│ 编译进 .ipa │ ↓ │ 编译进 .hap │
│ │ 编译进 .apk │ │
└───────────────────┴──────────────────┴──────────────────────────┘
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 插件的完整目录结构
lua
uni_modules/my-payment-sdk/
├── package.json ← 插件元信息
├── readme.md
├── changelog.md
│
├── utssdk/
│ ├── interface.uts ← 🔑 跨平台统一接口(类型约束)
│ │
│ ├── app-ios/
│ │ ├── index.uts ← iOS 实现(编译为 Swift)
│ │ └── config.json ← CocoaPods 依赖 + Framework
│ │
│ ├── app-android/
│ │ ├── index.uts ← Android 实现(编译为 Kotlin)
│ │ ├── config.json ← Maven 依赖 + 权限
│ │ └── libs/ ← 本地 aar 文件
│ │ └── alipay-sdk.aar
│ │
│ ├── app-harmony/
│ │ ├── index.uts ← 鸿蒙实现(编译为 ArkTS)
│ │ └── config.json ← OHPM 依赖
│ │
│ ├── mp-weixin/
│ │ └── index.uts ← 微信小程序实现(调 wx.requestPayment)
│ │
│ └── web/
│ └── index.uts ← H5 实现(调 JS-SDK)
│
└── components/ ← 可选:配套 UI 组件
└── payment-sheet.vue
6.4 interface.uts --- 跨平台契约
typescript
// utssdk/interface.uts
// 这个文件定义了所有平台必须实现的统一接口
export type PaymentResult = {
code: number;
message: string;
transactionId?: string;
}
export interface PaymentSDK {
/**
* 发起支付
*/
pay(orderId: string, amount: number): Promise<PaymentResult>;
/**
* 查询支付状态
*/
queryStatus(orderId: string): Promise<PaymentResult>;
/**
* 是否已安装支付App(仅App端有效)
*/
isInstalled(): boolean;
}
6.5 各平台实现示例
iOS 实现(app-ios/index.uts)
typescript
// utssdk/app-ios/index.uts
// 编译产物:Swift 代码
// 可直接调用所有 iOS 原生 API
import { PaymentResult, PaymentSDK } from '../interface.uts'
// 直接引用 iOS 原生类
import { AlipaySDK } from 'AlipaySDK' // 来自 config.json 中声明的 pod
export class PaymentSDKImpl implements PaymentSDK {
async pay(orderId: string, amount: number): Promise<PaymentResult> {
return new Promise((resolve, reject) => {
// 调用支付宝 iOS SDK 原生方法
AlipaySDK.defaultService().payOrder(
orderString,
fromScheme: "myapp",
callback: (result: NSDictionary) => {
resolve({
code: result["resultStatus"] as number,
message: result["memo"] as string ?? "",
transactionId: result["trade_no"] as string ?? ""
})
}
)
})
}
isInstalled(): boolean {
return UIApplication.shared.canOpenURL(
URL(string: "alipay://")!
)
}
}
Android 实现(app-android/index.uts)
typescript
// utssdk/app-android/index.uts
// 编译产物:Kotlin 代码
// 可直接调用所有 Android 原生 API
import { PaymentResult, PaymentSDK } from '../interface.uts'
// 直接引用 Android SDK 类
import { PayTask } from 'com.alipay.sdk.app.PayTask'
import { UTSAndroid } from 'io.dcloud.uts'
export class PaymentSDKImpl implements PaymentSDK {
async pay(orderId: string, amount: number): Promise<PaymentResult> {
return new Promise((resolve, reject) => {
val activity = UTSAndroid.getUIActivity()
val payTask = PayTask(activity)
// 异步调用支付宝 Android SDK
payTask.payV2(orderString, true, object : Map<String, String>() {
override fun onResult(result: Map<String, String>) {
resolve(PaymentResult(
code = result["resultStatus"]?.toInt() ?: -1,
message = result["memo"] ?: "",
transactionId = result["trade_no"] ?: ""
))
}
})
})
}
isInstalled(): boolean {
val context = UTSAndroid.getApplicationContext()
return context?.packageManager
?.getPackageInfo("com.eg.android.AlipayGphone", 0) != null
}
}
鸿蒙实现(app-harmony/index.uts)
typescript
// utssdk/app-harmony/index.uts
// 编译产物:ArkTS 代码
// 可直接调用所有鸿蒙原生 API
import { PaymentResult, PaymentSDK } from '../interface.uts'
import { alipay } from '@cashier_alipay/cashiersdk'
export class PaymentSDKImpl implements PaymentSDK {
async pay(orderId: string, amount: number): Promise<PaymentResult> {
return new Promise((resolve, reject) => {
alipay.pay(orderString, (result: string) => {
const parsed = JSON.parse(result)
resolve({
code: parsed.resultStatus ?? -1,
message: parsed.memo ?? '',
transactionId: parsed.trade_no ?? ''
})
})
})
}
isInstalled(): boolean {
// 鸿蒙通过 bundleManager 检查
try {
bundleManager.getBundleInfoForSelfSync(
bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT
)
return true
} catch {
return false
}
}
}
6.6 UTS 插件中引用原生依赖的核心机制
你不需要写 Podfile、不需要写 build.gradle、不需要写 oh-package.json5。
你只需要:
- 在各平台的
config.json中声明依赖 - 在 UTS 代码中
import对应的类 - HBuilderX 编译时自动完成依赖安装和代码生成
arduino
你写的:config.json + index.uts
↓ HBuilderX 编译器
自动完成:pod install / gradle sync / ohpm install
↓
编译产物:Swift / Kotlin / ArkTS 原生代码
↓
打包进:IPA / APK / HAP
6.7 UTS 插件的调试
| 调试方式 | 说明 |
|---|---|
| HBuilderX 真机运行 | 连接真机 → 运行到 App → 自动编译 UTS → 支持断点调试 |
| 自定义基座 | 涉及原生依赖时必须打自定义基座(标准基座不含你的三方库) |
| Android Studio 联调 | UTS 编译为 Kotlin 后,可在 AS 中打断点(HBuilderX 4.71+) |
| Xcode 联调 | 类似,编译产物为 Swift,可在 Xcode 中调试 |
⚠️ 重要: 任何涉及原生 SDK 依赖的 UTS 插件,标准基座无法运行 。必须先打自定义基座:
HBuilderX → 运行 → 运行到手机或模拟器 → 制作自定义调试基座。
七、实战决策流程
当你在 uni-app 项目中需要引入一个三方能力时,按以下流程决策:
objectivec
需要某个三方能力(如支付、地图、推送、蓝牙...)
│
▼
① 去 DCloud 插件市场搜索(ext.dcloud.net.cn)
│
┌─── 找到了 ───┐ 没找到
▼ ▼ │
② 是 UTS 插件? │
┌─YES─┐ NO │
▼ ▼ │ │
直接用 是原生语言插件? │
✅推荐 (已停维,谨慎) │
│ │
▼ ▼
③ 该能力是否需要原生 API?
┌──YES──┐ NO
▼ ▼ │
自己写 直接用 npm │
UTS插件 纯 JS 库 │
│ ✅ │
▼ │
④ 各端是否都有对应 SDK? │
┌──YES──┐ NO │
▼ ▼ │
全端实现 部分端实现 │
│ + 降级方案 │
▼ │
⑤ 配置 config.json │
声明各端原生依赖 │
│ │
▼ │
⑥ 打自定义基座验证 │
│ │
▼ │
完成 ✅ ◄──────────────┘
八、工程化最佳实践
8.1 项目依赖管理 Checklist
perl
# 项目根目录结构(关键部分)
my-uni-app/
├── package.json ← npm 依赖(第一层)
├── package-lock.json ← npm 版本锁定
├── pnpm-lock.yaml ← 或用 pnpm
│
├── uni_modules/ ← 🔑 纳入 Git!不要 .gitignore
│ ├── uni-ui/
│ ├── uni-camera-pro/
│ └── my-payment-sdk/
│
├── src/
│ ├── manifest.json ← App 权限、模块配置
│ └── pages.json ← 页面路由配置
│
└── nativeplugins/ ← ⚠️ 旧版原生语言插件(不推荐新增)
8.2 .gitignore 推荐配置
bash
# 忽略 npm 依赖(通过 lock 文件恢复)
node_modules/
# 🔑 不要忽略 uni_modules!它是项目的一部分
# uni_modules/ ← 绝对不要写这行
# 忽略插件内部的 npm 依赖(如果有)
uni_modules/*/node_modules/
# 忽略构建产物
unpackage/
dist/
# 忽略系统文件
.DS_Store
*.log
8.3 CI/CD 中的依赖恢复
bash
# .gitlab-ci.yml 示例
stages:
- install
- build
install_dependencies:
stage: install
script:
# npm 依赖
- npm ci
# uni_modules 已在 Git 中,无需额外安装
# 但如果插件有内部 npm 依赖:
- |
for dir in uni_modules/*/; do
if [ -f "$dir/package.json" ]; then
cd "$dir" && npm install && cd -
fi
done
build_android:
stage: build
script:
# HBuilderX CLI 打包(或使用 DCloud 云打包 API)
- cli publish --platform app-android --project ./
8.4 版本管理策略
| 依赖类型 | 版本管理方式 |
|---|---|
| npm 依赖 | package.json + lock 文件,npm ci 精确恢复 |
| uni_modules 插件 | Git 提交快照(目录整体纳入版本控制) |
| 原生 SDK(config.json 中) | 语义化版本范围(如 ~> 5.18),由原生包管理器解析 |
| 本地二进制(.aar/.framework/.har) | Git LFS 管理大文件 |
8.5 团队协作规范
markdown
## 插件引入规范(团队约定)
1. 新增插件前先在插件市场搜索,优先使用官方(uni- 前缀)或高下载量插件
2. 付费插件统一购买源码授权版,便于后续修改
3. 引入插件后必须:
- 测试所有目标平台(iOS/Android/鸿蒙/H5/小程序)
- 检查 config.json 中的权限声明是否合理
- 确认无隐私合规风险
4. Fork 修改的插件在 readme.md 头部标注修改记录
5. 禁止在 uni_modules 中引入未经评审的第三方原生 SDK
九、与原生包管理器的完整对照总结
| 维度 | 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 条件编译是你的"平台判断"
arduino
// 类似原生的 #if os(iOS) / BuildConfig / #ifdef
// #ifdef APP-IOS
// 仅 iOS App 端执行的代码
// #endif
// #ifdef APP-ANDROID
// 仅 Android App 端执行的代码
// #endif
// #ifdef APP-HARMONY
// 仅鸿蒙 App 端执行的代码
// #endif
// #ifdef MP-WEIXIN
// 仅微信小程序端执行的代码
// #endif
// #ifdef H5
// 仅 H5 端执行的代码
// #endif
十一、常见问题 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 插件开发指南整理。如有版本更新导致细节变化,请以官方最新文档为准。