这篇带你在 Windows 上把一个 uni-app 项目本地打包成 iOS App,从导出 Xcode 工程、装到 iPhone 上运行,一直做到出 ipa 上传 App Store Connect。适合已经在 HBuilderX 里开发 uni-app、想摆脱云打包排队的开发者。你需要准备 Apple 开发者账号、一台 iPhone 和数据线,并且已经安装 KXBuild,第一次走完全程大约一小时,之后每次重打几分钟。更多信息可以查看KXBuild官网:www.kxbuild.net/zh
为什么要本地打包 {#why}
HBuilderX 的云打包省去了自己配 Xcode 的麻烦,但项目进入频繁调试阶段后,下面几件事会越来越明显。
- 高峰期要排队,等一次包短则几分钟,长则更久。
- 云打包有次数限制,调试原生功能时很容易用完。
- 改一次 manifest.json 里的原生配置,比如权限描述、模块、图标,就要重新打一次自定义基座或正式包。
本地打包把这一步搬回自己电脑上。DCloud 官方的离线打包本来要求在 Mac 上用 Xcode 完成,用 KXBuild 可以在 Windows 上完成同样的事,导出、编译、装机、出 ipa 都在本机,打多少次都不用排队。
准备离线 SDK 和 AppKey {#prepare}
下载 iOS 离线 SDK {#download-sdk}
到 DCloud 的 iOS 离线 SDK 下载页 下载 SDK 并解压,解压后的根目录下有 HBuilder-Hello、SDK 两个文件夹和 uniapp.podspec 文件,导出时选的就是这个根目录,例如 D:\sdk\HBuilder-iOS-SDK。KXBuild 支持 HBuilderX 5.13 起的离线 SDK,这些版本的 SDK 用 CocoaPods 集成原生模块。
SDK 版本要和你的 HBuilderX 版本一致。 两边版本不同,App 启动后会提示版本不匹配或者白屏。升级 HBuilderX 之后记得同时换新的 SDK。
申请离线打包 AppKey {#appkey}
DCloud 离线 SDK 启动时会校验 AppKey,没有它 App 一打开就报 AppKey 错误。AppKey 和 Bundle ID 绑定,先想好 App 的 Bundle ID(例如 com.example.myapp),它也要和你在 Apple 开发者后台注册的 App ID 一致。
登录 DCloud 开发者中心 dev.dcloud.net.cn,在「我的应用」里打开这个 uni-app 应用,进入「各平台信息」新增 iOS 平台,填写 Bundle ID,保存后就能查看离线打包 Key。
在 Apple 开发者后台注册 App ID {#app-id}
登录 developer.apple.com,在「Certificates, Identifiers & Profiles」的 Identifiers 里新建一个 App ID,Bundle ID 填上面同一个。用到推送、Apple 登录、关联域名这类能力的,在这里勾上对应的 Capability,之后生成的描述文件才会带上这些权限。manifest.json 里声明的 iOS capabilities 导出时会写进工程的 entitlements,两边要对得上。
在 HBuilderX 里配好 manifest.json {#manifest}
导出时会读取 manifest.json 里的 App 配置,下面几项在 HBuilderX 的可视化界面里改好,之后每次导出都会自动带上。
- 应用名称、版本名称、版本号。版本号每次上传 App Store Connect 都要比上一次大。
- 「App 图标配置」里用一张 1024×1024 的图自动生成全部 iOS 图标。
- 「App 权限配置」里填 iOS 隐私信息访问的许可描述,用到相机、相册、定位时必须填,否则调用时 App 会闪退,审核也会被拒。
- 「App 模块配置」里勾选用到的模块,例如支付、推送、地图,并填好各自的参数,导出时会用 CocoaPods 装好对应的 SDK 库。
导出 Xcode 工程 {#export}
导出会先调用 HBuilderX 编译页面,再和离线 SDK 一起生成一个 Xcode 工程。导出前先打开 HBuilderX,这时会自动找到它;HBuilderX 没开时,桌面上有它的文件夹或快捷方式也能找到,都没有时命令行用 --hbx 指定安装目录。编译页面前 HBuilderX 要登录 DCloud 账号,manifest.json 的 AppID 要在「基础配置」里获取过。
Vue 2 项目的 HBuilderX 不能装在带括号的目录,例如 C:\Program Files (x86)\HBuilderX,这是 HBuilderX 自身编译插件的限制。把 HBuilderX 整个文件夹挪到 D:\HBuilderX 这样的目录,或者在 manifest.json 里改用 Vue 3。
以下两种做法任选其一。
用 VS Code 插件导出 {#export-plugin}
按 Ctrl+Shift+P 打开命令面板,运行 KXBuild: 导入 uni-app 项目,依次选择 uni-app 工程目录(含 manifest.json 的那一层)、离线 SDK 根目录和输出目录,再填写 Bundle ID 和 DCloud App Key。导出在终端中执行,完成后在 VS Code 中打开输出目录。
用命令行导出 {#export-cli}
uniapp2xcode --project D:\work\myuniapp --sdk D:\sdk\HBuilder-iOS-SDK --output D:\work\myuniapp-ios --bundle-id com.example.myapp --dcloud-appkey 你的AppKey --clean
--clean 表示先清空输出目录再导出,输出目录已存在时必须加。其余参数,例如 --display-name、--version-name、--team-id,见 uniapp2xcode 命令参考。导出完成后,生成的工程在 D:\work\myuniapp-ios\HBuilder-Hello\HBuilder-Hello.xcworkspace,在 VS Code 中「文件 → 打开文件夹」打开 D:\work\myuniapp-ios 即可。
把 Bundle ID 和 AppKey 写进 uni-app 工程 {#native-resources}
每次导出都要填 Bundle ID 和 AppKey 比较麻烦。在 uni-app 工程里建 nativeResources\ios\Info.plist,写上 CFBundleIdentifier 和 dcloud_appkey 两项,之后导出时这两项可以留空,插件和命令行都会从这里读取。这个 Info.plist 里的其他键也会在每次导出时合并进 iOS 工程的 Info.plist。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleIdentifier</key>
<string>com.example.myapp</string>
<key>dcloud_appkey</key>
<string>你的AppKey</string>
</dict>
</plist>
这个文件可以直接用 VS Code 打开,KXBuild 的属性列表编辑器按表格显示和编辑。
体检 {#doctor}
导出后第一次编译前先做一次体检,它会检查编译需要的环境并修好缺的部分。以下两种做法任选其一。
- VS Code 插件。在 KXBuild 视图标题栏「···」中运行「体检并修复开发环境」。
- 命令行。运行下面的命令。
kxbuild doctor D:\work\myuniapp-ios\HBuilder-Hello\HBuilder-Hello.xcworkspace
检查图标 {#icons}
导出后 App 图标在 HBuilder-Hello\HBuilder\Images.xcassets 里。在 VS Code 资源管理器中右键这个 .xcassets 文件夹,选择「KXBuild: 打开资源目录」,可以看到每个尺寸的图标是否都有。点标题栏的「KXBuild: 编译检查资源目录」,缺少的尺寸和 App Store 图标带透明通道这类问题会列在「问题」面板里。
图标要改就回 HBuilderX 的「App 图标配置」里改,然后重新导出。 直接在导出目录里改,下次带 --clean 导出时会被覆盖。
连接 iPhone 并真机运行 {#run}
真机运行需要签名。先在 Apple 开发者后台创建 Apple Development 证书和包含这台 iPhone 的 Development 描述文件,把 .p12 和 .mobileprovision 放进证书目录,做法见证书与签名。
用数据线连上 iPhone。第一次连接时 KXBuild 视图的设备节点如果提示「点击配置」,点一下安装设备驱动。手机上解锁并点「信任此电脑」,再到「设置 → 隐私与安全性 → 开发者模式」打开开发者模式,手机会重启一次。详细说明见设备准备。
在 KXBuild 视图中选中这台 iPhone,按 F5。KXBuild 会依次完成构建、签名、安装和启动,App 在手机上打开后,原生层可以在 VS Code 中打断点,页面 JS 用 HBuilderX 自带的调试工具,两边互不影响。第一次调试某个 iOS 版本时会自动下载符号库,有几个 GB,只需要一次。
改了前端代码之后怎么更新 {#update}
页面、样式、JS 照常在 HBuilderX 里写。导出的 iOS 工程里是页面的编译结果,改完代码重新导出一次,改动才会进入 App。导出时发现源码比上次编译的结果新,会自动重新编译页面。
- 重新运行一次导出,插件就是再运行一次 KXBuild: 导入 uni-app 项目,命令行就是再执行一次同一条 uniapp2xcode 命令。
- 回到 VS Code 按 F5。
manifest.json 里的原生配置(权限描述、模块、图标、版本号)改完同样重新导出即可,不需要重新打自定义基座,也不需要等云打包。不同改动要做的事如下。
| 改了什么 | 要做什么 |
|---|---|
| 页面、样式、JS | 重新导出,按 F5 |
| manifest.json 的原生配置 | 重新导出,按 F5 |
| nativeResources\ios\Info.plist | 重新导出,按 F5 |
| 升级了 HBuilderX | 换同版本的离线 SDK,重新导出,按 F5 |
重新导出会清空输出目录,不要在导出目录里手改文件,要保留的配置都放回 uni-app 工程的 manifest.json 或 nativeResources 里。
打包 ipa 并上架 {#release}
上架前准备好三样东西。Apple 开发者后台的 Apple Distribution 证书、App Store 类型的描述文件,都放进证书目录。App Store Connect 里新建好这个 App,Bundle ID 和工程里的一致。
在 HBuilderX 里把版本号调大并重新导出,然后用 Release 配置构建。以下两种做法任选其一。
- VS Code 插件。在 KXBuild 视图的「构建配置」节点切到 Release,命令面板运行 KXBuild: 构建。
- 命令行。运行下面的命令。
kxbuild build D:\work\myuniapp-ios\HBuilder-Hello\HBuilder-Hello.xcworkspace -s HBuilder -c Release
构建完成后,工程目录下的 build 文件夹里就是可以上传的 .ipa。Release 配置没有指定 Apple Distribution 证书时,命令行加 -D CODE_SIGN_IDENTITY="Apple Distribution" 临时覆盖。
在 Windows 上用 Appuploader 登录开发者账号上传这个 ipa,Apple 处理完后它会出现在 App Store Connect 的 TestFlight 页,先装到自己手机上确认,再在「App Store」页选择这个构建提交审核。完整步骤见发布与上架。
常见问题 {#faq}
App 一打开就提示 AppKey 错误 {#faq-appkey}
导出时没有提供 AppKey,或者 AppKey 申请时填的 Bundle ID 和工程里的不一致。在 DCloud 开发者中心核对 iOS 平台的包名,重新导出。
启动后提示版本不匹配或白屏 {#faq-version}
离线 SDK 和 HBuilderX 版本不一致。下载与当前 HBuilderX 同版本的 SDK,重新导出。
导出时提示找不到 HBuilderX {#faq-hbx}
先打开 HBuilderX 再导出。还找不到时,命令行加 --hbx 指定 HBuilderX 的安装目录,也就是 cli.exe 所在的目录。
导出时提示未登录或 AppID 不存在 {#faq-login}
HBuilderX 编译页面需要登录 DCloud 账号。在 HBuilderX 里登录,再打开 manifest.json 的「基础配置」,AppID 旁点「获取」或「重新获取」,然后重新导出。
导出结束时提示有模块被跳过 {#faq-skipped}
当前离线 SDK 里没有这个模块,或者模块自带的库链接不了,例如 5.26 版 SDK 的实人认证缺少依赖库。其他模块照常打包,被跳过的模块要等 DCloud 发布修复后的 SDK。
调用相机或相册时闪退 {#faq-privacy}
Info.plist 里缺少对应的隐私描述。在 HBuilderX「App 权限配置」里补上 iOS 隐私信息访问的许可描述,或写进 nativeResources\ios\Info.plist,然后重新导出。
装到手机失败 {#faq-install}
多数是签名问题,描述文件里没有这台手机的 UDID,或者证书类型不对。按证书与签名检查,其他错误见排错与 FAQ。