7. 打包与发布
一句话定位
发布只做两件事:把 utils/.env.js 的 baseUrl 换成正式环境地址,然后按目标端(H5 / 微信小程序 / Android / iOS)执行各自的打包流程。
发布全景
App/utils/.env.js baseUrl ← 唯一的后端地址开关
│
┌─────────────────┼─────────────────┬─────────────────┐
▼ ▼ ▼ ▼
H5 微信小程序 Android iOS
发行→网站-H5 发行→小程序-微信 云打包/离线打包 云打包/离线打包
dist/build/h5 dist/build/mp-weixin .apk/.aab .ipa
│ │ │ │
nginx 托管 微信开发者工具上传 应用市场/内测分发 App Store / TestFlight
/api 反代 https+备案域名 证书+包名+权限 开发者账号+证书一、发布前检查清单
# 1) 后端地址(必须改成正式域名,且小程序端必须 https)
sed -n '1,10p' App/utils/.env.js
# 2) 版本
grep -E '"versionName"|"versionCode"' App/manifest.json # 1.0.0 / 100
# 3) 微信小程序 appid(仓库当前为空!)
grep -A2 '"mp-weixin"' App/manifest.json
# 4) 图标资源(manifest 指向 unpackage/res/icons,需先生成)
ls App/unpackage/res/icons 2>/dev/null || echo "图标未生成,需在 HBuilderX 上传图标"
# 5) 全仓库搜一遍是否还有本地地址残留
grep -rn "localhost:5005" App/ --include=*.js --include=*.ts --include=*.vue
# 6) 隐私政策(Android 上架必查)
cat App/androidPrivacy.json # 当前是 { "prompt": "template" }二、接口地址切换
App/utils/.env.js(注意这是个点开头的隐藏文件,在 utils/ 目录下):
const env = {
baseUrl: 'https://api.yourdomain.com', // ★ 生产环境:https + 备案域名
header: {},
smKey: '04851D32...E9', // 与后端 CryptogramHelper 配对,换环境要同步
defaultUser: '', // 生产环境清空默认账号/密码
defaultPassword: '',
defaultServicePhone: '18012345678'
}
export { env }建议做法(若需要多环境切换,可自行改造该文件,当前仓库为单环境):
const envMap = {
dev: { baseUrl: 'http://localhost:5005' },
test: { baseUrl: 'https://test-api.yourdomain.com' },
prod: { baseUrl: 'https://api.yourdomain.com' }
}
const cur = 'prod' // 发版前改这里
const env = { ...envMap[cur], header: {}, smKey: '...', defaultUser: '', defaultPassword: '', defaultServicePhone: '' }
export { env }baseUrl 在两处被消费:
// ① utils/request.js → http.setConfig({ baseURL }) 所有 /api/... 请求
// ② pages/mine/mine.vue → env.baseUrl + state.userInfo.avatar 拼接头像等静态资源换环境别忘了 `smKey`
登录密码用 SM2 公钥加密,smKey 与后端密钥对绑定。换到新环境(后端重新生成过密钥对)后不改这里,登录会直接失败。
三、manifest.json 关键字段速查
{
"name": "Admin.NET",
"appid": "__UNI__B91D75F", // uni-app 应用标识,云端打包凭证,不要改
"versionName": "1.0.0", // 展示版本
"versionCode": "100", // Android 内部版本,每次发版必须递增
"transformPx": false, // 关闭 px 转换,尺寸靠 rpx
"vueVersion": "3", // ★ Vue 3,与 main.js 的 createSSRApp 一致
"locale": "zh-Hans",
"uniStatistics": { "enable": false },
"app-plus": {
"compilerVersion": 3,
"nvueStyleCompiler": "uni-app",
"modules": {}, // 用到的原生模块(推送/支付/定位…)
"distribute": {
"android": { "permissions": [ /* 预置 15 项权限 */ ] },
"ios": {}, // ★ 本仓库为空节点
"sdkConfigs": { "oauth": {}, "payment": {} },
"icons": { "android": {...}, "ios": {...} } // 指向 unpackage/res/icons
}
},
"mp-weixin": { "appid": "", "setting": { "urlCheck": false }, "usingComponents": true },
"quickapp": {}
}| 字段 | 发版时必须动吗 | 说明 |
|---|---|---|
versionName | ✅ | 用户可见版本,建议遵循语义化版本 |
versionCode | ✅ | Android 内部版本号,必须递增,否则无法覆盖安装 |
mp-weixin.appid | ✅(小程序) | 微信公众平台 → 开发管理 → 开发设置 |
app-plus.distribute.icons | ✅(App) | 需在 HBuilderX 上传图标自动生成到 unpackage/res/icons |
app-plus.modules | 按需 | 用到推送、支付、定位等原生能力时勾选 |
uniStatistics.enable | 按需 | 当前 false,开启需注意隐私合规 |
四、H5 打包
- HBuilderX:
发行 → 网站-H5手机版(仅适用于手机),产物在dist/build/h5。 - CLI:本仓库
App/package.json未提供scripts与@dcloudio/*CLI 依赖(只有dependencies),因此官方推荐用 HBuilderX 可视化发行;若要用命令行,需按 uni-app 官方文档自行补齐 CLI 依赖与 scripts,本仓库未提供现成命令。 - 部署到 nginx:
server {
listen 80;
server_name h5.yourdomain.com;
root /www/adminnet-h5; # dist/build/h5 内容
index index.html;
location / {
try_files $uri $uri/ /index.html; # 刷新 404 必备
}
# 反向代理解决跨域,页面里 baseUrl 可保持同源
location /api/ {
proxy_pass http://127.0.0.1:5005/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}要点:
- H5 是单页应用,必须配
try_files,否则刷新子路径 404。 - 同域部署时把
baseUrl留成相对路径或同源域名,可彻底规避 CORS。 - 不同域则在后端开启 CORS(允许来源写具体域名,不要用
*配凭证请求)。 - 静态资源建议加长期缓存,但
index.html必须no-cache,否则用户拿不到新版:
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
location = /index.html {
add_header Cache-Control "no-cache, no-store, must-revalidate";
}五、微信小程序发布
manifest.json填 appid(仓库当前为""):
"mp-weixin" : {
"appid" : "wx1234567890abcdef", // ★ 微信公众平台 → 开发管理 → 开发设置
"setting" : { "urlCheck" : false }, // 开发期关闭域名校验;提审前建议改为 true 自检
"usingComponents" : true
}- HBuilderX:
发行 → 小程序-微信,产物dist/build/mp-weixin。 - 用微信开发者工具打开该目录 → 右上角「上传」→ 填版本号与备注。
- 微信公众平台 → 管理 → 版本管理 → 提交审核 → 发布。
服务器域名配置(微信公众平台 → 开发 → 开发设置 → 服务器域名):
| 类型 | 示例 |
|---|---|
| request 合法域名 | https://api.yourdomain.com |
| uploadFile 合法域名 | https://api.yourdomain.com |
| downloadFile 合法域名 | https://api.yourdomain.com |
硬性要求:https + ICP 备案域名,不支持 IP 与 http。 开发阶段可在开发者工具「详情 → 本地设置」勾选「不校验合法域名、web-view、TLS 版本」临时绕过。
小程序端额外检查(本仓库已知问题):
login.vue/about.vue/mine.vue/password.vue里混用了div/span/br,小程序端可能渲染异常,发布前统一改成view/text。- 头像拼接用了
env.baseUrl + avatar,确保该域名在downloadFile(图片展示走image组件,域名需加入 downloadFile 白名单)范围内。
六、Android 打包
manifest.json → app-plus.distribute.android 已预置权限(网络状态、相机、振动、闪光灯、WiFi、读写设置等),按需增删:
"android" : {
"permissions" : [
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>"
]
}云打包步骤(HBuilderX):
manifest.json→ 基础配置:应用名称Admin.NET、版本号1.0.0/versionCode 100。- App 图标:切换到「App图标配置」,上传 1024×1024 图标并自动生成全部尺寸(会写入
unpackage/res/icons,当前仓库未包含该目录)。 - 启动图(splashscreen):
alwaysShowBeforeRender: true、autoclose: true。 - 隐私合规:
App/androidPrivacy.json当前为{ "prompt": "template" },上架前必须换成真实隐私政策配置的prompt: "custom"并填写title/message/buttonAccept,否则应用市场会拒审。 发行 → 原生App-云打包:选 Android,填包名(如com.yourcompany.adminnet)与证书(可用 DCloud 公共测试证书调试,正式版用自有.keystore)。- 产出
.apk(或.aab),分发到应用市场 / 内测平台。
隐私政策文件示例:
{
"prompt": "custom",
"title": "服务协议和隐私政策",
"message": "请你务必审慎阅读、充分理解「服务协议和隐私政策」各条款内容……",
"buttonAccept": "同意并接受",
"buttonRefuse": "暂不同意",
"second": {
"title": "确认提示",
"message": "进入应用前,你需要先同意服务协议和隐私政策",
"buttonAccept": "同意并继续",
"buttonRefuse": "退出应用"
},
"styles": { "backgroundColor": "#FFFFFF", "buttonAccept": { "color": "#11559c" } }
}自有证书(正式发布):
keytool -genkey -alias adminnet -keyalg RSA -keysize 2048 -validity 36500 \
-keystore adminnet.keystore
# 记住别名与两个密码,云打包时填写;丢失证书将无法覆盖安装升级七、iOS 打包
仓库 manifest.json 的 distribute.ios 为空节点({}),证书、Bundle ID、描述文件等配置未在本仓库提供,需在 HBuilderX 中自行填写:
- 准备 Apple Developer 账号(99 美元/年)+ 发布证书
.p12+ 描述文件.mobileprovision。 manifest.json→ App 图标配置(iOS 需要appstore 1024×1024及 iPhone/iPad 各尺寸)。发行 → 原生App-云打包→ iOS → 上传证书并填 Bundle ID。- 产出
.ipa→ Transporter 上传 → App Store Connect 提交审核(TestFlight 可先内测)。
八、热更新(wgt)
uni-app 支持用 wgt 资源包做增量热更新(发行 → 制作移动App资源升级包,配合服务端的版本接口静默安装)。
本仓库未提供热更新相关代码(没有版本检查接口调用、没有 plus.runtime.install 逻辑,api_all/ 里也没有应用版本接口)。需要时请自行新增后端版本接口 + 前端下载安装逻辑,并注意:涉及原生模块变更、manifest 变更时必须整包升级,wgt 只覆盖前端资源。
九、常见坑与排查
| 现象 | 原因 | 处理 |
|---|---|---|
| 小程序请求全部失败 | 域名未备案 / 非 https / 不在合法域名列表 | 配 https 备案域名并加入 request 合法域名 |
| 真机白屏、开发者工具正常 | baseUrl 用了 localhost | 手机访问不到电脑的 localhost,改用局域网 IP 或正式域名 |
| H5 刷新 404 | nginx 未配 try_files | 加 try_files $uri $uri/ /index.html |
| H5 报 CORS | 前后端不同源且后端未开 CORS | nginx 反代 /api 或后端开 CORS |
| 登录后立刻跳回登录页 | 401:Token 过期/TokenVersion 不一致/smKey 与后端不匹配 | 抓包看 code;核对 smKey、系统配置的 Token 过期时间 |
| 一直弹「登录失败」 | 密码 SM2 加密用的公钥与后端配对失败 | 后端重新生成密钥对后必须同步 .env.js 的 smKey |
| 云打包报图标缺失 | unpackage/res/icons 不存在 | HBuilderX 图标配置里上传并自动生成 |
| 上架被拒(隐私) | androidPrivacy.json 仍是模板 | 改 prompt: "custom" 并填真实隐私政策 |
| 小程序上传后功能缺失 | 用了 div/span/br、window、FormData | 改为 view/text,上传改用 uni.uploadFile |
| 打包后接口还是打到 5005 | .env.js 未改 | 全局搜索 localhost:5005 确认无残留 |
| 修改权限后不生效 | 权限缓存 7 天(CacheConst.KeyUserApi) | 重新登录或清缓存 |
| iOS 打包报证书错误 | 证书/描述文件与 Bundle ID 不匹配 | 重新生成并确认三者一致 |
| App 安装失败/无法覆盖 | versionCode 没递增或证书不一致 | 递增 versionCode,沿用同一 .keystore |
| 头像/图片不显示 | 图片域名不在小程序 downloadFile 白名单 | 加入合法域名或改用同源反代 |
排查顺序建议:
① 浏览器/开发者工具 Network 看请求 URL 与 code
② 看响应头 access-token 是否回写、是否 invalid_token
③ 后端日志(Swagger 直连同一接口排除前端问题)
④ 真机「不校验合法域名」开关先排除域名问题
⑤ 最后再看打包配置(appid / 图标 / 证书 / 隐私)步骤清单
- 改
App/utils/.env.js(baseUrl指向生产,清空默认账号密码,核对smKey)。 - 改版本号:
manifest.json的versionName/versionCode(Android 每次发版versionCode必须递增)。 - H5:HBuilderX「发行 → 网站-H5」→ 上传
dist/build/h5到 nginx,配/api反代 +try_files,index.html设no-cache。 - 小程序:填
mp-weixin.appid→ 配置 https 备案合法域名 → 发行 → 开发者工具上传 → 提交审核。 - Android:配图标/权限/
androidPrivacy.json→ 云打包 → 分发。 - iOS:准备开发者账号与证书 → 填 Bundle ID 与图标 → 云打包 → App Store Connect 提审。
- 回归:登录、列表、上传下载、退出登录在生产环境各跑一遍。
⚠️ 注意事项
- 不要提交真实密钥与默认账号:
utils/.env.js里的smKey、defaultPassword属于敏感信息,生产环境务必清空默认账号密码。 versionCode必须递增,否则应用市场判定为旧包无法覆盖安装。urlCheck: false只是开发便利,提审前改回true验证域名配置正确。uniStatistics.enable当前为false,如需统计再开启,注意隐私合规声明。- 云打包依赖 DCloud 服务:正式项目建议保存自有证书与离线打包环境,避免云端排队与政策变动。
.env.js是隐藏文件:容易被.gitignore或文件同步工具漏掉,发布前确认它真的被打包进去了(打包后真机看 Network 的域名即可验证)。manifest.json里带注释:uni-app 支持带注释的 JSON(HBuilderX 能解析),但用脚本JSON.parse读取会失败,写自动化脚本时先剔除注释。- App 端
appid(__UNI__B91D75F)不要改:它与 DCloud 云端打包记录绑定,改了会丢失证书/插件配置。
小结
发版 = 改地址 + 改版本 + 按端打包。唯一容易漏的是小程序域名备案与Android 隐私政策(本仓库仍是 prompt: "template"),这两项提前处理可省掉大部分审核往返。另外记住 smKey 与后端配对、versionCode 递增、index.html 不缓存这三件小事,能避免绝大多数线上事故。