还在调整细节,应该很快就能开发好。
可以看一下编译的H5页面效果:https://www.flinthub.top/h5
这份工程是燧石社区的手机客户端(uni-app,Vue 3 + Vite),能出 H5 网页版 和 Android APK。 你拿到的是源码 + 构建配置,不含任何节点依赖和构建产物,也不含任何站点的连接信息: src/utils/site.config.js 里的连接常量为空,需要你填自己的。
成品包一共五步:填配置 → 装依赖 → 命令行构建 → HBuilderX 云打包 → 装上验收。 下面每一步都写了「怎么判断这一步真的成功了」,跳步或看错了征兆,最常见的结果是装出来的包能开但一条数据都读不到。
〇、先确认三件事
| 前提 | 说明 |
|---|---|
你的站点装着 mobile_api 插件 |
客户端只认这个插件的接口(本站在用的是 1.1.0)。没有它,下面所有步骤都能走完,包打出来是空壳。 |
| 站点是 HTTPS | 客户端不会去碰安卓 9+ 的明文流量限制。站点只有 HTTP 的话,先在原生层放开 usesCleartextTraffic 之前想清楚:那是安全倒退,别为了省事做。 |
| 你有 DCloud 账号 | APK 由 HBuilderX 的云打包出,命令行出不了 .apk。 |
技术栈与版本(本机实测跑通的组合):
- Node.js 18 以上(本机 24.x)
@dcloudio/*全家桶3.0.0-alpha-5030120260930001,vite5.2.8,vue3.4.21- HBuilderX 选 「App 开发版」,不是纯前端版
@dcloudio/uni-app-plus这个依赖必须和其它@dcloudio/*同一个版本号。少了它或版本不一致,uni build -p app不会报错,它会静默按 H5 编译,产物是一份index.html + assets/*.js的网页包, 看上去像成功了。判别方法见第三步。
一、接上你自己的站(唯一必须改的地方)
打开 src/utils/site.config.js,填一行:
export const SITE_API_BASE = 'https://你的域名';
SITE_API_BASE:站点的根地址,必须以http://或https://开头,末尾有没有斜杠都行(代码会去掉)。 只填到域名(协议 + 主机)即可,客户端自己会拼/api/*(REST + Bearer 令牌)。SITE_NAME_FALLBACK:接口还没回来(或站点连不上)时登录页品牌区先显示的名字,可留默认。
站点这一侧要装 mobile_api 插件,并且站点走 HTTPS(安卓 9+ 默认拒绝明文 HTTP)。
不想改源文件(CI、或者一份工程给多个人用)就用环境变量覆盖,环境变量优先于源码常量:
cp .env.example .env.local # 填 VITE_API_BASE
两种写法都行,别同时留两份不同的真值。
第三步「构建」之前改才算数。App 里没有连接设置页,终端用户改不了连的是哪个站; 装好之后「我的」页有一行只读的「当前连接」(显示域名,未配置时显示未配置)给你自查。
顺带一提,src/manifest.json 的 name、src/pages.json 的 navigationBarTitleText、 index.html 的 <title>、package.json 的 description 这几处写着「燧石社区」,是显示用的站名; 客户端连上站点后,多数位置会显示站点自己下发的名字,这几处是兜底和外壳。
二、装依赖
npm install
package-lock.json 带着走,锁的是 npmmirror 公共镜像地址,不需要额外配 registry。
三、命令行构建
npm run build:app # App 资源包 → dist/build/app
npm run build:h5 # 网页版 → dist/build/h5
App 产物正确的样子:目录里应该有 app-service.js、app-config.js、manifest.json、 uni-app-view.umd.js,外加每个页面一个 pages/*/index.css,总量约 1.2 MB。 只有 index.html 和 assets/ 的就是假成功(按 H5 编译去了,回第一步查 uni-app-plus 依赖版本)。
H5 那一份是纯静态站,dist/build/h5 整个目录扔到任意静态服务器就能访问; manifest.json 里 h5 的 router.base 是 ./,所以放子目录也不用改配置。
改过源码之后要重新出 APK,固定顺序是:改源码 → npm run build:app → 回 HBuilderX 重新云打包。 只在 HBuilderX 里点、不重跑构建,打进包里的是旧代码。
外发给别人 / 换一台机器打包之前:dist/ 整个删掉再构建。uni build 只重写它自己那一个目标目录, 源码里删过的页面,旧的 dist/build/app(以及 app-plus)里可能还留着那些路由, 而 HBuilderX 读的就是这份产物——不删就会打出带死页面的包。dist/ 随时能重新生成,里面没有手写内容。
四、HBuilderX 云打包出 APK
文件 → 导入 → 从本地目录,选中这份工程目录(部署教程.md所在的那一层)。- 打开
src/manifest.json的可视化界面,在「基础配置」里点 「重新获取」 补appid。 这份工程里appid是空的(外发前清的),不补云打包会直接拒。 - 同一屏把 Android 包名填上,比如
com.你的名字.客户端。 填一个稳定值,以后不要改:改了包名等于换了一个应用,老包无法覆盖升级,用户要卸载重装。 - 启动界面在这台面板里配,不在代码里:左侧列表选「App 启动界面配置」,勾上 Android 启动图, 把
启动图/里现成的三张按分辨率传上去——splash-android-720x1280.png、splash-android-1080x1920.png、splash-android-1080x2340.png。 素材是瓷白底 + 字标 + 口号 + 页脚版本,改版号或改文案要重新出图再传。manifest.json里没有能写启动图片路径的公开键,启动图本体只存在于面板生成的原生资源里, 换机器打包要重新传一遍,别以为改了代码就跟着走。- 「App 图标配置」也要一起配。安卓 12 及以上会先画一层系统启动页(纯色底 + 居中的应用图标), 然后才是上面这张图。两层底色对不上就会看到一次颜色跳变,图标那一屏选同一个瓷白(
#ffffff)或品牌色。 app-plus.splashscreen里的alwaysShowBeforeRender和autoclose保持true别动: 前者保证首页画好之前启动图不消失(否则中间闪一屏白),后者保证它自己收掉 (不关就要自己写plus.navigator.closeSplashscreen(),忘了就卡在启动图)。
发行 → 原生App-云打包,勾 Android。 第一次先用「公共测试证书」出包,把链路验证到能装能读数据; 确认没问题之后再换自有证书。自有证书要你自己保管 keystore—— 它丢了以后就没法给老用户发覆盖升级包,这个代价没有补救手段。- 产物在
dist/release/(或 HBuilderX 提示的路径),是一个可以直接装到手机上的.apk。
另一条路:离线打包
不想把源码过 DCloud 服务器就走这条:Android Studio + uni-app 离线 SDK, 把 dist/build/app 的内容放进 SDK 工程的 app/src/main/assets/apps/<appid>/www, 包名与 manifest.json 里的 distribute.android.packagename 对齐后本地出 APK。 代价是要自己维护 SDK 版本与签名。当前这份工程没有任何原生能力需求(无推送、无分享、无相机), 所以除非你有合规要求,建议先云打包。
五、装上验收
先过这三条,再管其它:
- 能装上、能打开,首屏不白屏、不卡启动图;
- 首页能读到你站点的真实主题列表;
- 能注册/登录,能发一条回帖。
「我的 → 当前连接」那一行应该等于你第一步填的那个域名。显示「未配置」就是第一步没生效(改了没重新构建, 或者环境变量和源码常量两份值打架)。
真机上还要盯这几件(这些只有在真机上才看得出来):
- 图标画不画得出来。全站图标用的是「一块纯色 + 一张 data URI 遮罩」,不依赖 emoji 也不依赖内联 SVG。 个别安卓内核只认带前缀的
-webkit-mask-image,规则里两条都写了;万一真机上是空白, 改法是遮罩换 base64 写法或直接换字体图标,调用处不用动。 - 顶部栏高度。全站是自绘顶部栏,栏高 = 系统状态栏高度 + 44,状态栏取值走
uni.getWindowInfo().statusBarHeight。真机上栏子偏高偏矮、吸顶层压住标题条,查的都是src/utils/system.js里navTotal()这一处,不要逐页调样式。 - 左缘右滑返回。自绘手势判定:起点在屏幕左 16 px 内、横位移 ≥60 且压过纵向 1.5 倍。 和安卓全面屏手势叠在一起时,系统手势先响应是正常现象。
- 富文本里的链接。正文用
rich-text渲染,App 端里面的<a>不一定响应, 需要的话是解析出链接后走uni.openWebUrl。 - 键盘弹起会不会挡住回帖框和发帖正文(
pages.json用的是默认adjustPosition,被挡就调这一项)。 - 登录态存活。令牌存在
uni.setStorageSync,杀进程重进应该还在;不在了查的是 App 侧 storage 被清,不是接口。
六、排错对照表
| 现象 | 大概率原因 |
|---|---|
| 所有接口都不通,「当前连接」显示未配置 | SITE_API_BASE 没填、不是 http(s):// 开头,或者构建之后才改的 |
| 接口全部 404 / 返回 HTML | 站点没装 mobile_api 插件,或 nginx 没有把 /api/* 转发到 PHP 入口 |
dist/build/app 里只有 index.html |
@dcloudio/uni-app-plus 缺失或版本和其它 @dcloudio/* 不一致,静默按 H5 编译了 |
| 云打包按钮直接拒绝 | appid 没点「重新获取」,或 Android 包名空着 |
| 打出来的包里有打不开的死页面 | dist/ 没删就重新构建,HBuilderX 读到了旧产物的残留路由 |
| 新包覆盖安装失败 | 换了 Android 包名,或换了签名证书(自有证书 keystore 不是原来那个) |
| 启动页中间闪一下白 / 叠一个系统转圈 | alwaysShowBeforeRender、autoclose 被动过,或面板里那三张图没传上去 |
| 图标位置是空白 | 见第五项第一条的遮罩写法 |
七、这份工程里有什么
部署教程.md 本文件
index.html H5 入口壳
vite.config.js Vite 配置(dev 服务 host:true, port:5173)
package.json 脚本与依赖
package-lock.json 锁版本
.env.example 环境变量模板(复制成 .env.local,不要提交)
启动图/ 三张 Android 启动图 PNG
src/
main.js App.vue 入口;App.vue 启动时会清掉历史遗留的本机配置键
manifest.json 应用配置(appid / 包名 / 版本号 / 权限 / h5 路由)
pages.json 12 个页面 + 窗口样式
pages/ home 首页 forums 版块列表 forum 版块 topic 帖子 post 发帖
search 搜索 notice 消息 dm-thread 私信会话 user 个人主页
mine 我的 settings 个人设置 login 登录注册
components/ app-nav app-tabbar app-avatar app-icon state-block topic-item app-sheet
utils/api.js 接口封装:统一拼 /api/*,登录后带 Bearer 令牌
utils/config.js 连接配置的读取处(环境变量优先于 site.config.js)
utils/site.config.js ★ 你要改的就是这个文件的 SITE_API_BASE 常量
utils/site.js store.js 站点信息与登录态
utils/menu.js format.js system.js swipe-back.js
权限只声明了 INTERNET:没有存储、定位、相机、通知。要加图片上传之前,不要顺手加权限。
八、这份教程不包含的
- iOS 包:本工程只承诺 H5 + Android。
- 应用商店上架:要软著与备案,是你那侧的流程。
- 服务端:
mobile_api插件本身的部署不在这里。
