03|环境准备:把工具链装得服服帖帖
做SDK集成,说白了就是给不同平台搭积木。但积木之间的插口对不上,神仙也救不了。所以环境准备这步,我每次都不敢马虎。你想想看,一个依赖版本不对,编译花半小时才发现,心态直接崩掉。
3.1 开发工具的选择
我个人的习惯是:每个平台用官方推荐的主力工具,别整花活。三大平台的最低配置清单如下:
| 平台 | 必装工具 | 版本要求 | 我踩过的坑 |
|---|---|---|---|
| Android | Android Studio + JDK | JDK 11+ / AGP 7.x+ | JDK 8 编译新AGP直接报错 |
| iOS | Xcode + CocoaPods / SPM | Xcode 14+ / iOS 13+ | Xcode-beta 发布时记得切stable |
| Web | VS Code + Node.js | Node.js 18+ / npm 9+ | 低版本npm lockfile冲突频繁 |
嗯,这里要注意:Android SDK 路径别带空格,我曾经项目路径里有个空格,Gradle 解析文件死活找不到本地仓库,折腾了两小时。
我的小建议:装好工具后,先跑官方 demo 验证环境。
如果 demo 都编译不过,一定是工具链的问题,不是你的代码问题。
3.2 依赖管理:Gradle
Android 用 Gradle + Maven 仓库。说白了就是把 SDK 的 aar/jar 包地址写在 build.gradle 里。但这里门道不少。
// app/build.gradle
dependencies {
implementation 'com.example:sdk-core:2.1.0'
// 如果你要调试本地版本
// implementation files('libs/sdk-core-2.1.0.aar')
}
我在项目中遇到过最头疼的事:transitive dependencies 自动拉进来的库和宿主冲突。比如你 SDK 依赖了 okhttp 4.10,而宿主项目用了 okhttp 3.12,运行期直接 NoSuchMethodError。解决方案?
- 在发布 SDK 时尽量用
compileOnly或provided声明可选依赖 - 在接入方的 gradle 里显式排除:
exclude group: 'com.squareup.okhttp3' - 或者干脆让宿主统一管理版本——用 BOM 或 version catalog 都行
曾经有个教训:我发布 SDK 时用了 implementation 依赖了一个内部库,结果宿主引了两个冲突的版本,Android 打包时直接 duplicate class。后来我全部改成 api + transitive = false,才稳住。
3.3 依赖管理:CocoaPods
iOS 我最常用 CocoaPods。其实 Swift Package Manager 也不错,但很多旧版三方库还没完全适配,所以我个人还是优先 CocoaPods。
# Podfile
platform :ios, '13.0'
target 'YourApp' do
pod 'YourSDK', '~> 3.0'
end
你可能会问:为什么不直接用 Swift Package?我的看法是:如果你的接入方还在用 CocoaPods,你也必须提供 Podspec。另外,CocoaPods 的 use_frameworks! 开关要注意:
- use_frameworks!:生成动态 framework,支持 Swift 混编
- 不写:默认静态库,包体积小但 Objective-C 只能用
- 如果 SDK 内用了 Swift,必须开
use_frameworks!
嗯,这里有个坑:如果宿主项目同时用了 use_frameworks! 和静态库形式的其他 Pod,链接时可能报错 duplicate symbol。我曾经被迫把整个 SDK 改成只支持动态 framework 来规避。
3.4 依赖管理:npm
Web 端最简单,也最容易翻车。npm 的 package.json 里声明依赖,但经常被忽略的细节是:peerDependencies 和 bundleDependencies。
// package.json
{
"name": "your-sdk",
"version": "2.0.0",
"peerDependencies": {
"react": ">=17.0.0",
"react-dom": ">=17.0.0"
},
"optionalDependencies": {
"canvas": "^2.9.0"
}
}
为什么要用 peerDependencies?因为你的 SDK 如果锁死了 react 版本,宿主那边用 18 就不兼容了。peerDependencies 可以告诉 npm:「我的宿主自己装 react,版本别低于 17 就行」。
避坑指南:npm 7+ 会自动安装 peerDependencies,如果版本冲突会报错。
我曾经在 CI 上遇到 npm 7 自动装了 react 18,而我的 SDK 需要 react 17,结果 Hook 报错。后来我在 .npmrc 里加了 legacy-peer-deps=true 才跳过。
3.5 构建系统配置速查
这里我把三个平台的构建配置关键差异整理成了表格,方便你以后查阅:
| 项目 | Android (Gradle) | iOS (CocoaPods) | Web (npm) |
|---|---|---|---|
| 配置文件 | build.gradle.kts / .gradle | Podfile + .podspec | package.json |
| 仓库声明 | repositories { mavenCentral() } | source 'https://cdn.cocoapods.org/' | "registry": "https://registry.npmjs.org" |
| 版本约束 | implementation('1.+') 不推荐 | pod 'SDK', '~> 2.0' | "^2.0.0" (semver) |
| 本地调试 | implementation files('...') | pod 'SDK', :path => '../local' | npm link 或 file:../ |
| 构建缓存 | .gradle/ 目录 | ~/Library/Caches/CocoaPods | node_modules/ |
你看,每个平台的配置思路都差不多,但细节不同。比如版本约束:Gradle 用 + 太危险,npm 用 ^ 相对安全,CocoaPods 的 ~> 则只允许最后一段浮动。不建议混着用思维。
3.6 跨平台开发者的「通用工具箱」
如果你同时维护 Android、iOS、Web 三端的 SDK,我建议你准备以下东西:
- 统一的文档站点:每个平台写一页集成指南,方便自己查
- CI 上的构建验证脚本:每次发版前自动编译各大平台的 demo app
- 本地代理仓库:比如用 Artifactory 或 Nexus 缓存远程依赖,避免重复下载
我个人还有一个习惯:在每个项目的根目录下放一个 env-check.sh,自动检测 JDK、Xcode、Node 版本,确保所有开发者用的环境一致。这东西花十分钟写一次,能救你无数个小时的 debug 时间。