Android APK 完整打包教程
本文用于将 ruoyi-office-uniapp 编译并打包为可独立安装的 Android APK,覆盖环境配置、证书、图标、清理缓存、真机调试、DCloud 云打包、安装验证和常见问题。
先区分两个动作
- 运行到 Android 真机 / 模拟器:HBuilderX 使用调试基座同步资源,不需要云打包。
- 生成独立 APK:需要 DCloud 云打包,或自行配置 Android 离线打包环境。
一、打包流程总览
推荐先通过真机调试确认页面和接口正常,再提交云打包,避免反复消耗云打包次数或余额。
二、环境准备
1. 必备软件
| 工具 | 建议版本 | 用途 |
|---|---|---|
| Node.js | 20 或更高 | UniApp 编译 |
| pnpm | 9 或更高 | 安装依赖、执行构建 |
| HBuilderX | 使用当前稳定版 | 真机调试、云打包 |
JDK keytool | JDK 17 或更高 | 生成和检查 Android 证书 |
| Android SDK Platform Tools | 当前稳定版 | adb 安装、截图和日志 |
检查命令:
node --version
pnpm --version
java -version
adb version2. 登录 DCloud 账号
打开 HBuilderX,登录拥有目标 AppID 的 DCloud 账号。
需要确认:
- AppID 已创建并归属于当前账号或当前账号有协作权限。
- 云打包余额和“App 大小超限”额度充足。
- 充值后若余额未刷新,完全退出并重新启动 HBuilderX。
3. 拉取并确认最新代码
cd D:\workspace\ruoyi-office-uniapp
git status --short
git pull
git log -1 --format="%H%n%ci%n%s"
pnpm install --frozen-lockfile工作区存在未提交修改时不要直接覆盖或清理,先确认这些修改是否属于本次发布。
三、配置打包环境
RuoYi Office UniApp 的环境变量位于 env/ 目录,配置优先级为:
env/.env.[mode] > env/.env1. 新建生产 App 配置
建议为每个客户或环境建立独立 mode,例如:
env/.env.app-prod
env/.env.app-demo
env/.env.customer-a示例 env/.env.app-prod:
NODE_ENV = 'production'
VITE_DELETE_CONSOLE = true
VITE_SHOW_SOURCEMAP = false
# App 必须使用手机可访问的绝对地址,不能写 H5 的相对路径 /admin-api
VITE_SERVER_BASEURL = 'https://office.example.com/admin-api'
VITE_UPLOAD_BASEURL = 'https://office.example.com/upload'
VITE_STATIC_BASEURL = 'https://office.example.com'
VITE_WEB_H5_BASEURL = 'https://office.example.com/web'
VITE_APP_PUBLIC_BASE=/生产环境优先使用 HTTPS。使用局域网 IP 时,要确认手机与服务器网络互通,且 Android 明文 HTTP 策略与后端跨域、网关配置满足要求。
2. 配置 AppID、包名和应用名称
在 env/.env 或对应 mode 文件中确认:
VITE_APP_TITLE = '企业管理一体化平台'
VITE_UNI_APPID = '__UNI__XXXXXXXX'
VITE_ANDROID_PACKAGE = 'com.example.ruoyioffice'三者含义:
| 配置 | 说明 | 发布后是否建议修改 |
|---|---|---|
VITE_UNI_APPID | DCloud 应用标识 | 不建议 |
VITE_ANDROID_PACKAGE | Android 包名 | 不建议,修改后会被视为另一款 App |
VITE_APP_TITLE | 桌面和系统中的应用名称 | 可按品牌调整 |
升级已有 App 时必须保持包名和签名证书不变,否则无法覆盖安装。
3. 配置版本号
编辑 manifest.config.ts:
export default defineManifestConfig({
versionName: '1.0.1',
versionCode: '101',
})versionName:展示给用户看的版本,例如1.0.1。versionCode:Android 内部版本号,必须为整数形式的字符串,并且每次发布递增。
4. 检查 Android 权限和原生模块
RuoYi Office 在 manifest.config.ts 的 app-plus 中维护 Android 配置:
'app-plus': {
modules: {
Geolocation: {},
},
distribute: {
android: {
packagename: VITE_ANDROID_PACKAGE,
minSdkVersion: 21,
targetSdkVersion: 30,
abiFilters: ['armeabi-v7a', 'arm64-v8a'],
permissions: [
// 按实际业务保留权限
],
},
},
}调试基座内置的原生模块比正式 APK 多。定位、扫码、推送等功能在调试基座正常,不代表正式 APK 一定正常;正式包使用的模块必须在 modules 中显式配置。
权限应按最小化原则保留,并同步准备隐私政策和权限用途说明。上架应用市场前,必须完成 Android 隐私合规配置。
四、配置 Android 图标
图标文件位于:
static/app/icons/Android 常用尺寸:
| 密度 | 尺寸 | 项目文件 |
|---|---|---|
| hdpi | 72 × 72 | 72x72.png |
| xhdpi | 96 × 96 | 96x96.png |
| xxhdpi | 144 × 144 | 144x144.png |
| xxxhdpi | 192 × 192 | 192x192.png |
| 商店原图 | 1024 × 1024 | 1024x1024.png |
manifest.config.ts 中的路径示例:
icons: {
android: {
hdpi: 'static/app/icons/72x72.png',
xhdpi: 'static/app/icons/96x96.png',
xxhdpi: 'static/app/icons/144x144.png',
xxxhdpi: 'static/app/icons/192x192.png',
},
}检查要求:
- 图片为 PNG,尺寸正确。
- 图标主体不要贴边,避免被不同厂商桌面裁切。
- 不需要透明背景时,先合成为白底或品牌底色。
- 不要把备份图标放进正式
static目录;static下的文件可能进入打包资源。 - 修改图标后必须重新执行 UniApp 编译和 APK 打包,仅替换源码图片不会更新旧 APK。
五、生成和保管 Android 证书
1. 首次生成证书
在安全目录执行:
keytool -genkeypair `
-v `
-keystore D:\android-signing\ruoyi-office.keystore `
-alias ruoyioffice `
-keyalg RSA `
-keysize 2048 `
-validity 36500按提示输入:
- keystore 密码
- key 密码
- 组织和地区信息
证书一旦用于正式发布,应长期保管。证书丢失通常意味着无法继续升级同包名应用。
2. 查看证书指纹
keytool -list -v `
-keystore D:\android-signing\ruoyi-office.keystore `
-alias ruoyioffice记录:
- Alias
- SHA-1
- SHA-256
- 有效期
3. 安全要求
- keystore、密码和导出的签名信息不要提交 Git。
- 正式证书至少保留两份离线备份。
- 演示、测试和生产建议使用不同证书。
- 不要在公开文档、截图、构建日志中暴露真实密码。
六、彻底清理旧产物并保留证据
“干净打包”不是直接删除整个项目,而是先备份并隔离会被复用的构建目录。
以下为 Windows PowerShell 示例:
$project = 'D:\workspace\ruoyi-office-uniapp'
$stamp = Get-Date -Format 'yyyyMMdd_HHmmss'
$backup = "D:\android-pack\backups\clean-build_$stamp"
New-Item -ItemType Directory -Path $backup -Force | Out-Null
# 先备份旧 App 产物
if (Test-Path "$project\dist\build\app") {
robocopy `
"$project\dist\build\app" `
"$backup\dist-build-app" `
/E /COPY:DAT /DCOPY:DAT /R:2 /W:1
}
# 将旧目录改名隔离,标准构建路径立即变为空
if (Test-Path "$project\dist\build\app") {
Rename-Item `
-LiteralPath "$project\dist\build\app" `
-NewName "app.pre-clean-$stamp"
}
if (Test-Path "$project\node_modules\.cache") {
Rename-Item `
-LiteralPath "$project\node_modules\.cache" `
-NewName ".cache.pre-clean-$stamp"
}如使用 HBuilderX CLI 云打包,还可在关闭 HBuilderX 后隔离其临时目录:
$tempPack = "$env:LOCALAPPDATA\Temp\app-pack"
if (Test-Path $tempPack) {
Rename-Item `
-LiteralPath $tempPack `
-NewName "app-pack.pre-clean-$stamp"
}清理后确认标准路径不存在:
Test-Path "$project\dist\build\app"
Test-Path "$project\node_modules\.cache"
Test-Path "$env:LOCALAPPDATA\Temp\app-pack"三个结果应为 False。不要在 HBuilderX、Node 或打包进程仍占用文件时强制删除目录。
七、重新编译 App 资源
进入 UniApp 项目:
cd D:\workspace\ruoyi-office-uniapp生产环境:
pnpm exec uni build -p app --mode app-prod演示环境:
pnpm exec uni build -p app --mode app-demo也可以使用项目脚本:
pnpm build:app:prod成功标志:
DONE Build complete.
Run method: open HBuilderX, import dist\build\app run.产物目录:
dist/build/app编译后核对
$output = 'D:\workspace\ruoyi-office-uniapp\dist\build\app'
$manifest = Get-Content "$output\manifest.json" -Raw | ConvertFrom-Json
$manifest.id
$manifest.name
Get-Item "$output\app-service.js" |
Select-Object FullName, Length, LastWriteTime确认:
manifest.json中 AppID 正确。app-service.js修改时间属于本次构建。- 构建日志中的 API 地址、包名、AppID 和 mode 正确。
- 图标文件属于本次准备的版本。
八、创建独立、可审计的打包目录
不要长期复用混有 .hbuilderx、unpackage 或旧资源的目录。建议每次发布创建新目录:
$source = 'D:\workspace\ruoyi-office-uniapp\dist\build\app'
$target = 'D:\android-pack\ruoyi-office-android-20260730-01'
if (Test-Path $target) {
throw "目标目录已存在,请先备份或换一个新目录:$target"
}
New-Item -ItemType Directory -Path $target | Out-Null
robocopy $source $target /E /COPY:DAT /DCOPY:DAT /R:2 /W:1逐文件 SHA-256 比对
function Get-DirectoryManifest($root) {
Get-ChildItem -LiteralPath $root -Recurse -File |
ForEach-Object {
[pscustomobject]@{
Path = $_.FullName.Substring($root.Length).TrimStart('\')
Length = $_.Length
SHA256 = (Get-FileHash $_.FullName -Algorithm SHA256).Hash
}
} |
Sort-Object Path
}
$sourceManifest = @(Get-DirectoryManifest $source)
$targetManifest = @(Get-DirectoryManifest $target)
$differences = @(
Compare-Object `
$sourceManifest `
$targetManifest `
-Property Path, Length, SHA256
)
"源文件数:$($sourceManifest.Count)"
"目标文件数:$($targetManifest.Count)"
"哈希差异:$($differences.Count)"哈希差异 应为 0。建议将清单导出并随 APK 归档:
$sourceManifest | Export-Csv `
'D:\android-pack\source-sha256.csv' `
-NoTypeInformation `
-Encoding UTF8九、运行到 Android 真机
1. 手机准备
- 开启开发者选项。
- 开启 USB 调试。
- 使用数据线连接电脑。
- 手机弹出授权提示时,允许该电脑调试。
检查设备:
adb devices -l真实手机通常显示 USB 序列号。127.0.0.1:7555 等本机端口通常是模拟器,不应当作真实手机验收。
2. HBuilderX 图形界面运行
- 打开 HBuilderX。
- 选择“文件 → 导入 → 从本地目录导入”。
- 导入刚创建的独立打包目录。
- 选择“运行 → 运行到手机或模拟器 → 运行到 Android App 基座”。
- 选择已连接的真实手机。
首次运行可能安装或更新 HBuilder 调试基座,并弹出权限请求。
3. HBuilderX CLI 运行
& 'D:\Program Files\HBuilderX\cli.exe' open
& 'D:\Program Files\HBuilderX\cli.exe' project open `
--path 'D:\android-pack\ruoyi-office-android-20260730-01'
& 'D:\Program Files\HBuilderX\cli.exe' launch app-android `
--project 'D:\android-pack\ruoyi-office-android-20260730-01' `
--deviceId '<adb devices 显示的设备序列号>' `
--playground standard `
--native-log false `
--continue-on-error false4. 真机调试验收
- 登录页、Logo、应用名称正常。
- 接口请求指向目标环境。
- 登录、菜单、列表、详情、审批流程正常。
- 定位、相机、扫码、文件上传等原生能力正常。
- 不只验证首页,要覆盖正式 APK 所依赖的原生模块。
保存日志:
adb logcat -c
# 复现问题后
adb logcat -d -v time > D:\android-pack\logcat.txt保存截图:
adb shell screencap -p /sdcard/ruoyi-office-check.png
adb pull /sdcard/ruoyi-office-check.png D:\android-pack\十、DCloud 云打包生成 APK
方式一:HBuilderX 图形界面
- 使用 HBuilderX 导入独立打包目录。
- 选择“发行 → 原生 App-云打包”。
- 平台选择 Android。
- 填写包名。
- 选择“使用自有证书”。
- 填写 keystore、Alias、证书密码。
- 选择正式包,不勾选不需要的广告和渠道能力。
- 提交云打包。
- 等待完成并下载 APK。
方式二:HBuilderX CLI
& 'D:\Program Files\HBuilderX\cli.exe' pack `
--project 'D:\android-pack\ruoyi-office-android-20260730-01' `
--platform android `
--android.packagename com.example.ruoyioffice `
--android.androidpacktype 0 `
--android.certalias ruoyioffice `
--android.certfile 'D:\android-signing\ruoyi-office.keystore' `
--android.certpassword '<KEY_PASSWORD>' `
--android.storepassword '<STORE_PASSWORD>' `
--safemode false `
--sourceMap false `
--isconfusion false `
--splashads false `
--rpads false `
--unimpads false注意:
- 命令行密码可能进入终端历史和进程列表,只适合受控构建机。
- AppID、包名、Alias、证书文件和密码必须配套。
- CLI 长时间无输出时,先检查 HBuilderX 界面、DCloud 登录状态、网络和
cli.exe进程,不要重复提交多个任务。 - 临时 WGT 常见于
%LOCALAPPDATA%\Temp\app-pack\,WGT 生成不等于 APK 已打包成功。
项目体积超过 60 MB
DCloud 的免费额度按云打包上传的未压缩项目体积计算,不是最终 APK 或 WGT 大小。
处理方式:
- 检查是否把备份图标、无用图片、视频、源码归档放进了
static。 - 删除确定不需要的本地原生插件和资源。
- 对大图片做无损或有损压缩。
- 为“App 大小超限”充值,并确认充值账号与 HBuilderX 登录账号一致。
- 充值后重启 HBuilderX 再提交。
不要为了低于额度而盲目删除业务分包;必须重新完成真机回归。
十一、校验 APK
1. 计算 APK 哈希
Get-FileHash `
'D:\android-pack\ruoyi-office-release.apk' `
-Algorithm SHA256将 SHA-256 写入发布记录,交付双方可据此确认文件未被替换。
2. 校验签名
apksigner 位于 Android SDK build-tools 目录:
apksigner verify `
--verbose `
--print-certs `
'D:\android-pack\ruoyi-office-release.apk'核对证书 SHA-1、SHA-256 是否与发布证书一致。
3. 校验包名和版本
aapt dump badging `
'D:\android-pack\ruoyi-office-release.apk'重点检查:
package: nameversionCodeversionNameapplication-labelsdkVersiontargetSdkVersion
十二、安装正式 APK
1. 全新安装
adb install 'D:\android-pack\ruoyi-office-release.apk'2. 覆盖安装
adb install -r 'D:\android-pack\ruoyi-office-release.apk'覆盖安装失败的常见原因:
- 新旧 APK 包名不同。
- 签名证书不同。
- 新包
versionCode小于已安装版本。
不要为了测试覆盖安装而删除用户数据。必须卸载时,先确认是否需要备份业务数据。
十三、正式 APK 验收清单
基础信息
- [ ] AppID 与目标 DCloud 应用一致
- [ ] 包名正确
- [ ]
versionCode已递增 - [ ] 应用名称正确
- [ ] 桌面图标为最新版本,无透明黑底或旧 Logo
- [ ] APK 签名指纹与发布证书一致
环境与安全
- [ ] API、上传、静态资源和 Web 地址均指向目标环境
- [ ] 生产包无演示域名和默认测试地址
- [ ] 生产环境使用 HTTPS
- [ ] 登录验证码、接口加密与后端配置一致
- [ ] 权限申请时机和用途说明合理
- [ ] 隐私政策可访问
功能
- [ ] 登录、退出、Token 失效跳转正常
- [ ] 首页和菜单完整
- [ ] 列表、详情、新增、编辑正常
- [ ] BPM 发起、审批、驳回和详情正常
- [ ] 图片、附件上传与预览正常
- [ ] 定位、相机、扫码等原生能力正常
- [ ] App 冷启动、切后台和恢复正常
稳定性
- [ ] 无白屏
- [ ] 无持续崩溃
- [ ]
adb logcat无FATAL EXCEPTION - [ ] 无 JS 实例创建失败
- [ ] 弱网和接口 401/500 时页面有合理提示
十四、常见问题
1. 修改 Logo 后 APK 仍是旧图标
原因通常是:
- 只修改源码图片,没有重新执行
uni build。 - HBuilderX 导入的是旧
dist/build/app。 - 云打包临时目录仍来自上一次任务。
- 手机桌面缓存旧图标。
处理顺序:
- 核对
manifest.config.ts图标路径。 - 隔离旧
dist/build/app和 HBuilderapp-pack。 - 重新编译。
- 创建新的独立打包目录。
- 重新云打包。
- 卸载旧测试包后再检查桌面图标。
2. 真机只显示部分菜单
先区分:
- 页面没有渲染完整。
- 登录用户权限或后端返回菜单本来就少。
- JS 启动阶段报错,页面只剩原生导航或底部栏。
检查:
adb logcat -d -v time |
Select-String `
'FATAL EXCEPTION|Uncaught ReferenceError|createInstanceContext failed|WX_RENDER_ERR'同时检查网络请求、用户角色和后端菜单接口。
3. 调试基座正常,正式 APK 功能失效
调试基座内置模块更多。检查 manifest.config.ts 的:
app-plus.modules- Android permissions
sdkConfigs- ABI 和最低 SDK
修改后必须重新编译并重新打包 APK。
4. CLI 卡住或没有生成 APK
- 检查 HBuilderX 是否已登录 DCloud。
- 查看 HBuilderX 界面是否有证书、隐私或余额提示。
- 检查
cli.exe、HBuilderX.exe是否存在重复进程。 - 检查
%LOCALAPPDATA%\Temp\app-pack是否只生成 WGT。 - 不要把“WGT 已生成”误判为“APK 已完成”。
5. 云打包提示隐私配置缺失
不上架应用市场时可按交付要求评估;需要上架时必须配置:
- 隐私政策链接
- 权限用途说明
- 首次启动隐私授权
- 第三方 SDK 信息
- 注销与个人信息处理规则
十五、发布归档建议
每次正式发布建议归档:
android-release/
├── ruoyi-office-v1.0.1.apk
├── ruoyi-office-v1.0.1.apk.sha256.txt
├── source-sha256.csv
├── build-info.txt
├── certificate-fingerprint.txt
├── logcat-smoke.txt
├── screenshots/
└── release-checklist.mdbuild-info.txt 至少记录:
Git commit:
Build time:
Build mode:
Node version:
pnpm version:
HBuilderX version:
DCloud AppID:
Android package:
versionName:
versionCode:
API base URL:
Certificate SHA-1:
APK SHA-256:
Tester:这样可以证明 APK 来自哪个提交、哪个环境、哪个证书,也能在客户反馈问题时快速复现。
相关文档:关闭演示与安全基线 · Logo 与系统名称 · 上线验收清单
